提交 8e00cc12 编写于 作者: J Johannes Berg

Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next

...@@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah) ...@@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
aniState->listenTime = 0; aniState->listenTime = 0;
ENABLE_REGWRITE_BUFFER(ah); ENABLE_REGWRITE_BUFFER(ah);
...@@ -143,7 +143,7 @@ static void ath9k_ani_restart(struct ath_hw *ah) ...@@ -143,7 +143,7 @@ static void ath9k_ani_restart(struct ath_hw *ah)
static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
bool scan) bool scan)
{ {
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck; const struct ani_cck_level_entry *entry_cck;
...@@ -195,10 +195,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) ...@@ -195,10 +195,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
...@@ -210,7 +210,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) ...@@ -210,7 +210,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
bool scan) bool scan)
{ {
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck; const struct ani_cck_level_entry *entry_cck;
...@@ -251,10 +251,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) ...@@ -251,10 +251,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
...@@ -269,7 +269,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ...@@ -269,7 +269,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
aniState = &ah->curchan->ani; aniState = &ah->ani;
/* lower OFDM noise immunity */ /* lower OFDM noise immunity */
if (aniState->ofdmNoiseImmunityLevel > 0 && if (aniState->ofdmNoiseImmunityLevel > 0 &&
...@@ -292,12 +292,12 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ...@@ -292,12 +292,12 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
*/ */
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
{ {
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int ofdm_nil, cck_nil; int ofdm_nil, cck_nil;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
BUG_ON(aniState == NULL); BUG_ON(aniState == NULL);
...@@ -380,7 +380,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) ...@@ -380,7 +380,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
u32 phyCnt1, phyCnt2; u32 phyCnt1, phyCnt2;
int32_t listenTime; int32_t listenTime;
...@@ -415,10 +415,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -415,10 +415,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
u32 ofdmPhyErrRate, cckPhyErrRate; u32 ofdmPhyErrRate, cckPhyErrRate;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
if (!ath9k_hw_ani_read_counters(ah)) if (!ath9k_hw_ani_read_counters(ah))
return; return;
...@@ -490,32 +490,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); ...@@ -490,32 +490,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
void ath9k_hw_ani_init(struct ath_hw *ah) void ath9k_hw_ani_init(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int i; struct ar5416AniState *ani = &ah->ani;
ath_dbg(common, ANI, "Initialize ANI\n"); ath_dbg(common, ANI, "Initialize ANI\n");
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
struct ath9k_channel *chan = &ah->channels[i]; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
struct ar5416AniState *ani = &chan->ani; ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
ani->ofdmsTurn = true;
ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->ofdmWeakSigDetect = true;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
ani->ofdmsTurn = true;
ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
}
/* /*
* since we expect some ongoing maintenance on the tables, let's sanity * since we expect some ongoing maintenance on the tables, let's sanity
...@@ -524,9 +514,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ...@@ -524,9 +514,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ah->aniperiod = ATH9K_ANI_PERIOD; ah->aniperiod = ATH9K_ANI_PERIOD;
ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
if (ah->config.enable_ani)
ah->proc_phyerr |= HAL_PROCESS_ANI;
ath9k_ani_restart(ah); ath9k_ani_restart(ah);
ath9k_enable_mib_counters(ah); ath9k_enable_mib_counters(ah);
} }
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
#ifndef ANI_H #ifndef ANI_H
#define ANI_H #define ANI_H
#define HAL_PROCESS_ANI 0x00000001
#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan)
#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
/* units are errors per second */ /* units are errors per second */
...@@ -38,11 +34,7 @@ ...@@ -38,11 +34,7 @@
#define ATH9K_ANI_CCK_TRIG_LOW 300 #define ATH9K_ANI_CCK_TRIG_LOW 300
#define ATH9K_ANI_NOISE_IMMUNE_LVL 4 #define ATH9K_ANI_NOISE_IMMUNE_LVL 4
#define ATH9K_ANI_USE_OFDM_WEAK_SIG true
#define ATH9K_ANI_CCK_WEAK_SIG_THR false
#define ATH9K_ANI_SPUR_IMMUNE_LVL 3 #define ATH9K_ANI_SPUR_IMMUNE_LVL 3
#define ATH9K_ANI_FIRSTEP_LVL 2 #define ATH9K_ANI_FIRSTEP_LVL 2
#define ATH9K_ANI_RSSI_THR_HIGH 40 #define ATH9K_ANI_RSSI_THR_HIGH 40
...@@ -111,7 +103,7 @@ struct ar5416AniState { ...@@ -111,7 +103,7 @@ struct ar5416AniState {
u8 mrcCCK; u8 mrcCCK;
u8 spurImmunityLevel; u8 spurImmunityLevel;
u8 firstepLevel; u8 firstepLevel;
u8 ofdmWeakSigDetect; bool ofdmWeakSigDetect;
u32 listenTime; u32 listenTime;
u32 ofdmPhyErrCount; u32 ofdmPhyErrCount;
u32 cckPhyErrCount; u32 cckPhyErrCount;
...@@ -119,8 +111,6 @@ struct ar5416AniState { ...@@ -119,8 +111,6 @@ struct ar5416AniState {
}; };
struct ar5416Stats { struct ar5416Stats {
u32 ast_ani_niup;
u32 ast_ani_nidown;
u32 ast_ani_spurup; u32 ast_ani_spurup;
u32 ast_ani_spurdown; u32 ast_ani_spurdown;
u32 ast_ani_ofdmon; u32 ast_ani_ofdmon;
......
...@@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, ...@@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &chan->ani; struct ar5416AniState *aniState = &ah->ani;
s32 value, value2; s32 value, value2;
switch (cmd & ah->ani_function) { switch (cmd & ah->ani_function) {
...@@ -1207,7 +1207,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1207,7 +1207,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &chan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath9k_ani_default *iniDef; struct ath9k_ani_default *iniDef;
u32 val; u32 val;
...@@ -1251,7 +1251,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1251,7 +1251,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* these levels just got reset to defaults by the INI */ /* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; aniState->ofdmWeakSigDetect = true;
aniState->mrcCCK = false; /* not available on pre AR9003 */ aniState->mrcCCK = false; /* not available on pre AR9003 */
} }
......
...@@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah) ...@@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
else else
INIT_INI_ARRAY(&ah->iniPcieSerdes, INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9280PciePhy_clkreq_always_on_L1_9280); ar9280PciePhy_clkreq_always_on_L1_9280);
#ifdef CONFIG_PM_SLEEP
INIT_INI_ARRAY(&ah->iniPcieSerdesWow,
ar9280PciePhy_awow);
#endif
if (AR_SREV_9287_11_OR_LATER(ah)) { if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);
......
...@@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { ...@@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000}, {0x00004044, 0x00000000},
}; };
static const u32 ar9280PciePhy_awow[][2] = {
/* Addr allmodes */
{0x00004040, 0x9248fd00},
{0x00004040, 0x24924924},
{0x00004040, 0xa8000019},
{0x00004040, 0x13160820},
{0x00004040, 0xe5980560},
{0x00004040, 0xc01dcffd},
{0x00004040, 0x1aaabe41},
{0x00004040, 0xbe105554},
{0x00004040, 0x00043007},
{0x00004044, 0x00000000},
};
static const u32 ar9285Modes_9285_1_2[][5] = { static const u32 ar9285Modes_9285_1_2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
......
...@@ -469,6 +469,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, ...@@ -469,6 +469,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_status = 0; rxs->rs_status = 0;
rxs->rs_flags = 0; rxs->rs_flags = 0;
rxs->flag = 0;
rxs->rs_datalen = rxsp->status2 & AR_DataLen; rxs->rs_datalen = rxsp->status2 & AR_DataLen;
rxs->rs_tstamp = rxsp->status3; rxs->rs_tstamp = rxsp->status3;
...@@ -493,8 +494,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, ...@@ -493,8 +494,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0;
rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; rxs->flag |= (rxsp->status4 & AR_GI) ? RX_FLAG_SHORT_GI : 0;
rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; rxs->flag |= (rxsp->status4 & AR_2040) ? RX_FLAG_40MHZ : 0;
rxs->evm0 = rxsp->status6; rxs->evm0 = rxsp->status6;
rxs->evm1 = rxsp->status7; rxs->evm1 = rxsp->status7;
......
...@@ -904,7 +904,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, ...@@ -904,7 +904,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &chan->ani; struct ar5416AniState *aniState = &ah->ani;
s32 value, value2; s32 value, value2;
switch (cmd & ah->ani_function) { switch (cmd & ah->ani_function) {
...@@ -1172,7 +1172,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1172,7 +1172,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
struct ath9k_ani_default *iniDef; struct ath9k_ani_default *iniDef;
u32 val; u32 val;
aniState = &ah->curchan->ani; aniState = &ah->ani;
iniDef = &aniState->iniDef; iniDef = &aniState->iniDef;
ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
...@@ -1213,7 +1213,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1213,7 +1213,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* these levels just got reset to defaults by the INI */ /* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; aniState->ofdmWeakSigDetect = true;
aniState->mrcCCK = true; aniState->mrcCCK = true;
} }
......
...@@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = { ...@@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t read_file_disable_ani(struct file *file, char __user *user_buf, static ssize_t read_file_ani(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32]; struct ath_hw *ah = sc->sc_ah;
unsigned int len; unsigned int len = 0, size = 1024;
ssize_t retval = 0;
char *buf;
len = sprintf(buf, "%d\n", common->disable_ani); buf = kzalloc(size, GFP_KERNEL);
return simple_read_from_buffer(user_buf, count, ppos, buf, len); if (buf == NULL)
return -ENOMEM;
if (common->disable_ani) {
len += snprintf(buf + len, size - len, "%s: %s\n",
"ANI", "DISABLED");
goto exit;
}
len += snprintf(buf + len, size - len, "%15s: %s\n",
"ANI", "ENABLED");
len += snprintf(buf + len, size - len, "%15s: %u\n",
"ANI RESET", ah->stats.ast_ani_reset);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"SPUR UP", ah->stats.ast_ani_spurup);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"SPUR DOWN", ah->stats.ast_ani_spurup);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"MRC-CCK ON", ah->stats.ast_ani_ccklow);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"FIR-STEP UP", ah->stats.ast_ani_stepup);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"CCK ERRORS", ah->stats.ast_ani_cckerrs);
exit:
if (len > size)
len = size;
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
} }
static ssize_t write_file_disable_ani(struct file *file, static ssize_t write_file_ani(struct file *file,
const char __user *user_buf, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long disable_ani; unsigned long ani;
char buf[32]; char buf[32];
ssize_t len; ssize_t len;
...@@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file, ...@@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file,
return -EFAULT; return -EFAULT;
buf[len] = '\0'; buf[len] = '\0';
if (strict_strtoul(buf, 0, &disable_ani)) if (strict_strtoul(buf, 0, &ani))
return -EINVAL;
if (ani < 0 || ani > 1)
return -EINVAL; return -EINVAL;
common->disable_ani = !!disable_ani; common->disable_ani = !ani;
if (disable_ani) { if (common->disable_ani) {
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_stop_ani(sc); ath_stop_ani(sc);
} else { } else {
...@@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file, ...@@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file,
return count; return count;
} }
static const struct file_operations fops_disable_ani = { static const struct file_operations fops_ani = {
.read = read_file_disable_ani, .read = read_file_ani,
.write = write_file_disable_ani, .write = write_file_ani,
.open = simple_open, .open = simple_open,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = default_llseek, .llseek = default_llseek,
...@@ -1719,8 +1766,8 @@ int ath9k_init_debug(struct ath_hw *ah) ...@@ -1719,8 +1766,8 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.debugfs_phy, sc, &fops_rx_chainmask); sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_tx_chainmask); sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, debugfs_create_file("ani", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_disable_ani); sc->debug.debugfs_phy, sc, &fops_ani);
debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->sc_ah->config.enable_paprd); &sc->sc_ah->config.enable_paprd);
debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
......
...@@ -251,45 +251,6 @@ struct ath_stats { ...@@ -251,45 +251,6 @@ struct ath_stats {
u32 reset[__RESET_TYPE_MAX]; u32 reset[__RESET_TYPE_MAX];
}; };
#define ATH_DBG_MAX_SAMPLES 10
struct ath_dbg_bb_mac_samp {
u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS];
u32 pcu_obs, pcu_cr, noise;
struct {
u64 jiffies;
int8_t rssi_ctl0;
int8_t rssi_ctl1;
int8_t rssi_ctl2;
int8_t rssi_ext0;
int8_t rssi_ext1;
int8_t rssi_ext2;
int8_t rssi;
bool isok;
u8 rts_fail_cnt;
u8 data_fail_cnt;
u8 rateindex;
u8 qid;
u8 tid;
u32 ba_low;
u32 ba_high;
} ts[ATH_DBG_MAX_SAMPLES];
struct {
u64 jiffies;
int8_t rssi_ctl0;
int8_t rssi_ctl1;
int8_t rssi_ctl2;
int8_t rssi_ext0;
int8_t rssi_ext1;
int8_t rssi_ext2;
int8_t rssi;
bool is_mybeacon;
u8 antenna;
u8 rate;
} rs[ATH_DBG_MAX_SAMPLES];
struct ath_cycle_counters cc;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
};
struct ath9k_debug { struct ath9k_debug {
struct dentry *debugfs_phy; struct dentry *debugfs_phy;
u32 regidx; u32 regidx;
......
...@@ -814,8 +814,7 @@ void ath9k_htc_ani_work(struct work_struct *work) ...@@ -814,8 +814,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
} }
/* Verify whether we must check ANI */ /* Verify whether we must check ANI */
if (ah->config.enable_ani && if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
(timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
aniflag = true; aniflag = true;
common->ani.checkani_timer = timestamp; common->ani.checkani_timer = timestamp;
} }
...@@ -845,8 +844,7 @@ void ath9k_htc_ani_work(struct work_struct *work) ...@@ -845,8 +844,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
* short calibration and long calibration. * short calibration and long calibration.
*/ */
cal_interval = ATH_LONG_CALINTERVAL; cal_interval = ATH_LONG_CALINTERVAL;
if (ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
if (!common->ani.caldone) if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval); cal_interval = min(cal_interval, (u32)short_cal_interval);
......
...@@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ...@@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.pcie_clock_req = 0; ah->config.pcie_clock_req = 0;
ah->config.pcie_waen = 0; ah->config.pcie_waen = 0;
ah->config.analog_shiftreg = 1; ah->config.analog_shiftreg = 1;
ah->config.enable_ani = true;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
ah->config.spurchans[i][0] = AR_NO_SPUR; ah->config.spurchans[i][0] = AR_NO_SPUR;
...@@ -549,8 +548,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ...@@ -549,8 +548,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_ver(ah),
ah->eep_ops->get_eeprom_rev(ah)); ah->eep_ops->get_eeprom_rev(ah));
if (ah->config.enable_ani) ath9k_hw_ani_init(ah);
ath9k_hw_ani_init(ah);
return 0; return 0;
} }
...@@ -2595,13 +2593,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ...@@ -2595,13 +2593,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RTT; pCap->hw_caps |= ATH9K_HW_CAP_RTT;
} }
if (AR_SREV_9280_20_OR_LATER(ah)) { if (AR_SREV_9462(ah))
pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE;
ATH9K_HW_WOW_PATTERN_MATCH_EXACT;
if (AR_SREV_9280(ah))
pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD;
}
if (AR_SREV_9300_20_OR_LATER(ah) && if (AR_SREV_9300_20_OR_LATER(ah) &&
ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
......
...@@ -246,9 +246,7 @@ enum ath9k_hw_caps { ...@@ -246,9 +246,7 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_MCI = BIT(15), ATH9K_HW_CAP_MCI = BIT(15),
ATH9K_HW_CAP_DFS = BIT(16), ATH9K_HW_CAP_DFS = BIT(16),
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
ATH9K_HW_WOW_PATTERN_MATCH_EXACT = BIT(18), ATH9K_HW_CAP_PAPRD = BIT(18),
ATH9K_HW_WOW_PATTERN_MATCH_DWORD = BIT(19),
ATH9K_HW_CAP_PAPRD = BIT(20),
}; };
/* /*
...@@ -291,7 +289,6 @@ struct ath9k_ops_config { ...@@ -291,7 +289,6 @@ struct ath9k_ops_config {
u32 ofdm_trig_high; u32 ofdm_trig_high;
u32 cck_trig_high; u32 cck_trig_high;
u32 cck_trig_low; u32 cck_trig_low;
u32 enable_ani;
u32 enable_paprd; u32 enable_paprd;
int serialize_regmode; int serialize_regmode;
bool rx_intr_mitigation; bool rx_intr_mitigation;
...@@ -423,7 +420,6 @@ struct ath9k_hw_cal_data { ...@@ -423,7 +420,6 @@ struct ath9k_hw_cal_data {
struct ath9k_channel { struct ath9k_channel {
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct ar5416AniState ani;
u16 channel; u16 channel;
u32 channelFlags; u32 channelFlags;
u32 chanmode; u32 chanmode;
...@@ -854,10 +850,10 @@ struct ath_hw { ...@@ -854,10 +850,10 @@ struct ath_hw {
u32 globaltxtimeout; u32 globaltxtimeout;
/* ANI */ /* ANI */
u32 proc_phyerr;
u32 aniperiod; u32 aniperiod;
enum ath9k_ani_cmd ani_function; enum ath9k_ani_cmd ani_function;
u32 ani_skip_count; u32 ani_skip_count;
struct ar5416AniState ani;
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
struct ath_btcoex_hw btcoex_hw; struct ath_btcoex_hw btcoex_hw;
...@@ -882,9 +878,6 @@ struct ath_hw { ...@@ -882,9 +878,6 @@ struct ath_hw {
struct ar5416IniArray iniBank6; struct ar5416IniArray iniBank6;
struct ar5416IniArray iniAddac; struct ar5416IniArray iniAddac;
struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdes;
#ifdef CONFIG_PM_SLEEP
struct ar5416IniArray iniPcieSerdesWow;
#endif
struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniPcieSerdesLowPower;
struct ar5416IniArray iniModesFastClock; struct ar5416IniArray iniModesFastClock;
struct ar5416IniArray iniAdditional; struct ar5416IniArray iniAdditional;
...@@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
} }
#endif #endif
#define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_CCK 22
#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/ath9k_platform.h> #include <linux/ath9k_platform.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/relay.h> #include <linux/relay.h>
#include <net/ieee80211_radiotap.h>
#include "ath9k.h" #include "ath9k.h"
...@@ -766,12 +767,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -766,12 +767,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_RC_TABLE; IEEE80211_HW_SUPPORTS_RC_TABLE;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
if (AR_SREV_9280_20_OR_LATER(ah))
hw->radiotap_mcs_details |=
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
}
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE; hw->flags |= IEEE80211_HW_MFP_CAPABLE;
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
hw->wiphy->interface_modes = hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
...@@ -792,21 +800,17 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -792,21 +800,17 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
device_can_wakeup(sc->dev)) { device_can_wakeup(sc->dev)) {
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
WIPHY_WOWLAN_DISCONNECT; WIPHY_WOWLAN_DISCONNECT;
hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN; hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN;
hw->wiphy->wowlan.pattern_min_len = 1; hw->wiphy->wowlan.pattern_min_len = 1;
hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE; hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE;
} }
atomic_set(&sc->wow_sleep_proc_intr, -1); atomic_set(&sc->wow_sleep_proc_intr, -1);
atomic_set(&sc->wow_got_bmiss_intr, -1); atomic_set(&sc->wow_got_bmiss_intr, -1);
#endif #endif
hw->queues = 4; hw->queues = 4;
......
...@@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data) ...@@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data)
} }
/* Verify whether we must check ANI */ /* Verify whether we must check ANI */
if (sc->sc_ah->config.enable_ani if ((timestamp - common->ani.checkani_timer) >= ah->config.ani_poll_interval) {
&& (timestamp - common->ani.checkani_timer) >=
ah->config.ani_poll_interval) {
aniflag = true; aniflag = true;
common->ani.checkani_timer = timestamp; common->ani.checkani_timer = timestamp;
} }
...@@ -427,9 +425,7 @@ void ath_ani_calibrate(unsigned long data) ...@@ -427,9 +425,7 @@ void ath_ani_calibrate(unsigned long data)
* short calibration and long calibration. * short calibration and long calibration.
*/ */
cal_interval = ATH_LONG_CALINTERVAL; cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ah->config.ani_poll_interval);
cal_interval = min(cal_interval,
(u32)ah->config.ani_poll_interval);
if (!common->ani.caldone) if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval); cal_interval = min(cal_interval, (u32)short_cal_interval);
......
...@@ -547,6 +547,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ...@@ -547,6 +547,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_status = 0; rs->rs_status = 0;
rs->rs_flags = 0; rs->rs_flags = 0;
rs->flag = 0;
rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
rs->rs_tstamp = ads.AR_RcvTimestamp; rs->rs_tstamp = ads.AR_RcvTimestamp;
...@@ -586,10 +587,17 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ...@@ -586,10 +587,17 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_moreaggr = rs->rs_moreaggr =
(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
rs->rs_flags =
(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; /* directly mapped flags for ieee80211_rx_status */
rs->rs_flags |= rs->flag |=
(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; (ads.ds_rxstatus3 & AR_GI) ? RX_FLAG_SHORT_GI : 0;
rs->flag |=
(ads.ds_rxstatus3 & AR_2040) ? RX_FLAG_40MHZ : 0;
if (AR_SREV_9280_20_OR_LATER(ah))
rs->flag |=
(ads.ds_rxstatus3 & AR_STBC) ?
/* we can only Nss=1 STBC */
(1 << RX_FLAG_STBC_SHIFT) : 0;
if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
......
...@@ -149,6 +149,7 @@ struct ath_rx_status { ...@@ -149,6 +149,7 @@ struct ath_rx_status {
u32 evm2; u32 evm2;
u32 evm3; u32 evm3;
u32 evm4; u32 evm4;
u32 flag; /* see enum mac80211_rx_flags */
}; };
struct ath_htc_rx_status { struct ath_htc_rx_status {
...@@ -533,7 +534,8 @@ struct ar5416_desc { ...@@ -533,7 +534,8 @@ struct ar5416_desc {
#define AR_2040 0x00000002 #define AR_2040 0x00000002
#define AR_Parallel40 0x00000004 #define AR_Parallel40 0x00000004
#define AR_Parallel40_S 2 #define AR_Parallel40_S 2
#define AR_RxStatusRsvd30 0x000000f8 #define AR_STBC 0x00000008 /* on ar9280 and later */
#define AR_RxStatusRsvd30 0x000000f0
#define AR_RxAntenna 0xffffff00 #define AR_RxAntenna 0xffffff00
#define AR_RxAntenna_S 8 #define AR_RxAntenna_S 8
......
...@@ -2003,7 +2003,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -2003,7 +2003,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pcaps = &ah->caps;
int pattern_count = 0; int pattern_count = 0;
int i, byte_cnt; int i, byte_cnt;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
...@@ -2073,36 +2072,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -2073,36 +2072,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
/* Create Disassociate pattern mask */ /* Create Disassociate pattern mask */
if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) { dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03;
if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) { dis_deauth_mask[2] = 0xc0;
/*
* for AR9280, because of hardware limitation, the
* first 4 bytes have to be matched for all patterns.
* the mask for disassociation and de-auth pattern
* matching need to enable the first 4 bytes.
* also the duration field needs to be filled.
*/
dis_deauth_mask[0] = 0xf0;
/*
* fill in duration field
FIXME: what is the exact value ?
*/
dis_deauth_pattern[2] = 0xff;
dis_deauth_pattern[3] = 0xff;
} else {
dis_deauth_mask[0] = 0xfe;
}
dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0;
} else {
dis_deauth_mask[0] = 0xef;
dis_deauth_mask[1] = 0x3f;
dis_deauth_mask[2] = 0x00;
dis_deauth_mask[3] = 0xfc;
}
ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
......
...@@ -868,10 +868,7 @@ static int ath9k_process_rate(struct ath_common *common, ...@@ -868,10 +868,7 @@ static int ath9k_process_rate(struct ath_common *common,
if (rx_stats->rs_rate & 0x80) { if (rx_stats->rs_rate & 0x80) {
/* HT rate */ /* HT rate */
rxs->flag |= RX_FLAG_HT; rxs->flag |= RX_FLAG_HT;
if (rx_stats->rs_flags & ATH9K_RX_2040) rxs->flag |= rx_stats->flag;
rxs->flag |= RX_FLAG_40MHZ;
if (rx_stats->rs_flags & ATH9K_RX_GI)
rxs->flag |= RX_FLAG_SHORT_GI;
rxs->rate_idx = rx_stats->rs_rate & 0x7f; rxs->rate_idx = rx_stats->rs_rate & 0x7f;
return 0; return 0;
} }
...@@ -958,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ...@@ -958,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (rx_stats->rs_more) if (rx_stats->rs_more)
return 0; return 0;
ath9k_process_rssi(common, hw, hdr, rx_stats);
if (ath9k_process_rate(common, hw, rx_stats, rx_status)) if (ath9k_process_rate(common, hw, rx_stats, rx_status))
return -EINVAL; return -EINVAL;
ath9k_process_rssi(common, hw, hdr, rx_stats);
rx_status->band = hw->conf.chandef.chan->band; rx_status->band = hw->conf.chandef.chan->band;
rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->signal = ah->noise + rx_stats->rs_rssi;
......
...@@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event) ...@@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event)
} }
EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
static void ath9k_hw_config_serdes_wow_sleep(struct ath_hw *ah)
{
int i;
for (i = 0; i < ah->iniPcieSerdesWow.ia_rows; i++)
REG_WRITE(ah, INI_RA(&ah->iniPcieSerdesWow, i, 0),
INI_RA(&ah->iniPcieSerdesWow, i, 1));
usleep_range(1000, 1500);
}
static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
...@@ -58,15 +47,8 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) ...@@ -58,15 +47,8 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
return; return;
} else {
if (!AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_RXDP, 0x0);
} }
/* AR9280 WoW has sleep issue, do not set it to sleep */
if (AR_SREV_9280_20(ah))
return;
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
} }
...@@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) ...@@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
/* set the transmit buffer */ /* set the transmit buffer */
ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
if (!(AR_SREV_9300_20_OR_LATER(ah)))
ctl[0] += (KAL_ANTENNA_MODE << 25);
ctl[1] = 0; ctl[1] = 0;
ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */
ctl[4] = 0; ctl[4] = 0;
ctl[7] = (ah->txchainmask) << 2; ctl[7] = (ah->txchainmask) << 2;
ctl[2] = 0xf << 16; /* tx_tries 0 */
if (AR_SREV_9300_20_OR_LATER(ah))
ctl[2] = 0xf << 16; /* tx_tries 0 */
else
ctl[2] = 0x7 << 16; /* tx_tries 0 */
for (i = 0; i < KAL_NUM_DESC_WORDS; i++) for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
/* for AR9300 family 13 descriptor words */ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
if (AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
(KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
...@@ -183,9 +154,6 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, ...@@ -183,9 +154,6 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
if (!AR_SREV_9285_12_OR_LATER(ah))
return;
if (pattern_count < 4) { if (pattern_count < 4) {
/* Pattern 0-3 uses AR_WOW_LENGTH1 register */ /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) << set = (pattern_len & AR_WOW_LENGTH_MAX) <<
...@@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
{ {
u32 wow_status = 0; u32 wow_status = 0;
u32 val = 0, rval; u32 val = 0, rval;
/* /*
* read the WoW status register to know * read the WoW status register to know
* the wakeup reason * the wakeup reason
...@@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
val &= ah->wow_event_mask; val &= ah->wow_event_mask;
if (val) { if (val) {
if (val & AR_WOW_MAGIC_PAT_FOUND) if (val & AR_WOW_MAGIC_PAT_FOUND)
wow_status |= AH_WOW_MAGIC_PATTERN_EN; wow_status |= AH_WOW_MAGIC_PATTERN_EN;
if (AR_WOW_PATTERN_FOUND(val)) if (AR_WOW_PATTERN_FOUND(val))
wow_status |= AH_WOW_USER_PATTERN_EN; wow_status |= AH_WOW_USER_PATTERN_EN;
if (val & AR_WOW_KEEP_ALIVE_FAIL) if (val & AR_WOW_KEEP_ALIVE_FAIL)
wow_status |= AH_WOW_LINK_CHANGE; wow_status |= AH_WOW_LINK_CHANGE;
if (val & AR_WOW_BEACON_FAIL) if (val & AR_WOW_BEACON_FAIL)
wow_status |= AH_WOW_BEACON_MISS; wow_status |= AH_WOW_BEACON_MISS;
} }
/* /*
...@@ -254,17 +218,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -254,17 +218,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
REG_WRITE(ah, AR_WOW_PATTERN, REG_WRITE(ah, AR_WOW_PATTERN,
AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
/*
* tie reset register for AR9002 family of chipsets
* NB: not tieing it back might have some repurcussions.
*/
if (!AR_SREV_9300_20_OR_LATER(ah)) {
REG_SET_BIT(ah, AR_WA, AR_WA_UNTIE_RESET_EN |
AR_WA_POR_SHORT | AR_WA_RESET_EN);
}
/* /*
* restore the beacon threshold to init value * restore the beacon threshold to init value
*/ */
...@@ -277,8 +230,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -277,8 +230,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
* reset to our Chip's Power On Reset so that any PCI-E * reset to our Chip's Power On Reset so that any PCI-E
* reset from the bus will not reset our chip * reset from the bus will not reset our chip
*/ */
if (ah->is_pciexpress)
if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, false); ath9k_hw_configpcipowersave(ah, false);
ah->wow_event_mask = 0; ah->wow_event_mask = 0;
...@@ -298,7 +250,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -298,7 +250,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
* are from the 'pattern_enable' in this function and * are from the 'pattern_enable' in this function and
* 'pattern_count' of ath9k_hw_wow_apply_pattern() * 'pattern_count' of ath9k_hw_wow_apply_pattern()
*/ */
wow_event_mask = ah->wow_event_mask; wow_event_mask = ah->wow_event_mask;
/* /*
...@@ -306,50 +257,15 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -306,50 +257,15 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
* WOW sleep, we do want the Reset from the PCI-E to disturb * WOW sleep, we do want the Reset from the PCI-E to disturb
* our hw state * our hw state
*/ */
if (ah->is_pciexpress) { if (ah->is_pciexpress) {
/* /*
* we need to untie the internal POR (power-on-reset) * we need to untie the internal POR (power-on-reset)
* to the external PCI-E reset. We also need to tie * to the external PCI-E reset. We also need to tie
* the PCI-E Phy reset to the PCI-E reset. * the PCI-E Phy reset to the PCI-E reset.
*/ */
set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
if (AR_SREV_9300_20_OR_LATER(ah)) { clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
set = AR_WA_RESET_EN | AR_WA_POR_SHORT; REG_RMW(ah, AR_WA, set, clr);
clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
REG_RMW(ah, AR_WA, set, clr);
} else {
if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
set = AR9285_WA_DEFAULT;
else
set = AR9280_WA_DEFAULT;
/*
* In AR9280 and AR9285, bit 14 in WA register
* (disable L1) should only be set when device
* enters D3 state and be cleared when device
* comes back to D0
*/
if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
set |= AR_WA_D3_L1_DISABLE;
clr = AR_WA_UNTIE_RESET_EN;
set |= AR_WA_RESET_EN | AR_WA_POR_SHORT;
REG_RMW(ah, AR_WA, set, clr);
/*
* for WoW sleep, we reprogram the SerDes so that the
* PLL and CLK REQ are both enabled. This uses more
* power but otherwise WoW sleep is unstable and the
* chip may disappear.
*/
if (AR_SREV_9285_12_OR_LATER(ah))
ath9k_hw_config_serdes_wow_sleep(ah);
}
} }
/* /*
...@@ -378,7 +294,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -378,7 +294,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
* Program default values for pattern backoff, aifs/slot/KAL count, * Program default values for pattern backoff, aifs/slot/KAL count,
* beacon miss timeout, KAL timeout, etc. * beacon miss timeout, KAL timeout, etc.
*/ */
set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
REG_SET_BIT(ah, AR_WOW_PATTERN, set); REG_SET_BIT(ah, AR_WOW_PATTERN, set);
...@@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
/* /*
* Keep alive timo in ms except AR9280 * Keep alive timo in ms except AR9280
*/ */
if (!pattern_enable || AR_SREV_9280(ah)) if (!pattern_enable)
set = AR_WOW_KEEP_ALIVE_NEVER; set = AR_WOW_KEEP_ALIVE_NEVER;
else else
set = KAL_TIMEOUT * 32; set = KAL_TIMEOUT * 32;
...@@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
/* /*
* Configure MAC WoW Registers * Configure MAC WoW Registers
*/ */
set = 0; set = 0;
/* Send keep alive timeouts anyway */ /* Send keep alive timeouts anyway */
clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
...@@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
else else
set = AR_WOW_KEEP_ALIVE_FAIL_DIS; set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
/*
* FIXME: For now disable keep alive frame
* failure. This seems to sometimes trigger
* unnecessary wake up with AR9485 chipsets.
*/
set = AR_WOW_KEEP_ALIVE_FAIL_DIS; set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
/* /*
* we are relying on a bmiss failure. ensure we have * we are relying on a bmiss failure. ensure we have
* enough threshold to prevent false positives * enough threshold to prevent false positives
...@@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
set |= AR_WOW_MAC_INTR_EN; set |= AR_WOW_MAC_INTR_EN;
REG_RMW(ah, AR_WOW_PATTERN, set, clr); REG_RMW(ah, AR_WOW_PATTERN, set, clr);
/* REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
* For AR9285 and later version of chipsets AR_WOW_PATTERN_SUPPORTED);
* enable WoW pattern match for packets less
* than 256 bytes for all patterns
*/
if (AR_SREV_9285_12_OR_LATER(ah))
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
AR_WOW_PATTERN_SUPPORTED);
/* /*
* Set the power states appropriately and enable PME * Set the power states appropriately and enable PME
...@@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
clr = 0; clr = 0;
set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
AR_PMCTRL_PWR_PM_CTRL_ENA; AR_PMCTRL_PWR_PM_CTRL_ENA;
/*
* This is needed for AR9300 chipsets to wake-up
* the host.
*/
if (AR_SREV_9300_20_OR_LATER(ah))
clr = AR_PCIE_PM_CTRL_ENA;
clr = AR_PCIE_PM_CTRL_ENA;
REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { /*
/* * this is needed to prevent the chip waking up
* this is needed to prevent the chip waking up * the host within 3-4 seconds with certain
* the host within 3-4 seconds with certain * platform/BIOS. The fix is to enable
* platform/BIOS. The fix is to enable * D1 & D3 to match original definition and
* D1 & D3 to match original definition and * also match the OTP value. Anyway this
* also match the OTP value. Anyway this * is more related to SW WOW.
* is more related to SW WOW. */
*/ clr = AR_PMCTRL_PWR_STATE_D1D3;
clr = AR_PMCTRL_PWR_STATE_D1D3; REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
}
set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
if (AR_SREV_9300_20_OR_LATER(ah)) { /* to bring down WOW power low margin */
/* to bring down WOW power low margin */ set = BIT(13);
set = BIT(13); REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); /* HW WoW */
/* HW WoW */ clr = BIT(5);
clr = BIT(5); REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
}
ath9k_hw_set_powermode_wow_sleep(ah); ath9k_hw_set_powermode_wow_sleep(ah);
ah->wow_event_mask = wow_event_mask; ah->wow_event_mask = wow_event_mask;
......
...@@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, ...@@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
if (supr_status) { if (supr_status) {
update_rate = false; update_rate = false;
if (supr_status == TX_STATUS_SUPR_BADCH) { if (supr_status == TX_STATUS_SUPR_BADCH) {
brcms_err(wlc->hw->d11core, brcms_dbg_ht(wlc->hw->d11core,
"%s: Pkt tx suppressed, illegal channel possibly %d\n", "%s: Pkt tx suppressed, illegal channel possibly %d\n",
__func__, CHSPEC_CHANNEL( __func__, CHSPEC_CHANNEL(
wlc->default_bss->chanspec)); wlc->default_bss->chanspec));
......
...@@ -13,34 +13,18 @@ config CW1200_WLAN_SDIO ...@@ -13,34 +13,18 @@ config CW1200_WLAN_SDIO
depends on CW1200 && MMC depends on CW1200 && MMC
help help
Enable support for the CW1200 connected via an SDIO bus. Enable support for the CW1200 connected via an SDIO bus.
By default this driver only supports the Sagrad SG901-1091/1098 EVK
and similar designs that utilize a hardware reset circuit. To
support different CW1200 SDIO designs you will need to override
the default platform data by calling cw1200_sdio_set_platform_data()
in your board setup file.
config CW1200_WLAN_SPI config CW1200_WLAN_SPI
tristate "Support SPI platforms" tristate "Support SPI platforms"
depends on CW1200 && SPI depends on CW1200 && SPI
help help
Enables support for the CW1200 connected via a SPI bus. Enables support for the CW1200 connected via a SPI bus. You will
need to add appropriate platform data glue in your board setup
config CW1200_WLAN_SAGRAD file.
tristate "Support Sagrad SG901-1091/1098 modules"
depends on CW1200_WLAN_SDIO
help
This provides the platform data glue to support the
Sagrad SG901-1091/1098 modules in their standard SDIO EVK.
It also includes example SPI platform data.
menu "Driver debug features"
depends on CW1200 && DEBUG_FS
config CW1200_ETF
bool "Enable CW1200 Engineering Test Framework hooks"
help
If you don't know what this is, just say N.
config CW1200_ITP
bool "Enable ITP access"
help
If you don't know what this is, just say N.
endmenu
endif endif
...@@ -8,17 +8,14 @@ cw1200_core-y := \ ...@@ -8,17 +8,14 @@ cw1200_core-y := \
wsm.o \ wsm.o \
sta.o \ sta.o \
scan.o \ scan.o \
pm.o \
debug.o debug.o
cw1200_core-$(CONFIG_CW1200_ITP) += itp.o cw1200_core-$(CONFIG_PM) += pm.o
# CFLAGS_sta.o += -DDEBUG # CFLAGS_sta.o += -DDEBUG
cw1200_wlan_sdio-y := cw1200_sdio.o cw1200_wlan_sdio-y := cw1200_sdio.o
cw1200_wlan_spi-y := cw1200_spi.o cw1200_wlan_spi-y := cw1200_spi.o
cw1200_wlan_sagrad-y := cw1200_sagrad.o
obj-$(CONFIG_CW1200) += cw1200_core.o obj-$(CONFIG_CW1200) += cw1200_core.o
obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o
obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o
obj-$(CONFIG_CW1200_WLAN_SAGRAD) += cw1200_wlan_sagrad.o
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "bh.h" #include "bh.h"
#include "hwio.h" #include "hwio.h"
#include "wsm.h" #include "wsm.h"
#include "sbus.h" #include "hwbus.h"
#include "debug.h" #include "debug.h"
#include "fwio.h" #include "fwio.h"
...@@ -31,7 +31,8 @@ static int cw1200_bh(void *arg); ...@@ -31,7 +31,8 @@ static int cw1200_bh(void *arg);
#define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4) #define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4)
/* an SPI message cannot be bigger than (2"12-1)*2 bytes /* an SPI message cannot be bigger than (2"12-1)*2 bytes
* "*2" to cvt to bytes */ * "*2" to cvt to bytes
*/
#define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) #define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2)
#define PIGGYBACK_CTRL_REG (2) #define PIGGYBACK_CTRL_REG (2)
#define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) #define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG)
...@@ -103,7 +104,7 @@ void cw1200_irq_handler(struct cw1200_common *priv) ...@@ -103,7 +104,7 @@ void cw1200_irq_handler(struct cw1200_common *priv)
pr_debug("[BH] irq.\n"); pr_debug("[BH] irq.\n");
/* Disable Interrupts! */ /* Disable Interrupts! */
/* NOTE: sbus_ops->lock already held */ /* NOTE: hwbus_ops->lock already held */
__cw1200_irq_enable(priv, 0); __cw1200_irq_enable(priv, 0);
if (/* WARN_ON */(priv->bh_error)) if (/* WARN_ON */(priv->bh_error))
...@@ -217,7 +218,8 @@ static int cw1200_device_wakeup(struct cw1200_common *priv) ...@@ -217,7 +218,8 @@ static int cw1200_device_wakeup(struct cw1200_common *priv)
return ret; return ret;
/* If the device returns WLAN_RDY as 1, the device is active and will /* If the device returns WLAN_RDY as 1, the device is active and will
* remain active. */ * remain active.
*/
if (ctrl_reg & ST90TDS_CONT_RDY_BIT) { if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
pr_debug("[BH] Device awake.\n"); pr_debug("[BH] Device awake.\n");
return 1; return 1;
...@@ -262,11 +264,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv, ...@@ -262,11 +264,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv,
} }
/* Add SIZE of PIGGYBACK reg (CONTROL Reg) /* Add SIZE of PIGGYBACK reg (CONTROL Reg)
* to the NEXT Message length + 2 Bytes for SKB */ * to the NEXT Message length + 2 Bytes for SKB
*/
read_len = read_len + 2; read_len = read_len + 2;
alloc_len = priv->sbus_ops->align_size( alloc_len = priv->hwbus_ops->align_size(
priv->sbus_priv, read_len); priv->hwbus_priv, read_len);
/* Check if not exceeding CW1200 capabilities */ /* Check if not exceeding CW1200 capabilities */
if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) {
...@@ -384,8 +387,8 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv, ...@@ -384,8 +387,8 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv,
atomic_add(1, &priv->bh_tx); atomic_add(1, &priv->bh_tx);
tx_len = priv->sbus_ops->align_size( tx_len = priv->hwbus_ops->align_size(
priv->sbus_priv, tx_len); priv->hwbus_priv, tx_len);
/* Check if not exceeding CW1200 capabilities */ /* Check if not exceeding CW1200 capabilities */
if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE)) if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE))
...@@ -597,15 +600,15 @@ static int cw1200_bh(void *arg) ...@@ -597,15 +600,15 @@ static int cw1200_bh(void *arg)
done: done:
/* Re-enable device interrupts */ /* Re-enable device interrupts */
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
__cw1200_irq_enable(priv, 1); __cw1200_irq_enable(priv, 1);
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
} }
/* Explicitly disable device interrupts */ /* Explicitly disable device interrupts */
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
__cw1200_irq_enable(priv, 0); __cw1200_irq_enable(priv, 0);
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
if (!term) { if (!term) {
pr_err("[BH] Fatal error, exiting.\n"); pr_err("[BH] Fatal error, exiting.\n");
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#define CW1200_H #define CW1200_H
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/version.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <net/mac80211.h> #include <net/mac80211.h>
...@@ -31,16 +30,11 @@ ...@@ -31,16 +30,11 @@
#include "pm.h" #include "pm.h"
/* Forward declarations */ /* Forward declarations */
struct sbus_ops; struct hwbus_ops;
struct task_struct; struct task_struct;
struct cw1200_debug_priv; struct cw1200_debug_priv;
struct firmware; struct firmware;
#ifdef CONFIG_CW1200_ETF
extern int etf_mode;
extern char *etf_firmware;
#endif
#define CW1200_MAX_CTRL_FRAME_LEN (0x1000) #define CW1200_MAX_CTRL_FRAME_LEN (0x1000)
#define CW1200_MAX_STA_IN_AP_MODE (5) #define CW1200_MAX_STA_IN_AP_MODE (5)
...@@ -110,8 +104,8 @@ struct cw1200_common { ...@@ -110,8 +104,8 @@ struct cw1200_common {
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
/* Hardware interface */ /* Hardware interface */
const struct sbus_ops *sbus_ops; const struct hwbus_ops *hwbus_ops;
struct sbus_priv *sbus_priv; struct hwbus_priv *hwbus_priv;
/* Hardware information */ /* Hardware information */
enum { enum {
...@@ -213,7 +207,8 @@ struct cw1200_common { ...@@ -213,7 +207,8 @@ struct cw1200_common {
/* Scan status */ /* Scan status */
struct cw1200_scan scan; struct cw1200_scan scan;
/* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid /* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid
* FW issue with sleeping/waking up. */ * FW issue with sleeping/waking up.
*/
atomic_t recent_scan; atomic_t recent_scan;
struct delayed_work clear_recent_scan_work; struct delayed_work clear_recent_scan_work;
...@@ -288,10 +283,6 @@ struct cw1200_common { ...@@ -288,10 +283,6 @@ struct cw1200_common {
struct work_struct linkid_reset_work; struct work_struct linkid_reset_work;
u8 action_frame_sa[ETH_ALEN]; u8 action_frame_sa[ETH_ALEN];
u8 action_linkid; u8 action_linkid;
#ifdef CONFIG_CW1200_ETF
struct sk_buff_head etf_q;
#endif
}; };
struct cw1200_sta_priv { struct cw1200_sta_priv {
...@@ -299,8 +290,8 @@ struct cw1200_sta_priv { ...@@ -299,8 +290,8 @@ struct cw1200_sta_priv {
}; };
/* interfaces for the drivers */ /* interfaces for the drivers */
int cw1200_core_probe(const struct sbus_ops *sbus_ops, int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
struct sbus_priv *sbus, struct hwbus_priv *hwbus,
struct device *pdev, struct device *pdev,
struct cw1200_common **pself, struct cw1200_common **pself,
int ref_clk, const u8 *macaddr, int ref_clk, const u8 *macaddr,
......
/*
* Platform glue data for ST-Ericsson CW1200 driver
*
* Copyright (c) 2013, Sagrad, Inc
* Author: Solomon Peachy <speachy@sagrad.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.
*/
#include <linux/module.h>
#include <linux/cw1200_platform.h>
MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
MODULE_DESCRIPTION("ST-Ericsson CW1200 Platform glue driver");
MODULE_LICENSE("GPL");
/* Define just one of these. Feel free to customize as needed */
#define SAGRAD_1091_1098_EVK_SDIO
/* #define SAGRAD_1091_1098_EVK_SPI */
#ifdef SAGRAD_1091_1098_EVK_SDIO
#if 0
static struct resource cw1200_href_resources[] = {
{
.start = 215, /* fix me as appropriate */
.end = 215, /* ditto */
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_reset",
},
{
.start = 216, /* fix me as appropriate */
.end = 216, /* ditto */
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_powerup",
},
{
.start = NOMADIK_GPIO_TO_IRQ(216), /* fix me as appropriate */
.end = NOMADIK_GPIO_TO_IRQ(216), /* ditto */
.flags = IORESOURCE_IRQ,
.name = "cw1200_wlan_irq",
},
};
#endif
static int cw1200_power_ctrl(const struct cw1200_platform_data_sdio *pdata,
bool enable)
{
/* Control 3v3 and 1v8 to hardware as appropriate */
/* Note this is not needed if it's controlled elsewhere or always on */
/* May require delay for power to stabilize */
return 0;
}
static int cw1200_clk_ctrl(const struct cw1200_platform_data_sdio *pdata,
bool enable)
{
/* Turn CLK_32K off and on as appropriate. */
/* Note this is not needed if it's always on */
/* May require delay for clock to stabilize */
return 0;
}
static struct cw1200_platform_data_sdio cw1200_platform_data = {
.ref_clk = 38400,
.have_5ghz = false,
#if 0
.reset = &cw1200_href_resources[0],
.powerup = &cw1200_href_resources[1],
.irq = &cw1200_href_resources[2],
#endif
.power_ctrl = cw1200_power_ctrl,
.clk_ctrl = cw1200_clk_ctrl,
/* .macaddr = ??? */
.sdd_file = "sdd_sagrad_1091_1098.bin",
};
#endif
#ifdef SAGRAD_1091_1098_EVK_SPI
/* Note that this is an example of integrating into your board support file */
static struct resource cw1200_href_resources[] = {
{
.start = GPIO_RF_RESET,
.end = GPIO_RF_RESET,
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_reset",
},
{
.start = GPIO_RF_POWERUP,
.end = GPIO_RF_POWERUP,
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_powerup",
},
};
static int cw1200_power_ctrl(const struct cw1200_platform_data_spi *pdata,
bool enable)
{
/* Control 3v3 and 1v8 to hardware as appropriate */
/* Note this is not needed if it's controlled elsewhere or always on */
/* May require delay for power to stabilize */
return 0;
}
static int cw1200_clk_ctrl(const struct cw1200_platform_data_spi *pdata,
bool enable)
{
/* Turn CLK_32K off and on as appropriate. */
/* Note this is not needed if it's always on */
/* May require delay for clock to stabilize */
return 0;
}
static struct cw1200_platform_data_spi cw1200_platform_data = {
.ref_clk = 38400,
.spi_bits_per_word = 16,
.reset = &cw1200_href_resources[0],
.powerup = &cw1200_href_resources[1],
.power_ctrl = cw1200_power_ctrl,
.clk_ctrl = cw1200_clk_ctrl,
/* .macaddr = ??? */
.sdd_file = "sdd_sagrad_1091_1098.bin",
};
static struct spi_board_info myboard_spi_devices[] __initdata = {
{
.modalias = "cw1200_wlan_spi",
.max_speed_hz = 10000000, /* 52MHz Max */
.bus_num = 0,
.irq = WIFI_IRQ,
.platform_data = &cw1200_platform_data,
.chip_select = 0,
},
};
#endif
const void *cw1200_get_platform_data(void)
{
return &cw1200_platform_data;
}
EXPORT_SYMBOL_GPL(cw1200_get_platform_data);
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -20,8 +19,8 @@ ...@@ -20,8 +19,8 @@
#include <net/mac80211.h> #include <net/mac80211.h>
#include "cw1200.h" #include "cw1200.h"
#include "sbus.h" #include "hwbus.h"
#include <linux/cw1200_platform.h> #include <linux/platform_data/net-cw1200.h>
#include "hwio.h" #include "hwio.h"
MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>"); MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
...@@ -30,7 +29,22 @@ MODULE_LICENSE("GPL"); ...@@ -30,7 +29,22 @@ MODULE_LICENSE("GPL");
#define SDIO_BLOCK_SIZE (512) #define SDIO_BLOCK_SIZE (512)
struct sbus_priv { /* Default platform data for Sagrad modules */
static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = {
.ref_clk = 38400,
.have_5ghz = false,
.sdd_file = "sdd_sagrad_1091_1098.bin",
};
/* Allow platform data to be overridden */
static struct cw1200_platform_data_sdio *global_plat_data = &sagrad_109x_evk_platform_data;
void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata)
{
global_plat_data = pdata;
}
struct hwbus_priv {
struct sdio_func *func; struct sdio_func *func;
struct cw1200_common *core; struct cw1200_common *core;
const struct cw1200_platform_data_sdio *pdata; const struct cw1200_platform_data_sdio *pdata;
...@@ -49,35 +63,35 @@ static const struct sdio_device_id cw1200_sdio_ids[] = { ...@@ -49,35 +63,35 @@ static const struct sdio_device_id cw1200_sdio_ids[] = {
{ /* end: all zeroes */ }, { /* end: all zeroes */ },
}; };
/* sbus_ops implemetation */ /* hwbus_ops implemetation */
static int cw1200_sdio_memcpy_fromio(struct sbus_priv *self, static int cw1200_sdio_memcpy_fromio(struct hwbus_priv *self,
unsigned int addr, unsigned int addr,
void *dst, int count) void *dst, int count)
{ {
return sdio_memcpy_fromio(self->func, dst, addr, count); return sdio_memcpy_fromio(self->func, dst, addr, count);
} }
static int cw1200_sdio_memcpy_toio(struct sbus_priv *self, static int cw1200_sdio_memcpy_toio(struct hwbus_priv *self,
unsigned int addr, unsigned int addr,
const void *src, int count) const void *src, int count)
{ {
return sdio_memcpy_toio(self->func, addr, (void *)src, count); return sdio_memcpy_toio(self->func, addr, (void *)src, count);
} }
static void cw1200_sdio_lock(struct sbus_priv *self) static void cw1200_sdio_lock(struct hwbus_priv *self)
{ {
sdio_claim_host(self->func); sdio_claim_host(self->func);
} }
static void cw1200_sdio_unlock(struct sbus_priv *self) static void cw1200_sdio_unlock(struct hwbus_priv *self)
{ {
sdio_release_host(self->func); sdio_release_host(self->func);
} }
static void cw1200_sdio_irq_handler(struct sdio_func *func) static void cw1200_sdio_irq_handler(struct sdio_func *func)
{ {
struct sbus_priv *self = sdio_get_drvdata(func); struct hwbus_priv *self = sdio_get_drvdata(func);
/* note: sdio_host already claimed here. */ /* note: sdio_host already claimed here. */
if (self->core) if (self->core)
...@@ -91,7 +105,7 @@ static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id) ...@@ -91,7 +105,7 @@ static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id)
static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id) static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
{ {
struct sbus_priv *self = dev_id; struct hwbus_priv *self = dev_id;
if (self->core) { if (self->core) {
sdio_claim_host(self->func); sdio_claim_host(self->func);
...@@ -103,10 +117,9 @@ static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id) ...@@ -103,10 +117,9 @@ static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
} }
} }
static int cw1200_request_irq(struct sbus_priv *self) static int cw1200_request_irq(struct hwbus_priv *self)
{ {
int ret; int ret;
const struct resource *irq = self->pdata->irq;
u8 cccr; u8 cccr;
cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret); cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
...@@ -123,15 +136,15 @@ static int cw1200_request_irq(struct sbus_priv *self) ...@@ -123,15 +136,15 @@ static int cw1200_request_irq(struct sbus_priv *self)
if (WARN_ON(ret)) if (WARN_ON(ret))
goto err; goto err;
ret = enable_irq_wake(irq->start); ret = enable_irq_wake(self->pdata->irq);
if (WARN_ON(ret)) if (WARN_ON(ret))
goto err; goto err;
/* Request the IRQ */ /* Request the IRQ */
ret = request_threaded_irq(irq->start, cw1200_gpio_hardirq, ret = request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq,
cw1200_gpio_irq, cw1200_gpio_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
irq->name, self); "cw1200_wlan_irq", self);
if (WARN_ON(ret)) if (WARN_ON(ret))
goto err; goto err;
...@@ -141,7 +154,7 @@ static int cw1200_request_irq(struct sbus_priv *self) ...@@ -141,7 +154,7 @@ static int cw1200_request_irq(struct sbus_priv *self)
return ret; return ret;
} }
static int cw1200_sdio_irq_subscribe(struct sbus_priv *self) static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self)
{ {
int ret = 0; int ret = 0;
...@@ -156,15 +169,15 @@ static int cw1200_sdio_irq_subscribe(struct sbus_priv *self) ...@@ -156,15 +169,15 @@ static int cw1200_sdio_irq_subscribe(struct sbus_priv *self)
return ret; return ret;
} }
static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self) static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self)
{ {
int ret = 0; int ret = 0;
pr_debug("SW IRQ unsubscribe\n"); pr_debug("SW IRQ unsubscribe\n");
if (self->pdata->irq) { if (self->pdata->irq) {
disable_irq_wake(self->pdata->irq->start); disable_irq_wake(self->pdata->irq);
free_irq(self->pdata->irq->start, self); free_irq(self->pdata->irq, self);
} else { } else {
sdio_claim_host(self->func); sdio_claim_host(self->func);
ret = sdio_release_irq(self->func); ret = sdio_release_irq(self->func);
...@@ -175,12 +188,10 @@ static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self) ...@@ -175,12 +188,10 @@ static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self)
static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata) static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
{ {
const struct resource *reset = pdata->reset; if (pdata->reset) {
gpio_set_value(pdata->reset, 0);
if (reset) {
gpio_set_value(reset->start, 0);
msleep(30); /* Min is 2 * CLK32K cycles */ msleep(30); /* Min is 2 * CLK32K cycles */
gpio_free(reset->start); gpio_free(pdata->reset);
} }
if (pdata->power_ctrl) if (pdata->power_ctrl)
...@@ -193,20 +204,17 @@ static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata) ...@@ -193,20 +204,17 @@ static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata) static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
{ {
const struct resource *reset = pdata->reset;
const struct resource *powerup = pdata->reset;
/* Ensure I/Os are pulled low */ /* Ensure I/Os are pulled low */
if (reset) { if (pdata->reset) {
gpio_request(reset->start, reset->name); gpio_request(pdata->reset, "cw1200_wlan_reset");
gpio_direction_output(reset->start, 0); gpio_direction_output(pdata->reset, 0);
} }
if (powerup) { if (pdata->powerup) {
gpio_request(powerup->start, powerup->name); gpio_request(pdata->powerup, "cw1200_wlan_powerup");
gpio_direction_output(powerup->start, 0); gpio_direction_output(pdata->powerup, 0);
} }
if (reset || powerup) if (pdata->reset || pdata->powerup)
msleep(50); /* Settle time */ msleep(10); /* Settle time? */
/* Enable 3v3 and 1v8 to hardware */ /* Enable 3v3 and 1v8 to hardware */
if (pdata->power_ctrl) { if (pdata->power_ctrl) {
...@@ -226,19 +234,19 @@ static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata) ...@@ -226,19 +234,19 @@ static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
} }
/* Enable POWERUP signal */ /* Enable POWERUP signal */
if (powerup) { if (pdata->powerup) {
gpio_set_value(powerup->start, 1); gpio_set_value(pdata->powerup, 1);
msleep(250); /* or more..? */ msleep(250); /* or more..? */
} }
/* Enable RSTn signal */ /* Enable RSTn signal */
if (reset) { if (pdata->reset) {
gpio_set_value(reset->start, 1); gpio_set_value(pdata->reset, 1);
msleep(50); /* Or more..? */ msleep(50); /* Or more..? */
} }
return 0; return 0;
} }
static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size) static size_t cw1200_sdio_align_size(struct hwbus_priv *self, size_t size)
{ {
if (self->pdata->no_nptb) if (self->pdata->no_nptb)
size = round_up(size, SDIO_BLOCK_SIZE); size = round_up(size, SDIO_BLOCK_SIZE);
...@@ -248,18 +256,18 @@ static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size) ...@@ -248,18 +256,18 @@ static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size)
return size; return size;
} }
static int cw1200_sdio_pm(struct sbus_priv *self, bool suspend) static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend)
{ {
int ret = 0; int ret = 0;
if (self->pdata->irq) if (self->pdata->irq)
ret = irq_set_irq_wake(self->pdata->irq->start, suspend); ret = irq_set_irq_wake(self->pdata->irq, suspend);
return ret; return ret;
} }
static struct sbus_ops cw1200_sdio_sbus_ops = { static struct hwbus_ops cw1200_sdio_hwbus_ops = {
.sbus_memcpy_fromio = cw1200_sdio_memcpy_fromio, .hwbus_memcpy_fromio = cw1200_sdio_memcpy_fromio,
.sbus_memcpy_toio = cw1200_sdio_memcpy_toio, .hwbus_memcpy_toio = cw1200_sdio_memcpy_toio,
.lock = cw1200_sdio_lock, .lock = cw1200_sdio_lock,
.unlock = cw1200_sdio_unlock, .unlock = cw1200_sdio_unlock,
.align_size = cw1200_sdio_align_size, .align_size = cw1200_sdio_align_size,
...@@ -268,26 +276,26 @@ static struct sbus_ops cw1200_sdio_sbus_ops = { ...@@ -268,26 +276,26 @@ static struct sbus_ops cw1200_sdio_sbus_ops = {
/* Probe Function to be called by SDIO stack when device is discovered */ /* Probe Function to be called by SDIO stack when device is discovered */
static int cw1200_sdio_probe(struct sdio_func *func, static int cw1200_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id) const struct sdio_device_id *id)
{ {
struct sbus_priv *self; struct hwbus_priv *self;
int status; int status;
pr_info("cw1200_wlan_sdio: Probe called\n"); pr_info("cw1200_wlan_sdio: Probe called\n");
/* We are only able to handle the wlan function */ /* We are only able to handle the wlan function */
if (func->num != 0x01) if (func->num != 0x01)
return -ENODEV; return -ENODEV;
self = kzalloc(sizeof(*self), GFP_KERNEL); self = kzalloc(sizeof(*self), GFP_KERNEL);
if (!self) { if (!self) {
pr_err("Can't allocate SDIO sbus_priv.\n"); pr_err("Can't allocate SDIO hwbus_priv.\n");
return -ENOMEM; return -ENOMEM;
} }
func->card->quirks |= MMC_QUIRK_LENIENT_FN0; func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
self->pdata = cw1200_get_platform_data(); self->pdata = global_plat_data; /* FIXME */
self->func = func; self->func = func;
sdio_set_drvdata(func, self); sdio_set_drvdata(func, self);
sdio_claim_host(func); sdio_claim_host(func);
...@@ -296,7 +304,7 @@ static int cw1200_sdio_probe(struct sdio_func *func, ...@@ -296,7 +304,7 @@ static int cw1200_sdio_probe(struct sdio_func *func,
status = cw1200_sdio_irq_subscribe(self); status = cw1200_sdio_irq_subscribe(self);
status = cw1200_core_probe(&cw1200_sdio_sbus_ops, status = cw1200_core_probe(&cw1200_sdio_hwbus_ops,
self, &func->dev, &self->core, self, &func->dev, &self->core,
self->pdata->ref_clk, self->pdata->ref_clk,
self->pdata->macaddr, self->pdata->macaddr,
...@@ -315,10 +323,11 @@ static int cw1200_sdio_probe(struct sdio_func *func, ...@@ -315,10 +323,11 @@ static int cw1200_sdio_probe(struct sdio_func *func,
} }
/* Disconnect Function to be called by SDIO stack when /* Disconnect Function to be called by SDIO stack when
* device is disconnected */ * device is disconnected
*/
static void cw1200_sdio_disconnect(struct sdio_func *func) static void cw1200_sdio_disconnect(struct sdio_func *func)
{ {
struct sbus_priv *self = sdio_get_drvdata(func); struct hwbus_priv *self = sdio_get_drvdata(func);
if (self) { if (self) {
cw1200_sdio_irq_unsubscribe(self); cw1200_sdio_irq_unsubscribe(self);
...@@ -334,11 +343,12 @@ static void cw1200_sdio_disconnect(struct sdio_func *func) ...@@ -334,11 +343,12 @@ static void cw1200_sdio_disconnect(struct sdio_func *func)
} }
} }
#ifdef CONFIG_PM
static int cw1200_sdio_suspend(struct device *dev) static int cw1200_sdio_suspend(struct device *dev)
{ {
int ret; int ret;
struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_func *func = dev_to_sdio_func(dev);
struct sbus_priv *self = sdio_get_drvdata(func); struct hwbus_priv *self = sdio_get_drvdata(func);
if (!cw1200_can_suspend(self->core)) if (!cw1200_can_suspend(self->core))
return -EAGAIN; return -EAGAIN;
...@@ -360,15 +370,18 @@ static const struct dev_pm_ops cw1200_pm_ops = { ...@@ -360,15 +370,18 @@ static const struct dev_pm_ops cw1200_pm_ops = {
.suspend = cw1200_sdio_suspend, .suspend = cw1200_sdio_suspend,
.resume = cw1200_sdio_resume, .resume = cw1200_sdio_resume,
}; };
#endif
static struct sdio_driver sdio_driver = { static struct sdio_driver sdio_driver = {
.name = "cw1200_wlan_sdio", .name = "cw1200_wlan_sdio",
.id_table = cw1200_sdio_ids, .id_table = cw1200_sdio_ids,
.probe = cw1200_sdio_probe, .probe = cw1200_sdio_probe,
.remove = cw1200_sdio_disconnect, .remove = cw1200_sdio_disconnect,
#ifdef CONFIG_PM
.drv = { .drv = {
.pm = &cw1200_pm_ops, .pm = &cw1200_pm_ops,
} }
#endif
}; };
/* Init Module function -> Called by insmod */ /* Init Module function -> Called by insmod */
...@@ -377,7 +390,8 @@ static int __init cw1200_sdio_init(void) ...@@ -377,7 +390,8 @@ static int __init cw1200_sdio_init(void)
const struct cw1200_platform_data_sdio *pdata; const struct cw1200_platform_data_sdio *pdata;
int ret; int ret;
pdata = cw1200_get_platform_data(); /* FIXME -- this won't support multiple devices */
pdata = global_plat_data;
if (cw1200_sdio_on(pdata)) { if (cw1200_sdio_on(pdata)) {
ret = -1; ret = -1;
...@@ -399,7 +413,9 @@ static int __init cw1200_sdio_init(void) ...@@ -399,7 +413,9 @@ static int __init cw1200_sdio_init(void)
static void __exit cw1200_sdio_exit(void) static void __exit cw1200_sdio_exit(void)
{ {
const struct cw1200_platform_data_sdio *pdata; const struct cw1200_platform_data_sdio *pdata;
pdata = cw1200_get_platform_data();
/* FIXME -- this won't support multiple devices */
pdata = global_plat_data;
sdio_unregister_driver(&sdio_driver); sdio_unregister_driver(&sdio_driver);
cw1200_sdio_off(pdata); cw1200_sdio_off(pdata);
} }
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -25,8 +24,8 @@ ...@@ -25,8 +24,8 @@
#include <linux/device.h> #include <linux/device.h>
#include "cw1200.h" #include "cw1200.h"
#include "sbus.h" #include "hwbus.h"
#include <linux/cw1200_platform.h> #include <linux/platform_data/net-cw1200.h>
#include "hwio.h" #include "hwio.h"
MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>"); MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
...@@ -36,7 +35,7 @@ MODULE_ALIAS("spi:cw1200_wlan_spi"); ...@@ -36,7 +35,7 @@ MODULE_ALIAS("spi:cw1200_wlan_spi");
/* #define SPI_DEBUG */ /* #define SPI_DEBUG */
struct sbus_priv { struct hwbus_priv {
struct spi_device *func; struct spi_device *func;
struct cw1200_common *core; struct cw1200_common *core;
const struct cw1200_platform_data_spi *pdata; const struct cw1200_platform_data_spi *pdata;
...@@ -48,18 +47,16 @@ struct sbus_priv { ...@@ -48,18 +47,16 @@ struct sbus_priv {
#define SET_WRITE 0x7FFF /* usage: and operation */ #define SET_WRITE 0x7FFF /* usage: and operation */
#define SET_READ 0x8000 /* usage: or operation */ #define SET_READ 0x8000 /* usage: or operation */
/* /* Notes on byte ordering:
Notes on byte ordering:
LE: B0 B1 B2 B3 LE: B0 B1 B2 B3
BE: B3 B2 B1 B0 BE: B3 B2 B1 B0
Hardware expects 32-bit data to be written as 16-bit BE words: Hardware expects 32-bit data to be written as 16-bit BE words:
B1 B0 B3 B2 B1 B0 B3 B2
*/ */
static int cw1200_spi_memcpy_fromio(struct sbus_priv *self, static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self,
unsigned int addr, unsigned int addr,
void *dst, int count) void *dst, int count)
{ {
...@@ -120,7 +117,7 @@ static int cw1200_spi_memcpy_fromio(struct sbus_priv *self, ...@@ -120,7 +117,7 @@ static int cw1200_spi_memcpy_fromio(struct sbus_priv *self,
return ret; return ret;
} }
static int cw1200_spi_memcpy_toio(struct sbus_priv *self, static int cw1200_spi_memcpy_toio(struct hwbus_priv *self,
unsigned int addr, unsigned int addr,
const void *src, int count) const void *src, int count)
{ {
...@@ -188,7 +185,7 @@ static int cw1200_spi_memcpy_toio(struct sbus_priv *self, ...@@ -188,7 +185,7 @@ static int cw1200_spi_memcpy_toio(struct sbus_priv *self,
return rval; return rval;
} }
static void cw1200_spi_lock(struct sbus_priv *self) static void cw1200_spi_lock(struct hwbus_priv *self)
{ {
unsigned long flags; unsigned long flags;
...@@ -210,7 +207,7 @@ static void cw1200_spi_lock(struct sbus_priv *self) ...@@ -210,7 +207,7 @@ static void cw1200_spi_lock(struct sbus_priv *self)
return; return;
} }
static void cw1200_spi_unlock(struct sbus_priv *self) static void cw1200_spi_unlock(struct hwbus_priv *self)
{ {
unsigned long flags; unsigned long flags;
...@@ -222,7 +219,7 @@ static void cw1200_spi_unlock(struct sbus_priv *self) ...@@ -222,7 +219,7 @@ static void cw1200_spi_unlock(struct sbus_priv *self)
static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
{ {
struct sbus_priv *self = dev_id; struct hwbus_priv *self = dev_id;
if (self->core) { if (self->core) {
cw1200_irq_handler(self->core); cw1200_irq_handler(self->core);
...@@ -232,7 +229,7 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) ...@@ -232,7 +229,7 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
} }
} }
static int cw1200_spi_irq_subscribe(struct sbus_priv *self) static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
{ {
int ret; int ret;
...@@ -256,7 +253,7 @@ static int cw1200_spi_irq_subscribe(struct sbus_priv *self) ...@@ -256,7 +253,7 @@ static int cw1200_spi_irq_subscribe(struct sbus_priv *self)
return ret; return ret;
} }
static int cw1200_spi_irq_unsubscribe(struct sbus_priv *self) static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
{ {
int ret = 0; int ret = 0;
...@@ -269,12 +266,10 @@ static int cw1200_spi_irq_unsubscribe(struct sbus_priv *self) ...@@ -269,12 +266,10 @@ static int cw1200_spi_irq_unsubscribe(struct sbus_priv *self)
static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
{ {
const struct resource *reset = pdata->reset; if (pdata->reset) {
gpio_set_value(pdata->reset, 0);
if (reset) {
gpio_set_value(reset->start, 0);
msleep(30); /* Min is 2 * CLK32K cycles */ msleep(30); /* Min is 2 * CLK32K cycles */
gpio_free(reset->start); gpio_free(pdata->reset);
} }
if (pdata->power_ctrl) if (pdata->power_ctrl)
...@@ -287,19 +282,16 @@ static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) ...@@ -287,19 +282,16 @@ static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
{ {
const struct resource *reset = pdata->reset;
const struct resource *powerup = pdata->reset;
/* Ensure I/Os are pulled low */ /* Ensure I/Os are pulled low */
if (reset) { if (pdata->reset) {
gpio_request(reset->start, reset->name); gpio_request(pdata->reset, "cw1200_wlan_reset");
gpio_direction_output(reset->start, 0); gpio_direction_output(pdata->reset, 0);
} }
if (powerup) { if (pdata->powerup) {
gpio_request(powerup->start, powerup->name); gpio_request(pdata->powerup, "cw1200_wlan_powerup");
gpio_direction_output(powerup->start, 0); gpio_direction_output(pdata->powerup, 0);
} }
if (reset || powerup) if (pdata->reset || pdata->powerup)
msleep(10); /* Settle time? */ msleep(10); /* Settle time? */
/* Enable 3v3 and 1v8 to hardware */ /* Enable 3v3 and 1v8 to hardware */
...@@ -320,31 +312,31 @@ static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) ...@@ -320,31 +312,31 @@ static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
} }
/* Enable POWERUP signal */ /* Enable POWERUP signal */
if (powerup) { if (pdata->powerup) {
gpio_set_value(powerup->start, 1); gpio_set_value(pdata->powerup, 1);
msleep(250); /* or more..? */ msleep(250); /* or more..? */
} }
/* Enable RSTn signal */ /* Enable RSTn signal */
if (reset) { if (pdata->reset) {
gpio_set_value(reset->start, 1); gpio_set_value(pdata->reset, 1);
msleep(50); /* Or more..? */ msleep(50); /* Or more..? */
} }
return 0; return 0;
} }
static size_t cw1200_spi_align_size(struct sbus_priv *self, size_t size) static size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size)
{ {
return size & 1 ? size + 1 : size; return size & 1 ? size + 1 : size;
} }
static int cw1200_spi_pm(struct sbus_priv *self, bool suspend) static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend)
{ {
return irq_set_irq_wake(self->func->irq, suspend); return irq_set_irq_wake(self->func->irq, suspend);
} }
static struct sbus_ops cw1200_spi_sbus_ops = { static struct hwbus_ops cw1200_spi_hwbus_ops = {
.sbus_memcpy_fromio = cw1200_spi_memcpy_fromio, .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio,
.sbus_memcpy_toio = cw1200_spi_memcpy_toio, .hwbus_memcpy_toio = cw1200_spi_memcpy_toio,
.lock = cw1200_spi_lock, .lock = cw1200_spi_lock,
.unlock = cw1200_spi_unlock, .unlock = cw1200_spi_unlock,
.align_size = cw1200_spi_align_size, .align_size = cw1200_spi_align_size,
...@@ -356,7 +348,7 @@ static int cw1200_spi_probe(struct spi_device *func) ...@@ -356,7 +348,7 @@ static int cw1200_spi_probe(struct spi_device *func)
{ {
const struct cw1200_platform_data_spi *plat_data = const struct cw1200_platform_data_spi *plat_data =
func->dev.platform_data; func->dev.platform_data;
struct sbus_priv *self; struct hwbus_priv *self;
int status; int status;
/* Sanity check speed */ /* Sanity check speed */
...@@ -390,7 +382,7 @@ static int cw1200_spi_probe(struct spi_device *func) ...@@ -390,7 +382,7 @@ static int cw1200_spi_probe(struct spi_device *func)
self = kzalloc(sizeof(*self), GFP_KERNEL); self = kzalloc(sizeof(*self), GFP_KERNEL);
if (!self) { if (!self) {
pr_err("Can't allocate SPI sbus_priv."); pr_err("Can't allocate SPI hwbus_priv.");
return -ENOMEM; return -ENOMEM;
} }
...@@ -402,7 +394,7 @@ static int cw1200_spi_probe(struct spi_device *func) ...@@ -402,7 +394,7 @@ static int cw1200_spi_probe(struct spi_device *func)
status = cw1200_spi_irq_subscribe(self); status = cw1200_spi_irq_subscribe(self);
status = cw1200_core_probe(&cw1200_spi_sbus_ops, status = cw1200_core_probe(&cw1200_spi_hwbus_ops,
self, &func->dev, &self->core, self, &func->dev, &self->core,
self->pdata->ref_clk, self->pdata->ref_clk,
self->pdata->macaddr, self->pdata->macaddr,
...@@ -421,7 +413,7 @@ static int cw1200_spi_probe(struct spi_device *func) ...@@ -421,7 +413,7 @@ static int cw1200_spi_probe(struct spi_device *func)
/* Disconnect Function to be called by SPI stack when device is disconnected */ /* Disconnect Function to be called by SPI stack when device is disconnected */
static int cw1200_spi_disconnect(struct spi_device *func) static int cw1200_spi_disconnect(struct spi_device *func)
{ {
struct sbus_priv *self = spi_get_drvdata(func); struct hwbus_priv *self = spi_get_drvdata(func);
if (self) { if (self) {
cw1200_spi_irq_unsubscribe(self); cw1200_spi_irq_unsubscribe(self);
...@@ -436,9 +428,10 @@ static int cw1200_spi_disconnect(struct spi_device *func) ...@@ -436,9 +428,10 @@ static int cw1200_spi_disconnect(struct spi_device *func)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int cw1200_spi_suspend(struct device *dev, pm_message_t state) static int cw1200_spi_suspend(struct device *dev, pm_message_t state)
{ {
struct sbus_priv *self = spi_get_drvdata(to_spi_device(dev)); struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
if (!cw1200_can_suspend(self->core)) if (!cw1200_can_suspend(self->core))
return -EAGAIN; return -EAGAIN;
...@@ -451,6 +444,7 @@ static int cw1200_spi_resume(struct device *dev) ...@@ -451,6 +444,7 @@ static int cw1200_spi_resume(struct device *dev)
{ {
return 0; return 0;
} }
#endif
static struct spi_driver spi_driver = { static struct spi_driver spi_driver = {
.probe = cw1200_spi_probe, .probe = cw1200_spi_probe,
...@@ -459,22 +453,11 @@ static struct spi_driver spi_driver = { ...@@ -459,22 +453,11 @@ static struct spi_driver spi_driver = {
.name = "cw1200_wlan_spi", .name = "cw1200_wlan_spi",
.bus = &spi_bus_type, .bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.suspend = cw1200_spi_suspend, .suspend = cw1200_spi_suspend,
.resume = cw1200_spi_resume, .resume = cw1200_spi_resume,
#endif
}, },
}; };
/* Init Module function -> Called by insmod */ module_spi_driver(spi_driver);
static int __init cw1200_spi_init(void)
{
return spi_register_driver(&spi_driver);
}
/* Called at Driver Unloading */
static void __exit cw1200_spi_exit(void)
{
spi_unregister_driver(&spi_driver);
}
module_init(cw1200_spi_init);
module_exit(cw1200_spi_exit);
...@@ -357,140 +357,6 @@ static const struct file_operations fops_counters = { ...@@ -357,140 +357,6 @@ static const struct file_operations fops_counters = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int cw1200_generic_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
#ifdef CONFIG_CW1200_ETF
static int cw1200_etf_out_show(struct seq_file *seq, void *v)
{
struct cw1200_common *priv = seq->private;
struct sk_buff *skb;
u32 len = 0;
skb = skb_dequeue(&priv->etf_q);
if (skb)
len = skb->len;
seq_write(seq, &len, sizeof(len));
if (skb) {
seq_write(seq, skb->data, len);
kfree_skb(skb);
}
return 0;
}
static int cw1200_etf_out_open(struct inode *inode, struct file *file)
{
return single_open(file, &cw1200_etf_out_show,
inode->i_private);
}
static const struct file_operations fops_etf_out = {
.open = cw1200_etf_out_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
struct etf_req_msg;
static int etf_request(struct cw1200_common *priv,
struct etf_req_msg *msg, u32 len);
#define MAX_RX_SZE 2600
struct etf_in_state {
struct cw1200_common *priv;
u32 total_len;
u8 buf[MAX_RX_SZE];
u32 written;
};
static int cw1200_etf_in_open(struct inode *inode, struct file *file)
{
struct etf_in_state *etf = kmalloc(sizeof(struct etf_in_state),
GFP_KERNEL);
if (!etf)
return -ENOMEM;
etf->written = 0;
etf->total_len = 0;
etf->priv = inode->i_private;
file->private_data = etf;
return 0;
}
static int cw1200_etf_in_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
return 0;
}
static ssize_t cw1200_etf_in_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct etf_in_state *etf = file->private_data;
ssize_t written = 0;
if (!etf->total_len) {
if (count < sizeof(etf->total_len)) {
pr_err("count < sizeof(total_len)\n");
return -EINVAL;
}
if (copy_from_user(&etf->total_len, user_buf,
sizeof(etf->total_len))) {
pr_err("copy_from_user (len) failed\n");
return -EFAULT;
}
written += sizeof(etf->total_len);
count -= sizeof(etf->total_len);
}
if (!count)
goto done;
if (copy_from_user(etf->buf + etf->written, user_buf + written,
count)) {
pr_err("copy_from_user (payload %zu) failed\n", count);
return -EFAULT;
}
written += count;
etf->written += count;
if (etf->written >= etf->total_len) {
if (etf_request(etf->priv, (struct etf_req_msg *)etf->buf,
etf->total_len)) {
pr_err("etf_request failed\n");
return -EIO;
}
}
done:
return written;
}
static const struct file_operations fops_etf_in = {
.open = cw1200_etf_in_open,
.release = cw1200_etf_in_release,
.write = cw1200_etf_in_write,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
#endif /* CONFIG_CW1200_ETF */
static ssize_t cw1200_wsm_dumps(struct file *file, static ssize_t cw1200_wsm_dumps(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos) const char __user *user_buf, size_t count, loff_t *ppos)
{ {
...@@ -511,7 +377,7 @@ static ssize_t cw1200_wsm_dumps(struct file *file, ...@@ -511,7 +377,7 @@ static ssize_t cw1200_wsm_dumps(struct file *file,
} }
static const struct file_operations fops_wsm_dumps = { static const struct file_operations fops_wsm_dumps = {
.open = cw1200_generic_open, .open = simple_open,
.write = cw1200_wsm_dumps, .write = cw1200_wsm_dumps,
.llseek = default_llseek, .llseek = default_llseek,
}; };
...@@ -538,27 +404,10 @@ int cw1200_debug_init(struct cw1200_common *priv) ...@@ -538,27 +404,10 @@ int cw1200_debug_init(struct cw1200_common *priv)
priv, &fops_counters)) priv, &fops_counters))
goto err; goto err;
#ifdef CONFIG_CW1200_ETF
if (etf_mode) {
skb_queue_head_init(&priv->etf_q);
if (!debugfs_create_file("etf_out", S_IRUSR, d->debugfs_phy,
priv, &fops_etf_out))
goto err;
if (!debugfs_create_file("etf_in", S_IWUSR, d->debugfs_phy,
priv, &fops_etf_in))
goto err;
}
#endif /* CONFIG_CW1200_ETF */
if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy, if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy,
priv, &fops_wsm_dumps)) priv, &fops_wsm_dumps))
goto err; goto err;
ret = cw1200_itp_init(priv);
if (ret)
goto err;
return 0; return 0;
err: err:
...@@ -572,93 +421,8 @@ void cw1200_debug_release(struct cw1200_common *priv) ...@@ -572,93 +421,8 @@ void cw1200_debug_release(struct cw1200_common *priv)
{ {
struct cw1200_debug_priv *d = priv->debug; struct cw1200_debug_priv *d = priv->debug;
if (d) { if (d) {
cw1200_itp_release(priv); debugfs_remove_recursive(d->debugfs_phy);
priv->debug = NULL; priv->debug = NULL;
kfree(d); kfree(d);
} }
} }
#ifdef CONFIG_CW1200_ETF
struct cw1200_sdd {
u8 id;
u8 len;
u8 data[];
};
struct etf_req_msg {
u32 id;
u32 len;
u8 data[];
};
static int parse_sdd_file(struct cw1200_common *priv, u8 *data, u32 length)
{
struct cw1200_sdd *ie;
while (length > 0) {
ie = (struct cw1200_sdd *)data;
if (ie->id == SDD_REFERENCE_FREQUENCY_ELT_ID) {
priv->hw_refclk = cpu_to_le16(*((u16 *)ie->data));
pr_info("Using Reference clock frequency %d KHz\n",
priv->hw_refclk);
break;
}
length -= ie->len + sizeof(*ie);
data += ie->len + sizeof(*ie);
}
return 0;
}
char *etf_firmware;
#define ST90TDS_START_ADAPTER 0x09 /* Loads firmware too */
#define ST90TDS_STOP_ADAPTER 0x0A
#define ST90TDS_CONFIG_ADAPTER 0x0E /* Send configuration params */
#define ST90TDS_SBUS_READ 0x13
#define ST90TDS_SBUS_WRITE 0x14
#define ST90TDS_GET_DEVICE_OPTION 0x19
#define ST90TDS_SET_DEVICE_OPTION 0x1A
#define ST90TDS_SEND_SDD 0x1D /* SDD File used to find DPLL */
#include "fwio.h"
static int etf_request(struct cw1200_common *priv,
struct etf_req_msg *msg,
u32 len)
{
int rval = -1;
switch (msg->id) {
case ST90TDS_START_ADAPTER:
etf_firmware = "cw1200_etf.bin";
pr_info("ETF_START (len %d, '%s')\n", len, etf_firmware);
rval = cw1200_load_firmware(priv);
break;
case ST90TDS_STOP_ADAPTER:
pr_info("ETF_STOP (unhandled)\n");
break;
case ST90TDS_SEND_SDD:
pr_info("ETF_SDD\n");
rval = parse_sdd_file(priv, msg->data, msg->len);
break;
case ST90TDS_CONFIG_ADAPTER:
pr_info("ETF_CONFIG_ADAP (unhandled)\n");
break;
case ST90TDS_SBUS_READ:
pr_info("ETF_SBUS_READ (unhandled)\n");
break;
case ST90TDS_SBUS_WRITE:
pr_info("ETF_SBUS_WRITE (unhandled)\n");
break;
case ST90TDS_SET_DEVICE_OPTION:
pr_info("ETF_SET_DEV_OPT (unhandled)\n");
break;
default:
pr_info("ETF_PASSTHRU (0x%08x)\n", msg->id);
rval = wsm_raw_cmd(priv, (u8 *)msg, len);
break;
}
return rval;
}
#endif /* CONFIG_CW1200_ETF */
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#ifndef CW1200_DEBUG_H_INCLUDED #ifndef CW1200_DEBUG_H_INCLUDED
#define CW1200_DEBUG_H_INCLUDED #define CW1200_DEBUG_H_INCLUDED
#include "itp.h"
struct cw1200_debug_priv { struct cw1200_debug_priv {
struct dentry *debugfs_phy; struct dentry *debugfs_phy;
int tx; int tx;
...@@ -30,9 +28,6 @@ struct cw1200_debug_priv { ...@@ -30,9 +28,6 @@ struct cw1200_debug_priv {
int ba_acc; int ba_acc;
int ba_cnt_rx; int ba_cnt_rx;
int ba_acc_rx; int ba_acc_rx;
#ifdef CONFIG_CW1200_ITP
struct cw1200_itp itp;
#endif /* CONFIG_CW1200_ITP */
}; };
int cw1200_debug_init(struct cw1200_common *priv); int cw1200_debug_init(struct cw1200_common *priv);
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "cw1200.h" #include "cw1200.h"
#include "fwio.h" #include "fwio.h"
#include "hwio.h" #include "hwio.h"
#include "sbus.h" #include "hwbus.h"
#include "bh.h" #include "bh.h"
static int cw1200_get_hw_type(u32 config_reg_val, int *major_revision) static int cw1200_get_hw_type(u32 config_reg_val, int *major_revision)
...@@ -139,11 +139,6 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) ...@@ -139,11 +139,6 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT; val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT;
REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); REG_WRITE(ST90TDS_CONFIG_REG_ID, val32);
#ifdef CONFIG_CW1200_ETF
if (etf_mode)
fw_path = etf_firmware;
#endif
/* Load a firmware file */ /* Load a firmware file */
ret = request_firmware(&firmware, fw_path, priv->pdev); ret = request_firmware(&firmware, fw_path, priv->pdev);
if (ret) { if (ret) {
...@@ -489,9 +484,9 @@ int cw1200_load_firmware(struct cw1200_common *priv) ...@@ -489,9 +484,9 @@ int cw1200_load_firmware(struct cw1200_common *priv)
} }
/* Enable interrupt signalling */ /* Enable interrupt signalling */
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
ret = __cw1200_irq_enable(priv, 1); ret = __cw1200_irq_enable(priv, 1);
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
if (ret < 0) if (ret < 0)
goto unsubscribe; goto unsubscribe;
...@@ -518,8 +513,8 @@ int cw1200_load_firmware(struct cw1200_common *priv) ...@@ -518,8 +513,8 @@ int cw1200_load_firmware(struct cw1200_common *priv)
unsubscribe: unsubscribe:
/* Disable interrupt signalling */ /* Disable interrupt signalling */
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
ret = __cw1200_irq_enable(priv, 0); ret = __cw1200_irq_enable(priv, 0);
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
/* /*
* Common sbus abstraction layer interface for cw1200 wireless driver * Common hwbus abstraction layer interface for cw1200 wireless driver
* *
* Copyright (c) 2010, ST-Ericsson * Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
...@@ -9,29 +9,25 @@ ...@@ -9,29 +9,25 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifndef CW1200_SBUS_H #ifndef CW1200_HWBUS_H
#define CW1200_SBUS_H #define CW1200_HWBUS_H
/* struct hwbus_priv;
* sbus priv forward definition.
* Implemented and instantiated in particular modules.
*/
struct sbus_priv;
void cw1200_irq_handler(struct cw1200_common *priv); void cw1200_irq_handler(struct cw1200_common *priv);
/* This MUST be wrapped with sbus_ops->lock/unlock! */ /* This MUST be wrapped with hwbus_ops->lock/unlock! */
int __cw1200_irq_enable(struct cw1200_common *priv, int enable); int __cw1200_irq_enable(struct cw1200_common *priv, int enable);
struct sbus_ops { struct hwbus_ops {
int (*sbus_memcpy_fromio)(struct sbus_priv *self, unsigned int addr, int (*hwbus_memcpy_fromio)(struct hwbus_priv *self, unsigned int addr,
void *dst, int count); void *dst, int count);
int (*sbus_memcpy_toio)(struct sbus_priv *self, unsigned int addr, int (*hwbus_memcpy_toio)(struct hwbus_priv *self, unsigned int addr,
const void *src, int count); const void *src, int count);
void (*lock)(struct sbus_priv *self); void (*lock)(struct hwbus_priv *self);
void (*unlock)(struct sbus_priv *self); void (*unlock)(struct hwbus_priv *self);
size_t (*align_size)(struct sbus_priv *self, size_t size); size_t (*align_size)(struct hwbus_priv *self, size_t size);
int (*power_mgmt)(struct sbus_priv *self, bool suspend); int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
}; };
#endif /* CW1200_SBUS_H */ #endif /* CW1200_HWBUS_H */
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "cw1200.h" #include "cw1200.h"
#include "hwio.h" #include "hwio.h"
#include "sbus.h" #include "hwbus.h"
/* Sdio addr is 4*spi_addr */ /* Sdio addr is 4*spi_addr */
#define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2) #define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2)
...@@ -46,7 +46,7 @@ static int __cw1200_reg_read(struct cw1200_common *priv, u16 addr, ...@@ -46,7 +46,7 @@ static int __cw1200_reg_read(struct cw1200_common *priv, u16 addr,
addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); addr_sdio = SPI_REG_ADDR_TO_SDIO(addr);
sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio);
return priv->sbus_ops->sbus_memcpy_fromio(priv->sbus_priv, return priv->hwbus_ops->hwbus_memcpy_fromio(priv->hwbus_priv,
sdio_reg_addr_17bit, sdio_reg_addr_17bit,
buf, buf_len); buf, buf_len);
} }
...@@ -61,7 +61,7 @@ static int __cw1200_reg_write(struct cw1200_common *priv, u16 addr, ...@@ -61,7 +61,7 @@ static int __cw1200_reg_write(struct cw1200_common *priv, u16 addr,
addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); addr_sdio = SPI_REG_ADDR_TO_SDIO(addr);
sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio);
return priv->sbus_ops->sbus_memcpy_toio(priv->sbus_priv, return priv->hwbus_ops->hwbus_memcpy_toio(priv->hwbus_priv,
sdio_reg_addr_17bit, sdio_reg_addr_17bit,
buf, buf_len); buf, buf_len);
} }
...@@ -100,9 +100,9 @@ int cw1200_reg_read(struct cw1200_common *priv, u16 addr, void *buf, ...@@ -100,9 +100,9 @@ int cw1200_reg_read(struct cw1200_common *priv, u16 addr, void *buf,
size_t buf_len) size_t buf_len)
{ {
int ret; int ret;
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
ret = __cw1200_reg_read(priv, addr, buf, buf_len, 0); ret = __cw1200_reg_read(priv, addr, buf, buf_len, 0);
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
...@@ -110,9 +110,9 @@ int cw1200_reg_write(struct cw1200_common *priv, u16 addr, const void *buf, ...@@ -110,9 +110,9 @@ int cw1200_reg_write(struct cw1200_common *priv, u16 addr, const void *buf,
size_t buf_len) size_t buf_len)
{ {
int ret; int ret;
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
ret = __cw1200_reg_write(priv, addr, buf, buf_len, 0); ret = __cw1200_reg_write(priv, addr, buf, buf_len, 0);
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
...@@ -121,7 +121,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len) ...@@ -121,7 +121,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len)
int ret, retry = 1; int ret, retry = 1;
int buf_id_rx = priv->buf_id_rx; int buf_id_rx = priv->buf_id_rx;
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
while (retry <= MAX_RETRY) { while (retry <= MAX_RETRY) {
ret = __cw1200_reg_read(priv, ret = __cw1200_reg_read(priv,
...@@ -138,7 +138,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len) ...@@ -138,7 +138,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len)
} }
} }
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
...@@ -148,7 +148,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf, ...@@ -148,7 +148,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf,
int ret, retry = 1; int ret, retry = 1;
int buf_id_tx = priv->buf_id_tx; int buf_id_tx = priv->buf_id_tx;
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
while (retry <= MAX_RETRY) { while (retry <= MAX_RETRY) {
ret = __cw1200_reg_write(priv, ret = __cw1200_reg_write(priv,
...@@ -165,7 +165,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf, ...@@ -165,7 +165,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf,
} }
} }
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
...@@ -178,10 +178,9 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, ...@@ -178,10 +178,9 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf,
if ((buf_len / 2) >= 0x1000) { if ((buf_len / 2) >= 0x1000) {
pr_err("Can't read more than 0xfff words.\n"); pr_err("Can't read more than 0xfff words.\n");
return -EINVAL; return -EINVAL;
goto out;
} }
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
/* Write address */ /* Write address */
ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr);
if (ret < 0) { if (ret < 0) {
...@@ -230,7 +229,7 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, ...@@ -230,7 +229,7 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf,
} }
out: out:
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
...@@ -244,7 +243,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, ...@@ -244,7 +243,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf,
return -EINVAL; return -EINVAL;
} }
priv->sbus_ops->lock(priv->sbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
/* Write address */ /* Write address */
ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr);
...@@ -262,7 +261,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, ...@@ -262,7 +261,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf,
} }
out: out:
priv->sbus_ops->unlock(priv->sbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
return ret; return ret;
} }
......
...@@ -97,9 +97,8 @@ struct download_cntl_t { ...@@ -97,9 +97,8 @@ struct download_cntl_t {
#define CW1200_APB(addr) (PAC_SHARED_MEMORY_SILICON + (addr)) #define CW1200_APB(addr) (PAC_SHARED_MEMORY_SILICON + (addr))
/* *************************************************************** /* Device register definitions */
*Device register definitions
*************************************************************** */
/* WBF - SPI Register Addresses */ /* WBF - SPI Register Addresses */
#define ST90TDS_ADDR_ID_BASE (0x0000) #define ST90TDS_ADDR_ID_BASE (0x0000)
/* 16/32 bits */ /* 16/32 bits */
......
/*
* mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
* ITP code
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* 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.
*/
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/poll.h>
#include <linux/time.h>
#include <linux/random.h>
#include <linux/kallsyms.h>
#include <net/mac80211.h>
#include "cw1200.h"
#include "debug.h"
#include "itp.h"
#include "sta.h"
static int __cw1200_itp_open(struct cw1200_common *priv);
static int __cw1200_itp_close(struct cw1200_common *priv);
static void cw1200_itp_rx_start(struct cw1200_common *priv);
static void cw1200_itp_rx_stop(struct cw1200_common *priv);
static void cw1200_itp_rx_stats(struct cw1200_common *priv);
static void cw1200_itp_rx_reset(struct cw1200_common *priv);
static void cw1200_itp_tx_stop(struct cw1200_common *priv);
static void cw1200_itp_handle(struct cw1200_common *priv,
struct sk_buff *skb);
static void cw1200_itp_err(struct cw1200_common *priv,
int err,
int arg);
static void __cw1200_itp_tx_stop(struct cw1200_common *priv);
static ssize_t cw1200_itp_read(struct file *file,
char __user *user_buf, size_t count, loff_t *ppos)
{
struct cw1200_common *priv = file->private_data;
struct cw1200_itp *itp = &priv->debug->itp;
struct sk_buff *skb;
int ret;
if (skb_queue_empty(&itp->log_queue))
return 0;
skb = skb_dequeue(&itp->log_queue);
ret = copy_to_user(user_buf, skb->data, skb->len);
*ppos += skb->len;
skb->data[skb->len] = 0;
pr_debug("[ITP] >>> %s", skb->data);
consume_skb(skb);
return skb->len - ret;
}
static ssize_t cw1200_itp_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct cw1200_common *priv = file->private_data;
struct sk_buff *skb;
if (!count || count > 1024)
return -EINVAL;
skb = dev_alloc_skb(count + 1);
if (!skb)
return -ENOMEM;
skb_trim(skb, 0);
skb_put(skb, count + 1);
if (copy_from_user(skb->data, user_buf, count)) {
kfree_skb(skb);
return -EFAULT;
}
skb->data[count] = 0;
cw1200_itp_handle(priv, skb);
consume_skb(skb);
return count;
}
static unsigned int cw1200_itp_poll(struct file *file, poll_table *wait)
{
struct cw1200_common *priv = file->private_data;
struct cw1200_itp *itp = &priv->debug->itp;
unsigned int mask = 0;
poll_wait(file, &itp->read_wait, wait);
if (!skb_queue_empty(&itp->log_queue))
mask |= POLLIN | POLLRDNORM;
mask |= POLLOUT | POLLWRNORM;
return mask;
}
static int cw1200_itp_open(struct inode *inode, struct file *file)
{
struct cw1200_common *priv = inode->i_private;
struct cw1200_itp *itp = &priv->debug->itp;
int ret = 0;
file->private_data = priv;
if (atomic_inc_return(&itp->open_count) == 1) {
ret = __cw1200_itp_open(priv);
if (ret && !atomic_dec_return(&itp->open_count))
__cw1200_itp_close(priv);
} else {
atomic_dec(&itp->open_count);
ret = -EBUSY;
}
return ret;
}
static int cw1200_itp_close(struct inode *inode, struct file *file)
{
struct cw1200_common *priv = file->private_data;
struct cw1200_itp *itp = &priv->debug->itp;
if (!atomic_dec_return(&itp->open_count)) {
__cw1200_itp_close(priv);
wake_up(&itp->close_wait);
}
return 0;
}
static const struct file_operations fops_itp = {
.open = cw1200_itp_open,
.read = cw1200_itp_read,
.write = cw1200_itp_write,
.poll = cw1200_itp_poll,
.release = cw1200_itp_close,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static void cw1200_itp_fill_pattern(u8 *data, int size,
enum cw1200_itp_data_modes mode)
{
if (size <= 0)
return;
switch (mode) {
default:
case ITP_DATA_ZEROS:
memset(data, 0x0, size);
break;
case ITP_DATA_ONES:
memset(data, 0xff, size);
break;
case ITP_DATA_ZERONES:
memset(data, 0x55, size);
break;
case ITP_DATA_RANDOM:
get_random_bytes(data, size);
break;
}
return;
}
static void cw1200_itp_tx_work(struct work_struct *work)
{
struct cw1200_itp *itp = container_of(work, struct cw1200_itp,
tx_work.work);
struct cw1200_common *priv = itp->priv;
atomic_set(&priv->bh_tx, 1);
wake_up(&priv->bh_wq);
}
static void cw1200_itp_tx_finish(struct work_struct *work)
{
struct cw1200_itp *itp = container_of(work, struct cw1200_itp,
tx_finish.work);
__cw1200_itp_tx_stop(itp->priv);
}
int cw1200_itp_init(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
itp->priv = priv;
atomic_set(&itp->open_count, 0);
atomic_set(&itp->stop_tx, 0);
atomic_set(&itp->awaiting_confirm, 0);
skb_queue_head_init(&itp->log_queue);
spin_lock_init(&itp->tx_lock);
init_waitqueue_head(&itp->read_wait);
init_waitqueue_head(&itp->write_wait);
init_waitqueue_head(&itp->close_wait);
INIT_DELAYED_WORK(&itp->tx_work, cw1200_itp_tx_work);
INIT_DELAYED_WORK(&itp->tx_finish, cw1200_itp_tx_finish);
itp->data = NULL;
itp->hdr_len = WSM_TX_EXTRA_HEADROOM +
sizeof(struct ieee80211_hdr_3addr);
if (!debugfs_create_file("itp", S_IRUSR | S_IWUSR,
priv->debug->debugfs_phy, priv, &fops_itp))
return -ENOMEM;
return 0;
}
void cw1200_itp_release(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
wait_event_interruptible(itp->close_wait,
!atomic_read(&itp->open_count));
WARN_ON(atomic_read(&itp->open_count));
skb_queue_purge(&itp->log_queue);
cw1200_itp_tx_stop(priv);
}
static int __cw1200_itp_open(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
if (!priv->vif)
return -EINVAL;
if (priv->join_status)
return -EINVAL;
itp->saved_channel = priv->channel;
if (!priv->channel)
priv->channel = &priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
wsm_set_bssid_filtering(priv, false);
cw1200_itp_rx_reset(priv);
return 0;
}
static int __cw1200_itp_close(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
if (atomic_read(&itp->test_mode) == TEST_MODE_RX_TEST)
cw1200_itp_rx_stop(priv);
cw1200_itp_tx_stop(priv);
cw1200_disable_listening(priv);
cw1200_update_filtering(priv);
priv->channel = itp->saved_channel;
return 0;
}
bool cw1200_is_itp(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
return atomic_read(&itp->open_count) != 0;
}
static void cw1200_itp_rx_reset(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
itp->rx_cnt = 0;
itp->rx_rssi = 0;
itp->rx_rssi_max = -1000;
itp->rx_rssi_min = 1000;
}
static void cw1200_itp_rx_start(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
pr_debug("[ITP] RX start, band = %d, ch = %d\n",
itp->band, itp->ch);
atomic_set(&itp->test_mode, TEST_MODE_RX_TEST);
cw1200_update_listening(priv, false);
priv->channel = &priv->hw->
wiphy->bands[itp->band]->channels[itp->ch];
cw1200_update_listening(priv, true);
wsm_set_bssid_filtering(priv, false);
}
static void cw1200_itp_rx_stop(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
pr_debug("[ITP] RX stop\n");
atomic_set(&itp->test_mode, TEST_MODE_NO_TEST);
cw1200_itp_rx_reset(priv);
}
static void cw1200_itp_rx_stats(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
struct sk_buff *skb;
char buf[128];
int len, ret;
struct wsm_mib_counters_table counters;
ret = wsm_get_counters_table(priv, &counters);
if (ret)
cw1200_itp_err(priv, -EBUSY, 20);
if (!itp->rx_cnt)
len = snprintf(buf, sizeof(buf), "1,0,0,0,0,%d\n",
counters.rx_packet_errors);
else
len = snprintf(buf, sizeof(buf), "1,%d,%ld,%d,%d,%d\n",
itp->rx_cnt,
itp->rx_cnt ? itp->rx_rssi / itp->rx_cnt : 0,
itp->rx_rssi_min, itp->rx_rssi_max,
counters.rx_packet_errors);
if (len <= 0) {
cw1200_itp_err(priv, -EBUSY, 21);
return;
}
skb = dev_alloc_skb(len);
if (!skb) {
cw1200_itp_err(priv, -ENOMEM, 22);
return;
}
itp->rx_cnt = 0;
itp->rx_rssi = 0;
itp->rx_rssi_max = -1000;
itp->rx_rssi_min = 1000;
skb_trim(skb, 0);
skb_put(skb, len);
memcpy(skb->data, buf, len);
skb_queue_tail(&itp->log_queue, skb);
wake_up(&itp->read_wait);
}
static void cw1200_itp_tx_start(struct cw1200_common *priv)
{
struct wsm_tx *tx;
struct ieee80211_hdr_3addr *hdr;
struct cw1200_itp *itp = &priv->debug->itp;
struct wsm_mib_association_mode assoc_mode = {
.flags = WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE,
.preamble = itp->preamble,
};
int len;
u8 da_addr[6] = ITP_DEFAULT_DA_ADDR;
/* Rates index 4 and 5 are not supported */
if (itp->rate > 3)
itp->rate += 2;
pr_debug("[ITP] TX start: band = %d, ch = %d, rate = %d, preamble = %d, number = %d, data_mode = %d, interval = %d, power = %d, data_len = %d\n",
itp->band, itp->ch, itp->rate, itp->preamble,
itp->number, itp->data_mode, itp->interval_us,
itp->power, itp->data_len);
len = itp->hdr_len + itp->data_len;
itp->data = kmalloc(len, GFP_KERNEL);
tx = (struct wsm_tx *)itp->data;
tx->hdr.len = itp->data_len + itp->hdr_len;
tx->hdr.id = __cpu_to_le16(0x0004 | 1 << 6);
tx->max_tx_rate = itp->rate;
tx->queue_id = 3;
tx->more = 0;
tx->flags = 0xc;
tx->packet_id = 0x55ff55;
tx->reserved = 0;
tx->expire_time = 1;
if (itp->preamble == ITP_PREAMBLE_GREENFIELD)
tx->ht_tx_parameters = WSM_HT_TX_GREENFIELD;
else if (itp->preamble == ITP_PREAMBLE_MIXED)
tx->ht_tx_parameters = WSM_HT_TX_MIXED;
hdr = (struct ieee80211_hdr_3addr *)&itp->data[sizeof(struct wsm_tx)];
memset(hdr, 0, sizeof(*hdr));
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS);
memcpy(hdr->addr1, da_addr, ETH_ALEN);
memcpy(hdr->addr2, priv->vif->addr, ETH_ALEN);
memcpy(hdr->addr3, da_addr, ETH_ALEN);
cw1200_itp_fill_pattern(&itp->data[itp->hdr_len],
itp->data_len, itp->data_mode);
cw1200_update_listening(priv, false);
priv->channel = &priv->hw->wiphy->bands[itp->band]->channels[itp->ch];
WARN_ON(wsm_set_output_power(priv, itp->power));
if (itp->preamble == ITP_PREAMBLE_SHORT ||
itp->preamble == ITP_PREAMBLE_LONG)
WARN_ON(wsm_set_association_mode(priv,
&assoc_mode));
wsm_set_bssid_filtering(priv, false);
cw1200_update_listening(priv, true);
spin_lock_bh(&itp->tx_lock);
atomic_set(&itp->test_mode, TEST_MODE_TX_TEST);
atomic_set(&itp->awaiting_confirm, 0);
atomic_set(&itp->stop_tx, 0);
atomic_set(&priv->bh_tx, 1);
ktime_get_ts(&itp->last_sent);
wake_up(&priv->bh_wq);
spin_unlock_bh(&itp->tx_lock);
}
void __cw1200_itp_tx_stop(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
spin_lock_bh(&itp->tx_lock);
kfree(itp->data);
itp->data = NULL;
atomic_set(&itp->test_mode, TEST_MODE_NO_TEST);
spin_unlock_bh(&itp->tx_lock);
}
static void cw1200_itp_tx_stop(struct cw1200_common *priv)
{
struct cw1200_itp *itp = &priv->debug->itp;
pr_debug("[ITP] TX stop\n");
atomic_set(&itp->stop_tx, 1);
flush_workqueue(priv->workqueue);
/* time for FW to confirm all tx requests */
msleep(500);
__cw1200_itp_tx_stop(priv);
}
static int cw1200_print_fw_version(struct cw1200_common *priv,
u8 *buf, size_t len)
{
return snprintf(buf, len, "%s %d.%d",
cw1200_fw_types[priv->wsm_caps.fw_type],
priv->wsm_caps.fw_ver,
priv->wsm_caps.fw_build);
}
static void cw1200_itp_get_version(struct cw1200_common *priv,
enum cw1200_itp_version_type type)
{
struct cw1200_itp *itp = &priv->debug->itp;
struct sk_buff *skb;
char buf[ITP_BUF_SIZE];
size_t size = 0;
int len;
pr_debug("[ITP] print %s version\n",
type == ITP_CHIP_ID ? "chip" : "firmware");
len = snprintf(buf, ITP_BUF_SIZE, "2,");
if (len <= 0) {
cw1200_itp_err(priv, -EINVAL, 40);
return;
}
size += len;
switch (type) {
case ITP_CHIP_ID:
len = cw1200_print_fw_version(priv, buf+size,
ITP_BUF_SIZE - size);
if (len <= 0) {
cw1200_itp_err(priv, -EINVAL, 41);
return;
}
size += len;
break;
case ITP_FW_VER:
len = snprintf(buf+size, ITP_BUF_SIZE - size,
"%d.%d", priv->wsm_caps.hw_id,
priv->wsm_caps.hw_subid);
if (len <= 0) {
cw1200_itp_err(priv, -EINVAL, 42);
return;
}
size += len;
break;
default:
cw1200_itp_err(priv, -EINVAL, 43);
break;
}
len = snprintf(buf+size, ITP_BUF_SIZE-size, "\n");
if (len <= 0) {
cw1200_itp_err(priv, -EINVAL, 44);
return;
}
size += len;
skb = dev_alloc_skb(size);
if (!skb) {
cw1200_itp_err(priv, -ENOMEM, 45);
return;
}
skb_trim(skb, 0);
skb_put(skb, size);
memcpy(skb->data, buf, size);
skb_queue_tail(&itp->log_queue, skb);
wake_up(&itp->read_wait);
}
int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data,
size_t *tx_len, int *burst)
{
struct cw1200_itp *itp;
struct timespec now;
int time_left_us;
if (!priv->debug)
return 0;
itp = &priv->debug->itp;
if (!itp)
return 0;
spin_lock_bh(&itp->tx_lock);
if (atomic_read(&itp->test_mode) != TEST_MODE_TX_TEST)
goto out;
if (atomic_read(&itp->stop_tx))
goto out;
if (itp->number == 0) {
atomic_set(&itp->stop_tx, 1);
queue_delayed_work(priv->workqueue, &itp->tx_finish, HZ/10);
goto out;
}
if (!itp->data)
goto out;
if (priv->hw_bufs_used >= 2) {
if (!atomic_read(&priv->bh_rx))
atomic_set(&priv->bh_rx, 1);
atomic_set(&priv->bh_tx, 1);
goto out;
}
ktime_get_ts(&now);
time_left_us = (itp->last_sent.tv_sec - now.tv_sec)*1000000 +
(itp->last_sent.tv_nsec - now.tv_nsec)/1000 +
itp->interval_us;
if (time_left_us > ITP_TIME_THRES_US) {
queue_delayed_work(priv->workqueue, &itp->tx_work,
ITP_US_TO_MS(time_left_us)*HZ/1000);
goto out;
}
if (time_left_us > 50)
udelay(time_left_us);
if (itp->number > 0)
itp->number--;
*data = itp->data;
*tx_len = itp->data_len + itp->hdr_len;
if (itp->data_mode == ITP_DATA_RANDOM)
cw1200_itp_fill_pattern(&itp->data[itp->hdr_len],
itp->data_len, itp->data_mode);
*burst = 2;
atomic_set(&priv->bh_tx, 1);
ktime_get_ts(&itp->last_sent);
atomic_add(1, &itp->awaiting_confirm);
spin_unlock_bh(&itp->tx_lock);
return 1;
out:
spin_unlock_bh(&itp->tx_lock);
return 0;
}
bool cw1200_itp_rxed(struct cw1200_common *priv, struct sk_buff *skb)
{
struct cw1200_itp *itp = &priv->debug->itp;
struct ieee80211_rx_status *rx = IEEE80211_SKB_RXCB(skb);
int signal;
if (atomic_read(&itp->test_mode) != TEST_MODE_RX_TEST)
return cw1200_is_itp(priv);
if (rx->freq != priv->channel->center_freq)
return true;
signal = rx->signal;
itp->rx_cnt++;
itp->rx_rssi += signal;
if (itp->rx_rssi_min > rx->signal)
itp->rx_rssi_min = rx->signal;
if (itp->rx_rssi_max < rx->signal)
itp->rx_rssi_max = rx->signal;
return true;
}
void cw1200_itp_wake_up_tx(struct cw1200_common *priv)
{
wake_up(&priv->debug->itp.write_wait);
}
bool cw1200_itp_tx_running(struct cw1200_common *priv)
{
if (atomic_read(&priv->debug->itp.awaiting_confirm) ||
atomic_read(&priv->debug->itp.test_mode) ==
TEST_MODE_TX_TEST) {
atomic_sub(1, &priv->debug->itp.awaiting_confirm);
return true;
}
return false;
}
static void cw1200_itp_handle(struct cw1200_common *priv,
struct sk_buff *skb)
{
struct cw1200_itp *itp = &priv->debug->itp;
const struct wiphy *wiphy = priv->hw->wiphy;
int cmd;
int ret;
pr_debug("[ITP] <<< %s", skb->data);
if (sscanf(skb->data, "%d", &cmd) != 1) {
cw1200_itp_err(priv, -EINVAL, 1);
return;
}
switch (cmd) {
case 1: /* RX test */
if (atomic_read(&itp->test_mode)) {
cw1200_itp_err(priv, -EBUSY, 0);
return;
}
ret = sscanf(skb->data, "%d,%d,%d",
&cmd, &itp->band, &itp->ch);
if (ret != 3) {
cw1200_itp_err(priv, -EINVAL, ret + 1);
return;
}
if (itp->band >= 2) {
cw1200_itp_err(priv, -EINVAL, 2);
} else if (!wiphy->bands[itp->band]) {
cw1200_itp_err(priv, -EINVAL, 2);
} else if (itp->ch >= wiphy->bands[itp->band]->n_channels) {
cw1200_itp_err(priv, -EINVAL, 3);
} else {
cw1200_itp_rx_stats(priv);
cw1200_itp_rx_start(priv);
}
break;
case 2: /* RX stat */
cw1200_itp_rx_stats(priv);
break;
case 3: /* RX/TX stop */
if (atomic_read(&itp->test_mode) == TEST_MODE_RX_TEST) {
cw1200_itp_rx_stats(priv);
cw1200_itp_rx_stop(priv);
} else if (atomic_read(&itp->test_mode) == TEST_MODE_TX_TEST) {
cw1200_itp_tx_stop(priv);
} else {
cw1200_itp_err(priv, -EBUSY, 0);
}
break;
case 4: /* TX start */
if (atomic_read(&itp->test_mode) != TEST_MODE_NO_TEST) {
cw1200_itp_err(priv, -EBUSY, 0);
return;
}
ret = sscanf(skb->data, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
&cmd, &itp->band, &itp->ch, &itp->rate,
&itp->preamble, &itp->number, &itp->data_mode,
&itp->interval_us, &itp->power, &itp->data_len);
if (ret != 10) {
cw1200_itp_err(priv, -EINVAL, ret + 1);
return;
}
if (itp->band >= 2) {
cw1200_itp_err(priv, -EINVAL, 2);
} else if (!wiphy->bands[itp->band]) {
cw1200_itp_err(priv, -EINVAL, 2);
} else if (itp->ch >= wiphy->bands[itp->band]->n_channels) {
cw1200_itp_err(priv, -EINVAL, 3);
} else if (itp->rate >= 20) {
cw1200_itp_err(priv, -EINVAL, 4);
} else if (itp->preamble >= ITP_PREAMBLE_MAX) {
cw1200_itp_err(priv, -EINVAL, 5);
} else if (itp->data_mode >= ITP_DATA_MAX_MODE) {
cw1200_itp_err(priv, -EINVAL, 7);
} else if (itp->data_len < ITP_MIN_DATA_SIZE ||
itp->data_len > (priv->wsm_caps.input_buffer_size - itp->hdr_len)) {
cw1200_itp_err(priv, -EINVAL, 8);
} else {
cw1200_itp_tx_start(priv);
}
break;
case 5:
cw1200_itp_get_version(priv, ITP_CHIP_ID);
break;
case 6:
cw1200_itp_get_version(priv, ITP_FW_VER);
break;
}
}
static void cw1200_itp_err(struct cw1200_common *priv,
int err, int arg)
{
struct cw1200_itp *itp = &priv->debug->itp;
struct sk_buff *skb;
static char buf[255];
int len;
len = snprintf(buf, sizeof(buf), "%d,%d\n",
err, arg);
if (len <= 0)
return;
skb = dev_alloc_skb(len);
if (!skb)
return;
skb_trim(skb, 0);
skb_put(skb, len);
memcpy(skb->data, buf, len);
skb_queue_tail(&itp->log_queue, skb);
wake_up(&itp->read_wait);
len = sprint_symbol(buf,
(unsigned long)__builtin_return_address(0));
if (len <= 0)
return;
pr_debug("[ITP] error %d,%d from %s\n",
err, arg, buf);
}
/*
* ITP code for ST-Ericsson CW1200 mac80211 driver
*
* Copyright (c) 2011, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* 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.
*/
#ifndef CW1200_ITP_H_INCLUDED
#define CW1200_ITP_H_INCLUDED
struct cw200_common;
struct wsm_tx_confirm;
struct dentry;
#ifdef CONFIG_CW1200_ITP
/*extern*/ struct ieee80211_channel;
#define TEST_MODE_NO_TEST (0)
#define TEST_MODE_RX_TEST (1)
#define TEST_MODE_TX_TEST (2)
#define ITP_DEFAULT_DA_ADDR {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
#define ITP_MIN_DATA_SIZE 6
#define ITP_MAX_DATA_SIZE 1600
#define ITP_TIME_THRES_US 10000
#define ITP_US_TO_MS(x) ((x)/1000)
#define ITP_MS_TO_US(x) ((x)*1000)
#define ITP_BUF_SIZE 255
enum cw1200_itp_data_modes {
ITP_DATA_ZEROS,
ITP_DATA_ONES,
ITP_DATA_ZERONES,
ITP_DATA_RANDOM,
ITP_DATA_MAX_MODE,
};
enum cw1200_itp_version_type {
ITP_CHIP_ID,
ITP_FW_VER,
};
enum cw1200_itp_preamble_type {
ITP_PREAMBLE_LONG,
ITP_PREAMBLE_SHORT,
ITP_PREAMBLE_OFDM,
ITP_PREAMBLE_MIXED,
ITP_PREAMBLE_GREENFIELD,
ITP_PREAMBLE_MAX,
};
struct cw1200_itp {
struct cw1200_common *priv;
atomic_t open_count;
atomic_t awaiting_confirm;
struct sk_buff_head log_queue;
wait_queue_head_t read_wait;
wait_queue_head_t write_wait;
wait_queue_head_t close_wait;
struct ieee80211_channel *saved_channel;
atomic_t stop_tx;
struct delayed_work tx_work;
struct delayed_work tx_finish;
spinlock_t tx_lock;
struct timespec last_sent;
atomic_t test_mode;
int rx_cnt;
long rx_rssi;
int rx_rssi_max;
int rx_rssi_min;
unsigned band;
unsigned ch;
unsigned rate;
unsigned preamble;
unsigned int number;
unsigned data_mode;
int interval_us;
int power;
u8 *data;
int hdr_len;
int data_len;
};
int cw1200_itp_init(struct cw1200_common *priv);
void cw1200_itp_release(struct cw1200_common *priv);
bool cw1200_is_itp(struct cw1200_common *priv);
bool cw1200_itp_rxed(struct cw1200_common *priv, struct sk_buff *skb);
void cw1200_itp_wake_up_tx(struct cw1200_common *priv);
int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data,
size_t *tx_len, int *burst);
bool cw1200_itp_tx_running(struct cw1200_common *priv);
#else /* CONFIG_CW1200_ITP */
static inline int cw1200_itp_init(struct cw1200_common *priv)
{
return 0;
}
static inline void cw1200_itp_release(struct cw1200_common *priv)
{
}
static inline bool cw1200_is_itp(struct cw1200_common *priv)
{
return false;
}
static inline bool cw1200_itp_rxed(struct cw1200_common *priv,
struct sk_buff *skb)
{
return false;
}
static inline void cw1200_itp_consume_txed(struct cw1200_common *priv)
{
}
static inline void cw1200_itp_wake_up_tx(struct cw1200_common *priv)
{
}
static inline int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data,
size_t *tx_len, int *burst)
{
return 0;
}
static inline bool cw1200_itp_tx_running(struct cw1200_common *priv)
{
return false;
}
#endif /* CONFIG_CW1200_ITP */
#endif /* CW1200_ITP_H_INCLUDED */
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include "cw1200.h" #include "cw1200.h"
#include "txrx.h" #include "txrx.h"
#include "sbus.h" #include "hwbus.h"
#include "fwio.h" #include "fwio.h"
#include "hwio.h" #include "hwio.h"
#include "bh.h" #include "bh.h"
...@@ -61,12 +61,6 @@ int cw1200_power_mode = wsm_power_mode_quiescent; ...@@ -61,12 +61,6 @@ int cw1200_power_mode = wsm_power_mode_quiescent;
module_param(cw1200_power_mode, int, 0644); module_param(cw1200_power_mode, int, 0644);
MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode. 0 == active, 1 == doze, 2 == quiescent (default)"); MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode. 0 == active, 1 == doze, 2 == quiescent (default)");
#ifdef CONFIG_CW1200_ETF
int etf_mode;
module_param(etf_mode, int, 0644);
MODULE_PARM_DESC(etf_mode, "Enable EngineeringTestingFramework operation");
#endif
#define RATETAB_ENT(_rate, _rateid, _flags) \ #define RATETAB_ENT(_rate, _rateid, _flags) \
{ \ { \
.bitrate = (_rate), \ .bitrate = (_rate), \
...@@ -234,8 +228,10 @@ static const struct ieee80211_ops cw1200_ops = { ...@@ -234,8 +228,10 @@ static const struct ieee80211_ops cw1200_ops = {
.get_stats = cw1200_get_stats, .get_stats = cw1200_get_stats,
.ampdu_action = cw1200_ampdu_action, .ampdu_action = cw1200_ampdu_action,
.flush = cw1200_flush, .flush = cw1200_flush,
#ifdef CONFIG_PM
.suspend = cw1200_wow_suspend, .suspend = cw1200_wow_suspend,
.resume = cw1200_wow_resume, .resume = cw1200_wow_resume,
#endif
/* Intentionally not offloaded: */ /* Intentionally not offloaded: */
/*.channel_switch = cw1200_channel_switch, */ /*.channel_switch = cw1200_channel_switch, */
/*.remain_on_channel = cw1200_remain_on_channel, */ /*.remain_on_channel = cw1200_remain_on_channel, */
...@@ -292,10 +288,12 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, ...@@ -292,10 +288,12 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO); BIT(NL80211_IFTYPE_P2P_GO);
#ifdef CONFIG_PM
/* Support only for limited wowlan functionalities */ /* Support only for limited wowlan functionalities */
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
WIPHY_WOWLAN_DISCONNECT; WIPHY_WOWLAN_DISCONNECT;
hw->wiphy->wowlan.n_patterns = 0; hw->wiphy->wowlan.n_patterns = 0;
#endif
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
...@@ -414,29 +412,25 @@ static int cw1200_register_common(struct ieee80211_hw *dev) ...@@ -414,29 +412,25 @@ static int cw1200_register_common(struct ieee80211_hw *dev)
struct cw1200_common *priv = dev->priv; struct cw1200_common *priv = dev->priv;
int err; int err;
#ifdef CONFIG_CW1200_ETF #ifdef CONFIG_PM
if (etf_mode)
goto done;
#endif
err = cw1200_pm_init(&priv->pm_state, priv); err = cw1200_pm_init(&priv->pm_state, priv);
if (err) { if (err) {
pr_err("Cannot init PM. (%d).\n", pr_err("Cannot init PM. (%d).\n",
err); err);
return err; return err;
} }
#endif
err = ieee80211_register_hw(dev); err = ieee80211_register_hw(dev);
if (err) { if (err) {
pr_err("Cannot register device (%d).\n", pr_err("Cannot register device (%d).\n",
err); err);
#ifdef CONFIG_PM
cw1200_pm_deinit(&priv->pm_state); cw1200_pm_deinit(&priv->pm_state);
#endif
return err; return err;
} }
#ifdef CONFIG_CW1200_ETF
done:
#endif
cw1200_debug_init(priv); cw1200_debug_init(priv);
pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy)); pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
...@@ -453,13 +447,7 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev) ...@@ -453,13 +447,7 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev)
struct cw1200_common *priv = dev->priv; struct cw1200_common *priv = dev->priv;
int i; int i;
#ifdef CONFIG_CW1200_ETF ieee80211_unregister_hw(dev);
if (!etf_mode) {
#endif
ieee80211_unregister_hw(dev);
#ifdef CONFIG_CW1200_ETF
}
#endif
del_timer_sync(&priv->mcast_timeout); del_timer_sync(&priv->mcast_timeout);
cw1200_unregister_bh(priv); cw1200_unregister_bh(priv);
...@@ -482,7 +470,9 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev) ...@@ -482,7 +470,9 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev)
cw1200_queue_deinit(&priv->tx_queue[i]); cw1200_queue_deinit(&priv->tx_queue[i]);
cw1200_queue_stats_deinit(&priv->tx_queue_stats); cw1200_queue_stats_deinit(&priv->tx_queue_stats);
#ifdef CONFIG_PM
cw1200_pm_deinit(&priv->pm_state); cw1200_pm_deinit(&priv->pm_state);
#endif
} }
/* Clock is in KHz */ /* Clock is in KHz */
...@@ -518,8 +508,8 @@ u32 cw1200_dpll_from_clk(u16 clk_khz) ...@@ -518,8 +508,8 @@ u32 cw1200_dpll_from_clk(u16 clk_khz)
} }
} }
int cw1200_core_probe(const struct sbus_ops *sbus_ops, int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
struct sbus_priv *sbus, struct hwbus_priv *hwbus,
struct device *pdev, struct device *pdev,
struct cw1200_common **core, struct cw1200_common **core,
int ref_clk, const u8 *macaddr, int ref_clk, const u8 *macaddr,
...@@ -546,8 +536,8 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops, ...@@ -546,8 +536,8 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
if (cw1200_sdd_path) if (cw1200_sdd_path)
priv->sdd_path = cw1200_sdd_path; priv->sdd_path = cw1200_sdd_path;
priv->sbus_ops = sbus_ops; priv->hwbus_ops = hwbus_ops;
priv->sbus_priv = sbus; priv->hwbus_priv = hwbus;
priv->pdev = pdev; priv->pdev = pdev;
SET_IEEE80211_DEV(priv->hw, pdev); SET_IEEE80211_DEV(priv->hw, pdev);
...@@ -558,11 +548,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops, ...@@ -558,11 +548,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
if (err) if (err)
goto err1; goto err1;
#ifdef CONFIG_CW1200_ETF
if (etf_mode)
goto skip_fw;
#endif
err = cw1200_load_firmware(priv); err = cw1200_load_firmware(priv);
if (err) if (err)
goto err2; goto err2;
...@@ -584,9 +569,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops, ...@@ -584,9 +569,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
/* Enable multi-TX confirmation */ /* Enable multi-TX confirmation */
wsm_use_multi_tx_conf(priv, true); wsm_use_multi_tx_conf(priv, true);
#ifdef CONFIG_CW1200_ETF
skip_fw:
#endif
err = cw1200_register_common(dev); err = cw1200_register_common(dev);
if (err) if (err)
goto err2; goto err2;
...@@ -606,9 +588,9 @@ EXPORT_SYMBOL_GPL(cw1200_core_probe); ...@@ -606,9 +588,9 @@ EXPORT_SYMBOL_GPL(cw1200_core_probe);
void cw1200_core_release(struct cw1200_common *self) void cw1200_core_release(struct cw1200_common *self)
{ {
/* Disable device interrupts */ /* Disable device interrupts */
self->sbus_ops->lock(self->sbus_priv); self->hwbus_ops->lock(self->hwbus_priv);
__cw1200_irq_enable(self, 0); __cw1200_irq_enable(self, 0);
self->sbus_ops->unlock(self->sbus_priv); self->hwbus_ops->unlock(self->hwbus_priv);
/* And then clean up */ /* And then clean up */
cw1200_unregister_common(self->hw); cw1200_unregister_common(self->hw);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "pm.h" #include "pm.h"
#include "sta.h" #include "sta.h"
#include "bh.h" #include "bh.h"
#include "sbus.h" #include "hwbus.h"
#define CW1200_BEACON_SKIPPING_MULTIPLIER 3 #define CW1200_BEACON_SKIPPING_MULTIPLIER 3
...@@ -264,7 +264,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ...@@ -264,7 +264,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
pm_state->suspend_state = state; pm_state->suspend_state = state;
/* Enable IRQ wake */ /* Enable IRQ wake */
ret = priv->sbus_ops->power_mgmt(priv->sbus_priv, true); ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true);
if (ret) { if (ret) {
wiphy_err(priv->hw->wiphy, wiphy_err(priv->hw->wiphy,
"PM request failed: %d. WoW is disabled.\n", ret); "PM request failed: %d. WoW is disabled.\n", ret);
...@@ -313,7 +313,7 @@ int cw1200_wow_resume(struct ieee80211_hw *hw) ...@@ -313,7 +313,7 @@ int cw1200_wow_resume(struct ieee80211_hw *hw)
pm_state->suspend_state = NULL; pm_state->suspend_state = NULL;
/* Disable IRQ wake */ /* Disable IRQ wake */
priv->sbus_ops->power_mgmt(priv->sbus_priv, false); priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false);
/* Scan.lock must be released before BH is resumed other way /* Scan.lock must be released before BH is resumed other way
* in case when BSS_LOST command arrived the processing of the * in case when BSS_LOST command arrived the processing of the
......
...@@ -25,14 +25,19 @@ struct cw1200_pm_state { ...@@ -25,14 +25,19 @@ struct cw1200_pm_state {
spinlock_t lock; /* Protect access */ spinlock_t lock; /* Protect access */
}; };
#ifdef CONFIG_PM
int cw1200_pm_init(struct cw1200_pm_state *pm, int cw1200_pm_init(struct cw1200_pm_state *pm,
struct cw1200_common *priv); struct cw1200_common *priv);
void cw1200_pm_deinit(struct cw1200_pm_state *pm); void cw1200_pm_deinit(struct cw1200_pm_state *pm);
void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
unsigned long tmo);
int cw1200_wow_suspend(struct ieee80211_hw *hw, int cw1200_wow_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan); struct cfg80211_wowlan *wowlan);
int cw1200_wow_resume(struct ieee80211_hw *hw); int cw1200_wow_resume(struct ieee80211_hw *hw);
int cw1200_can_suspend(struct cw1200_common *priv); int cw1200_can_suspend(struct cw1200_common *priv);
void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
unsigned long tmo);
#else
static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
unsigned long tmo) {
}
#endif
#endif #endif
...@@ -483,15 +483,14 @@ void cw1200_update_filtering(struct cw1200_common *priv) ...@@ -483,15 +483,14 @@ void cw1200_update_filtering(struct cw1200_common *priv)
bf_tbl.num = __cpu_to_le32(3); bf_tbl.num = __cpu_to_le32(3);
} }
/* /* When acting as p2p client being connected to p2p GO, in order to
* When acting as p2p client being connected to p2p GO, in order to * receive frames from a different p2p device, turn off bssid filter.
* receive frames from a different p2p device, turn off bssid filter. *
* * WARNING: FW dependency!
* WARNING: FW dependency! * This can only be used with FW WSM371 and its successors.
* This can only be used with FW WSM371 and its successors. * In that FW version even with bssid filter turned off,
* In that FW version even with bssid filter turned off, * device will block most of the unwanted frames.
* device will block most of the unwanted frames. */
*/
if (is_p2p) if (is_p2p)
bssid_filtering = false; bssid_filtering = false;
...@@ -1015,17 +1014,17 @@ void cw1200_event_handler(struct work_struct *work) ...@@ -1015,17 +1014,17 @@ void cw1200_event_handler(struct work_struct *work)
/* RSSI: signed Q8.0, RCPI: unsigned Q7.1 /* RSSI: signed Q8.0, RCPI: unsigned Q7.1
* RSSI = RCPI / 2 - 110 * RSSI = RCPI / 2 - 110
*/ */
int rcpiRssi = (int)(event->evt.data & 0xFF); int rcpi_rssi = (int)(event->evt.data & 0xFF);
int cqm_evt; int cqm_evt;
if (priv->cqm_use_rssi) if (priv->cqm_use_rssi)
rcpiRssi = (s8)rcpiRssi; rcpi_rssi = (s8)rcpi_rssi;
else else
rcpiRssi = rcpiRssi / 2 - 110; rcpi_rssi = rcpi_rssi / 2 - 110;
cqm_evt = (rcpiRssi <= priv->cqm_rssi_thold) ? cqm_evt = (rcpi_rssi <= priv->cqm_rssi_thold) ?
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW :
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
pr_debug("[CQM] RSSI event: %d.\n", rcpiRssi); pr_debug("[CQM] RSSI event: %d.\n", rcpi_rssi);
ieee80211_cqm_rssi_notify(priv->vif, cqm_evt, ieee80211_cqm_rssi_notify(priv->vif, cqm_evt,
GFP_KERNEL); GFP_KERNEL);
break; break;
...@@ -1068,8 +1067,7 @@ void cw1200_bss_params_work(struct work_struct *work) ...@@ -1068,8 +1067,7 @@ void cw1200_bss_params_work(struct work_struct *work)
/* ******************************************************************** */ /* ******************************************************************** */
/* Internal API */ /* Internal API */
/* /* This function is called to Parse the SDD file
* This function is called to Parse the SDD file
* to extract listen_interval and PTA related information * to extract listen_interval and PTA related information
* sdd is a TLV: u8 id, u8 len, u8 data[] * sdd is a TLV: u8 id, u8 len, u8 data[]
*/ */
......
...@@ -75,9 +75,6 @@ static void tx_policy_build(const struct cw1200_common *priv, ...@@ -75,9 +75,6 @@ static void tx_policy_build(const struct cw1200_common *priv,
BUG_ON(rates[0].idx < 0); BUG_ON(rates[0].idx < 0);
memset(policy, 0, sizeof(*policy)); memset(policy, 0, sizeof(*policy));
/* minstrel is buggy a little bit, so distille
* incoming rates first. */
/* Sort rates in descending order. */ /* Sort rates in descending order. */
for (i = 1; i < count; ++i) { for (i = 1; i < count; ++i) {
if (rates[i].idx < 0) { if (rates[i].idx < 0) {
...@@ -108,7 +105,8 @@ static void tx_policy_build(const struct cw1200_common *priv, ...@@ -108,7 +105,8 @@ static void tx_policy_build(const struct cw1200_common *priv,
count = i + 1; count = i + 1;
/* Re-fill policy trying to keep every requested rate and with /* Re-fill policy trying to keep every requested rate and with
* respect to the global max tx retransmission count. */ * respect to the global max tx retransmission count.
*/
if (limit < count) if (limit < count)
limit = count; limit = count;
if (total > limit) { if (total > limit) {
...@@ -129,7 +127,6 @@ static void tx_policy_build(const struct cw1200_common *priv, ...@@ -129,7 +127,6 @@ static void tx_policy_build(const struct cw1200_common *priv,
if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) &&
rates[0].idx > 4 && rates[0].count > 2 && rates[0].idx > 4 && rates[0].count > 2 &&
rates[1].idx < 2) { rates[1].idx < 2) {
/* ">> 1" is an equivalent of "/ 2", but faster */
int mid_rate = (rates[0].idx + 4) >> 1; int mid_rate = (rates[0].idx + 4) >> 1;
/* Decrease number of retries for the initial rate */ /* Decrease number of retries for the initial rate */
...@@ -151,7 +148,8 @@ static void tx_policy_build(const struct cw1200_common *priv, ...@@ -151,7 +148,8 @@ static void tx_policy_build(const struct cw1200_common *priv,
/* Fallback to 1 Mbps is a really bad thing, /* Fallback to 1 Mbps is a really bad thing,
* so let's try to increase probability of * so let's try to increase probability of
* successful transmission on the lowest g rate * successful transmission on the lowest g rate
* even more */ * even more
*/
if (rates[0].count >= 3) { if (rates[0].count >= 3) {
--rates[0].count; --rates[0].count;
++rates[2].count; ++rates[2].count;
...@@ -190,13 +188,12 @@ static void tx_policy_build(const struct cw1200_common *priv, ...@@ -190,13 +188,12 @@ static void tx_policy_build(const struct cw1200_common *priv,
policy->retry_count += retries; policy->retry_count += retries;
} }
pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d\n",
count, count,
rates[0].idx, rates[0].count, rates[0].idx, rates[0].count,
rates[1].idx, rates[1].count, rates[1].idx, rates[1].count,
rates[2].idx, rates[2].count, rates[2].idx, rates[2].count,
rates[3].idx, rates[3].count, rates[3].idx, rates[3].count);
rates[4].idx, rates[4].count);
} }
static inline bool tx_policy_is_equal(const struct tx_policy *wanted, static inline bool tx_policy_is_equal(const struct tx_policy *wanted,
...@@ -221,7 +218,8 @@ static int tx_policy_find(struct tx_policy_cache *cache, ...@@ -221,7 +218,8 @@ static int tx_policy_find(struct tx_policy_cache *cache,
{ {
/* O(n) complexity. Not so good, but there's only 8 entries in /* O(n) complexity. Not so good, but there's only 8 entries in
* the cache. * the cache.
* Also lru helps to reduce search time. */ * Also lru helps to reduce search time.
*/
struct tx_policy_cache_entry *it; struct tx_policy_cache_entry *it;
/* First search for policy in "used" list */ /* First search for policy in "used" list */
list_for_each_entry(it, &cache->used, link) { list_for_each_entry(it, &cache->used, link) {
...@@ -265,7 +263,8 @@ void tx_policy_clean(struct cw1200_common *priv) ...@@ -265,7 +263,8 @@ void tx_policy_clean(struct cw1200_common *priv)
for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) { for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) {
entry = &cache->cache[idx]; entry = &cache->cache[idx];
/* Policy usage count should be 0 at this time as all queues /* Policy usage count should be 0 at this time as all queues
should be empty */ should be empty
*/
if (WARN_ON(entry->policy.usage_count)) { if (WARN_ON(entry->policy.usage_count)) {
entry->policy.usage_count = 0; entry->policy.usage_count = 0;
list_move(&entry->link, &cache->free); list_move(&entry->link, &cache->free);
...@@ -320,7 +319,8 @@ static int tx_policy_get(struct cw1200_common *priv, ...@@ -320,7 +319,8 @@ static int tx_policy_get(struct cw1200_common *priv,
struct tx_policy_cache_entry *entry; struct tx_policy_cache_entry *entry;
*renew = true; *renew = true;
/* If policy is not found create a new one /* If policy is not found create a new one
* using the oldest entry in "free" list */ * using the oldest entry in "free" list
*/
entry = list_entry(cache->free.prev, entry = list_entry(cache->free.prev,
struct tx_policy_cache_entry, link); struct tx_policy_cache_entry, link);
entry->policy = wanted; entry->policy = wanted;
...@@ -613,7 +613,8 @@ cw1200_tx_h_bt(struct cw1200_common *priv, ...@@ -613,7 +613,8 @@ cw1200_tx_h_bt(struct cw1200_common *priv,
priv->listen_interval, priv->listen_interval,
mgt_frame->u.assoc_req.listen_interval); mgt_frame->u.assoc_req.listen_interval);
/* Replace listen interval derieved from /* Replace listen interval derieved from
* the one read from SDD */ * the one read from SDD
*/
mgt_frame->u.assoc_req.listen_interval = mgt_frame->u.assoc_req.listen_interval =
priv->listen_interval; priv->listen_interval;
} }
...@@ -668,7 +669,8 @@ cw1200_tx_h_rate_policy(struct cw1200_common *priv, ...@@ -668,7 +669,8 @@ cw1200_tx_h_rate_policy(struct cw1200_common *priv,
pr_debug("[TX] TX policy renew.\n"); pr_debug("[TX] TX policy renew.\n");
/* It's not so optimal to stop TX queues every now and then. /* It's not so optimal to stop TX queues every now and then.
* Better to reimplement task scheduling with * Better to reimplement task scheduling with
* a counter. TODO. */ * a counter. TODO.
*/
wsm_lock_tx_async(priv); wsm_lock_tx_async(priv);
cw1200_tx_queues_lock(priv); cw1200_tx_queues_lock(priv);
if (queue_work(priv->workqueue, if (queue_work(priv->workqueue,
...@@ -833,8 +835,7 @@ static int cw1200_handle_pspoll(struct cw1200_common *priv, ...@@ -833,8 +835,7 @@ static int cw1200_handle_pspoll(struct cw1200_common *priv,
priv->pspoll_mask |= pspoll_mask; priv->pspoll_mask |= pspoll_mask;
drop = 0; drop = 0;
/* Do not report pspols if data for given link id is /* Do not report pspols if data for given link id is queued already. */
* queued already. */
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
if (cw1200_queue_get_num_queued(&priv->tx_queue[i], if (cw1200_queue_get_num_queued(&priv->tx_queue[i],
pspoll_mask)) { pspoll_mask)) {
...@@ -862,9 +863,6 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv, ...@@ -862,9 +863,6 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
pr_debug("[TX] TX confirm: %d, %d.\n", pr_debug("[TX] TX confirm: %d, %d.\n",
arg->status, arg->ack_failures); arg->status, arg->ack_failures);
if (cw1200_itp_tx_running(priv))
return;
if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) {
/* STA is stopped. */ /* STA is stopped. */
return; return;
...@@ -928,7 +926,8 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv, ...@@ -928,7 +926,8 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
cw1200_debug_txed(priv); cw1200_debug_txed(priv);
if (arg->flags & WSM_TX_STATUS_AGGREGATION) { if (arg->flags & WSM_TX_STATUS_AGGREGATION) {
/* Do not report aggregation to mac80211: /* Do not report aggregation to mac80211:
* it confuses minstrel a lot. */ * it confuses minstrel a lot.
*/
/* tx->flags |= IEEE80211_TX_STAT_AMPDU; */ /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */
cw1200_debug_txed_agg(priv); cw1200_debug_txed_agg(priv);
} }
...@@ -1002,8 +1001,7 @@ void cw1200_skb_dtor(struct cw1200_common *priv, ...@@ -1002,8 +1001,7 @@ void cw1200_skb_dtor(struct cw1200_common *priv,
txpriv->raw_link_id, txpriv->tid); txpriv->raw_link_id, txpriv->tid);
tx_policy_put(priv, txpriv->rate_id); tx_policy_put(priv, txpriv->rate_id);
} }
if (!cw1200_is_itp(priv)) ieee80211_tx_status(priv->hw, skb);
ieee80211_tx_status(priv->hw, skb);
} }
void cw1200_rx_cb(struct cw1200_common *priv, void cw1200_rx_cb(struct cw1200_common *priv,
...@@ -1049,7 +1047,8 @@ void cw1200_rx_cb(struct cw1200_common *priv, ...@@ -1049,7 +1047,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
ieee80211_is_action(frame->frame_control) && ieee80211_is_action(frame->frame_control) &&
(mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) {
/* Link ID already exists for the ACTION frame. /* Link ID already exists for the ACTION frame.
* Reset and Remap */ * Reset and Remap
*/
WARN_ON(work_pending(&priv->linkid_reset_work)); WARN_ON(work_pending(&priv->linkid_reset_work));
memcpy(&priv->action_frame_sa[0], memcpy(&priv->action_frame_sa[0],
ieee80211_get_SA(frame), ETH_ALEN); ieee80211_get_SA(frame), ETH_ALEN);
...@@ -1079,7 +1078,6 @@ void cw1200_rx_cb(struct cw1200_common *priv, ...@@ -1079,7 +1078,6 @@ void cw1200_rx_cb(struct cw1200_common *priv,
if (cw1200_handle_pspoll(priv, skb)) if (cw1200_handle_pspoll(priv, skb))
goto drop; goto drop;
hdr->mactime = 0; /* Not supported by WSM */
hdr->band = ((arg->channel_number & 0xff00) || hdr->band = ((arg->channel_number & 0xff00) ||
(arg->channel_number > 14)) ? (arg->channel_number > 14)) ?
IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
...@@ -1107,7 +1105,8 @@ void cw1200_rx_cb(struct cw1200_common *priv, ...@@ -1107,7 +1105,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED; hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED;
/* Oops... There is no fast way to ask mac80211 about /* Oops... There is no fast way to ask mac80211 about
* IV/ICV lengths. Even defineas are not exposed.*/ * IV/ICV lengths. Even defineas are not exposed.
*/
switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) {
case WSM_RX_STATUS_WEP: case WSM_RX_STATUS_WEP:
iv_len = 4 /* WEP_IV_LEN */; iv_len = 4 /* WEP_IV_LEN */;
...@@ -1154,6 +1153,8 @@ void cw1200_rx_cb(struct cw1200_common *priv, ...@@ -1154,6 +1153,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
hdr->mactime = le64_to_cpu(hdr->mactime); hdr->mactime = le64_to_cpu(hdr->mactime);
if (skb->len >= 8) if (skb->len >= 8)
skb_trim(skb, skb->len - 8); skb_trim(skb, skb->len - 8);
} else {
hdr->mactime = 0;
} }
cw1200_debug_rxed(priv); cw1200_debug_rxed(priv);
...@@ -1197,7 +1198,8 @@ void cw1200_rx_cb(struct cw1200_common *priv, ...@@ -1197,7 +1198,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
/* Stay awake after frame is received to give /* Stay awake after frame is received to give
* userspace chance to react and acquire appropriate * userspace chance to react and acquire appropriate
* wakelock. */ * wakelock.
*/
if (ieee80211_is_auth(frame->frame_control)) if (ieee80211_is_auth(frame->frame_control))
grace_period = 5 * HZ; grace_period = 5 * HZ;
else if (ieee80211_is_deauth(frame->frame_control)) else if (ieee80211_is_deauth(frame->frame_control))
...@@ -1206,9 +1208,7 @@ void cw1200_rx_cb(struct cw1200_common *priv, ...@@ -1206,9 +1208,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
grace_period = 1 * HZ; grace_period = 1 * HZ;
cw1200_pm_stay_awake(&priv->pm_state, grace_period); cw1200_pm_stay_awake(&priv->pm_state, grace_period);
if (cw1200_itp_rxed(priv, skb)) { if (early_data) {
consume_skb(skb);
} else if (early_data) {
spin_lock_bh(&priv->ps_state_lock); spin_lock_bh(&priv->ps_state_lock);
/* Double-check status with lock held */ /* Double-check status with lock held */
if (entry->status == CW1200_LINK_SOFT) if (entry->status == CW1200_LINK_SOFT)
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/random.h> #include <linux/random.h>
...@@ -22,7 +21,6 @@ ...@@ -22,7 +21,6 @@
#include "bh.h" #include "bh.h"
#include "sta.h" #include "sta.h"
#include "debug.h" #include "debug.h"
#include "itp.h"
#define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */ #define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */
#define WSM_CMD_START_TIMEOUT (7 * HZ) #define WSM_CMD_START_TIMEOUT (7 * HZ)
...@@ -930,6 +928,8 @@ static int wsm_event_indication(struct cw1200_common *priv, struct wsm_buf *buf) ...@@ -930,6 +928,8 @@ static int wsm_event_indication(struct cw1200_common *priv, struct wsm_buf *buf)
} }
event = kzalloc(sizeof(struct cw1200_wsm_event), GFP_KERNEL); event = kzalloc(sizeof(struct cw1200_wsm_event), GFP_KERNEL);
if (!event)
return -ENOMEM;
event->evt.id = __le32_to_cpu(WSM_GET32(buf)); event->evt.id = __le32_to_cpu(WSM_GET32(buf));
event->evt.data = __le32_to_cpu(WSM_GET32(buf)); event->evt.data = __le32_to_cpu(WSM_GET32(buf));
...@@ -1106,15 +1106,11 @@ static int wsm_cmd_send(struct cw1200_common *priv, ...@@ -1106,15 +1106,11 @@ static int wsm_cmd_send(struct cw1200_common *priv,
else else
pr_debug("[WSM] >>> 0x%.4X (%zu)\n", cmd, buf_len); pr_debug("[WSM] >>> 0x%.4X (%zu)\n", cmd, buf_len);
/* /* Due to buggy SPI on CW1200, we need to
* Due to buggy SPI on CW1200, we need to
* pad the message by a few bytes to ensure * pad the message by a few bytes to ensure
* that it's completely received. * that it's completely received.
*/ */
#ifdef CONFIG_CW1200_ETF buf_len += 4;
if (!etf_mode)
#endif
buf_len += 4;
/* Fill HI message header */ /* Fill HI message header */
/* BH will add sequence number */ /* BH will add sequence number */
...@@ -1165,29 +1161,6 @@ static int wsm_cmd_send(struct cw1200_common *priv, ...@@ -1165,29 +1161,6 @@ static int wsm_cmd_send(struct cw1200_common *priv,
return ret; return ret;
} }
#ifdef CONFIG_CW1200_ETF
int wsm_raw_cmd(struct cw1200_common *priv, u8 *data, size_t len)
{
struct wsm_buf *buf = &priv->wsm_cmd_buf;
int ret;
u16 *cmd = (u16 *)(data + 2);
wsm_cmd_lock(priv);
WSM_PUT(buf, data + 4, len - 4); /* Skip over header (u16+u16) */
ret = wsm_cmd_send(priv, buf, NULL, __le16_to_cpu(*cmd), WSM_CMD_TIMEOUT);
wsm_cmd_unlock(priv);
return ret;
nomem:
wsm_cmd_unlock(priv);
return -ENOMEM;
}
#endif /* CONFIG_CW1200_ETF */
/* ******************************************************************** */ /* ******************************************************************** */
/* WSM TX port control */ /* WSM TX port control */
...@@ -1343,34 +1316,6 @@ int wsm_handle_rx(struct cw1200_common *priv, u16 id, ...@@ -1343,34 +1316,6 @@ int wsm_handle_rx(struct cw1200_common *priv, u16 id,
pr_debug("[WSM] <<< 0x%.4X (%td)\n", id, pr_debug("[WSM] <<< 0x%.4X (%td)\n", id,
wsm_buf.end - wsm_buf.begin); wsm_buf.end - wsm_buf.begin);
#ifdef CONFIG_CW1200_ETF
if (etf_mode) {
struct sk_buff *skb = alloc_skb(wsm_buf.end - wsm_buf.begin, GFP_KERNEL);
/* Strip out Sequence num before passing up */
wsm->id = __le16_to_cpu(wsm->id);
wsm->id &= 0x0FFF;
wsm->id = __cpu_to_le16(wsm->id);
memcpy(skb_put(skb, wsm_buf.end - wsm_buf.begin),
wsm_buf.begin,
wsm_buf.end - wsm_buf.begin);
skb_queue_tail(&priv->etf_q, skb);
/* Special case for startup */
if (id == WSM_STARTUP_IND_ID) {
wsm_startup_indication(priv, &wsm_buf);
} else if (id & 0x0400) {
spin_lock(&priv->wsm_cmd.lock);
priv->wsm_cmd.done = 1;
spin_unlock(&priv->wsm_cmd.lock);
wake_up(&priv->wsm_cmd_wq);
}
goto out;
}
#endif
if (id == WSM_TX_CONFIRM_IND_ID) { if (id == WSM_TX_CONFIRM_IND_ID) {
ret = wsm_tx_confirm(priv, &wsm_buf, link_id); ret = wsm_tx_confirm(priv, &wsm_buf, link_id);
} else if (id == WSM_MULTI_TX_CONFIRM_ID) { } else if (id == WSM_MULTI_TX_CONFIRM_ID) {
...@@ -1732,12 +1677,6 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data, ...@@ -1732,12 +1677,6 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data,
/* More is used only for broadcasts. */ /* More is used only for broadcasts. */
bool more = false; bool more = false;
#ifdef CONFIG_CW1200_ITP
count = cw1200_itp_get_tx(priv, data, tx_len, burst);
if (count)
return count;
#endif
if (priv->wsm_cmd.ptr) { /* CMD request */ if (priv->wsm_cmd.ptr) { /* CMD request */
++count; ++count;
spin_lock(&priv->wsm_cmd.lock); spin_lock(&priv->wsm_cmd.lock);
......
...@@ -314,13 +314,16 @@ struct cw1200_common; ...@@ -314,13 +314,16 @@ struct cw1200_common;
#define WSM_JOIN_FLAGS_P2P_GO BIT(1) #define WSM_JOIN_FLAGS_P2P_GO BIT(1)
/* Force to join BSS with the BSSID and the /* Force to join BSS with the BSSID and the
* SSID specified without waiting for beacons. The * SSID specified without waiting for beacons. The
* ProbeForJoin parameter is ignored. */ * ProbeForJoin parameter is ignored.
*/
#define WSM_JOIN_FLAGS_FORCE BIT(2) #define WSM_JOIN_FLAGS_FORCE BIT(2)
/* Give probe request/response higher /* Give probe request/response higher
* priority over the BT traffic */ * priority over the BT traffic
*/
#define WSM_JOIN_FLAGS_PRIO BIT(3) #define WSM_JOIN_FLAGS_PRIO BIT(3)
/* Issue immediate join confirmation and use /* Issue immediate join confirmation and use
* join complete to notify about completion */ * join complete to notify about completion
*/
#define WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND BIT(5) #define WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND BIT(5)
/* Key types */ /* Key types */
...@@ -1015,22 +1018,19 @@ struct wsm_add_key { ...@@ -1015,22 +1018,19 @@ struct wsm_add_key {
u16 reserved; u16 reserved;
union { union {
struct { struct {
u8 peer[6]; /* MAC address of the u8 peer[6]; /* MAC address of the peer station */
* peer station */
u8 reserved; u8 reserved;
u8 keylen; /* Key length in bytes */ u8 keylen; /* Key length in bytes */
u8 keydata[16]; /* Key data */ u8 keydata[16]; /* Key data */
} __packed wep_pairwise; } __packed wep_pairwise;
struct { struct {
u8 keyid; /* Unique per key identifier u8 keyid; /* Unique per key identifier (0..3) */
* (0..3) */
u8 keylen; /* Key length in bytes */ u8 keylen; /* Key length in bytes */
u16 reserved; u16 reserved;
u8 keydata[16]; /* Key data */ u8 keydata[16]; /* Key data */
} __packed wep_group; } __packed wep_group;
struct { struct {
u8 peer[6]; /* MAC address of the u8 peer[6]; /* MAC address of the peer station */
* peer station */
u16 reserved; u16 reserved;
u8 keydata[16]; /* TKIP key data */ u8 keydata[16]; /* TKIP key data */
u8 rx_mic_key[8]; /* Rx MIC key */ u8 rx_mic_key[8]; /* Rx MIC key */
...@@ -1044,8 +1044,7 @@ struct wsm_add_key { ...@@ -1044,8 +1044,7 @@ struct wsm_add_key {
u8 rx_seqnum[8]; /* Receive Sequence Counter */ u8 rx_seqnum[8]; /* Receive Sequence Counter */
} __packed tkip_group; } __packed tkip_group;
struct { struct {
u8 peer[6]; /* MAC address of the u8 peer[6]; /* MAC address of the peer station */
* peer station */
u16 reserved; u16 reserved;
u8 keydata[16]; /* AES key data */ u8 keydata[16]; /* AES key data */
} __packed aes_pairwise; } __packed aes_pairwise;
...@@ -1056,8 +1055,7 @@ struct wsm_add_key { ...@@ -1056,8 +1055,7 @@ struct wsm_add_key {
u8 rx_seqnum[8]; /* Receive Sequence Counter */ u8 rx_seqnum[8]; /* Receive Sequence Counter */
} __packed aes_group; } __packed aes_group;
struct { struct {
u8 peer[6]; /* MAC address of the u8 peer[6]; /* MAC address of the peer station */
* peer station */
u8 keyid; /* Key ID */ u8 keyid; /* Key ID */
u8 reserved; u8 reserved;
u8 keydata[16]; /* WAPI key data */ u8 keydata[16]; /* WAPI key data */
...@@ -1550,7 +1548,8 @@ struct wsm_tx_rate_retry_policy { ...@@ -1550,7 +1548,8 @@ struct wsm_tx_rate_retry_policy {
* finishes. * finishes.
* BIT(3) - Count initial frame transmission as part of * BIT(3) - Count initial frame transmission as part of
* rate retry counting but not as a retry * rate retry counting but not as a retry
* attempt */ * attempt
*/
u8 flags; u8 flags;
u8 rate_recoveries; u8 rate_recoveries;
u8 reserved[3]; u8 reserved[3];
...@@ -1618,24 +1617,24 @@ static inline int wsm_set_udp_port_filter(struct cw1200_common *priv, ...@@ -1618,24 +1617,24 @@ static inline int wsm_set_udp_port_filter(struct cw1200_common *priv,
#define D11_MAX_SSID_LEN (32) #define D11_MAX_SSID_LEN (32)
struct wsm_p2p_device_type { struct wsm_p2p_device_type {
__le16 categoryId; __le16 category_id;
u8 oui[4]; u8 oui[4];
__le16 subCategoryId; __le16 subcategory_id;
} __packed; } __packed;
struct wsm_p2p_device_info { struct wsm_p2p_device_info {
struct wsm_p2p_device_type primaryDevice; struct wsm_p2p_device_type primaryDevice;
u8 reserved1[3]; u8 reserved1[3];
u8 devNameSize; u8 devname_size;
u8 localDevName[D11_MAX_SSID_LEN]; u8 local_devname[D11_MAX_SSID_LEN];
u8 reserved2[3]; u8 reserved2[3];
u8 numSecDevSupported; u8 num_secdev_supported;
struct wsm_p2p_device_type secondaryDevices[0]; struct wsm_p2p_device_type secdevs[0];
} __packed; } __packed;
/* 4.36 SetWCDMABand - WO */ /* 4.36 SetWCDMABand - WO */
struct wsm_cdma_band { struct wsm_cdma_band {
u8 WCDMA_Band; u8 wcdma_band;
u8 reserved[3]; u8 reserved[3];
} __packed; } __packed;
...@@ -1668,19 +1667,19 @@ struct wsm_ht_protection { ...@@ -1668,19 +1667,19 @@ struct wsm_ht_protection {
#define WSM_GPIO_ALL_PINS 0xFF #define WSM_GPIO_ALL_PINS 0xFF
struct wsm_gpio_command { struct wsm_gpio_command {
u8 GPIO_Command; u8 command;
u8 pin; u8 pin;
__le16 config; __le16 config;
} __packed; } __packed;
/* 4.41 TSFCounter - RO */ /* 4.41 TSFCounter - RO */
struct wsm_tsf_counter { struct wsm_tsf_counter {
__le64 TSF_Counter; __le64 tsf_counter;
} __packed; } __packed;
/* 4.43 Keep alive period */ /* 4.43 Keep alive period */
struct wsm_keep_alive_period { struct wsm_keep_alive_period {
__le16 keepAlivePeriod; __le16 period;
u8 reserved[2]; u8 reserved[2];
} __packed; } __packed;
...@@ -1688,7 +1687,7 @@ static inline int wsm_keep_alive_period(struct cw1200_common *priv, ...@@ -1688,7 +1687,7 @@ static inline int wsm_keep_alive_period(struct cw1200_common *priv,
int period) int period)
{ {
struct wsm_keep_alive_period arg = { struct wsm_keep_alive_period arg = {
.keepAlivePeriod = __cpu_to_le16(period), .period = __cpu_to_le16(period),
}; };
return wsm_write_mib(priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD, return wsm_write_mib(priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD,
&arg, sizeof(arg)); &arg, sizeof(arg));
...@@ -1739,13 +1738,13 @@ static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv, ...@@ -1739,13 +1738,13 @@ static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv,
/* P2P Power Save Mode Info - 4.31 */ /* P2P Power Save Mode Info - 4.31 */
struct wsm_p2p_ps_modeinfo { struct wsm_p2p_ps_modeinfo {
u8 oppPsCTWindow; u8 opp_ps_ct_window;
u8 count; u8 count;
u8 reserved; u8 reserved;
u8 dtimCount; u8 dtim_count;
__le32 duration; __le32 duration;
__le32 interval; __le32 interval;
__le32 startTime; __le32 start_time;
} __packed; } __packed;
static inline int wsm_set_p2p_ps_modeinfo(struct cw1200_common *priv, static inline int wsm_set_p2p_ps_modeinfo(struct cw1200_common *priv,
...@@ -1871,9 +1870,4 @@ static inline u8 wsm_queue_id_to_wsm(u8 queue_id) ...@@ -1871,9 +1870,4 @@ static inline u8 wsm_queue_id_to_wsm(u8 queue_id)
return queue_mapping[queue_id]; return queue_mapping[queue_id];
} }
#ifdef CONFIG_CW1200_ETF
int wsm_raw_cmd(struct cw1200_common *priv, u8 *data, size_t len);
#endif
#endif /* CW1200_HWIO_H_INCLUDED */ #endif /* CW1200_HWIO_H_INCLUDED */
...@@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, ...@@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
if ((val & 0x0000ff00) != 0) if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
pci_set_power_state(pci_dev, PCI_D0);
if (!ipw2100_hw_is_adapter_in_system(dev)) { if (!ipw2100_hw_is_adapter_in_system(dev)) {
printk(KERN_WARNING DRV_NAME printk(KERN_WARNING DRV_NAME
"Device not found via register read.\n"); "Device not found via register read.\n");
......
...@@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = { ...@@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
.types = BIT(NL80211_IFTYPE_STATION) | .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP), BIT(NL80211_IFTYPE_AP),
}, },
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO),
},
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
},
}; };
static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
...@@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->chanctx_data_size = sizeof(u16); hw->chanctx_data_size = sizeof(u16);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP); BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_DISABLE_BEACON_HINTS |
......
...@@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { ...@@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
#endif #endif
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) }, BIT(NL80211_IFTYPE_P2P_GO) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
}; };
static struct ieee80211_iface_combination hwsim_if_comb = { static struct ieee80211_iface_combination hwsim_if_comb = {
...@@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void) ...@@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT); BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->flags = IEEE80211_HW_MFP_CAPABLE | hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SIGNAL_DBM |
......
...@@ -1170,12 +1170,6 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, ...@@ -1170,12 +1170,6 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
rt2x00queue_reset(queue); rt2x00queue_reset(queue);
queue->limit = qdesc->entry_num;
queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10);
queue->data_size = qdesc->data_size;
queue->desc_size = qdesc->desc_size;
queue->winfo_size = qdesc->winfo_size;
/* /*
* Allocate all queue entries. * Allocate all queue entries.
*/ */
...@@ -1284,9 +1278,38 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) ...@@ -1284,9 +1278,38 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
} }
} }
static const struct data_queue_desc *
rt2x00queue_get_qdesc_by_qid(struct rt2x00_dev *rt2x00dev,
enum data_queue_qid qid)
{
switch (qid) {
case QID_RX:
return rt2x00dev->ops->rx;
case QID_AC_BE:
case QID_AC_BK:
case QID_AC_VO:
case QID_AC_VI:
return rt2x00dev->ops->tx;
case QID_BEACON:
return rt2x00dev->ops->bcn;
case QID_ATIM:
return rt2x00dev->ops->atim;
default:
break;
}
return NULL;
}
static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, enum data_queue_qid qid) struct data_queue *queue, enum data_queue_qid qid)
{ {
const struct data_queue_desc *qdesc;
mutex_init(&queue->status_lock); mutex_init(&queue->status_lock);
spin_lock_init(&queue->tx_lock); spin_lock_init(&queue->tx_lock);
spin_lock_init(&queue->index_lock); spin_lock_init(&queue->index_lock);
...@@ -1297,6 +1320,15 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, ...@@ -1297,6 +1320,15 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
queue->aifs = 2; queue->aifs = 2;
queue->cw_min = 5; queue->cw_min = 5;
queue->cw_max = 10; queue->cw_max = 10;
qdesc = rt2x00queue_get_qdesc_by_qid(rt2x00dev, qid);
BUG_ON(!qdesc);
queue->limit = qdesc->entry_num;
queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10);
queue->data_size = qdesc->data_size;
queue->desc_size = qdesc->desc_size;
queue->winfo_size = qdesc->winfo_size;
} }
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
......
...@@ -842,7 +842,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( ...@@ -842,7 +842,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
long val_y, ele_c = 0; long val_y, ele_c = 0;
u8 ofdm_index[2]; u8 ofdm_index[2];
s8 cck_index = 0; s8 cck_index = 0;
u8 ofdm_index_old[2]; u8 ofdm_index_old[2] = {0, 0};
s8 cck_index_old = 0; s8 cck_index_old = 0;
u8 index; u8 index;
int i; int i;
......
...@@ -14,8 +14,8 @@ struct cw1200_platform_data_spi { ...@@ -14,8 +14,8 @@ struct cw1200_platform_data_spi {
/* All others are optional */ /* All others are optional */
bool have_5ghz; bool have_5ghz;
const struct resource *reset; /* GPIO to RSTn signal */ int reset; /* GPIO to RSTn signal (0 disables) */
const struct resource *powerup; /* GPIO to POWERUP signal */ int powerup; /* GPIO to POWERUP signal (0 disables) */
int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata, int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata,
bool enable); /* Control 3v3 / 1v8 supply */ bool enable); /* Control 3v3 / 1v8 supply */
int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata, int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata,
...@@ -28,11 +28,11 @@ struct cw1200_platform_data_sdio { ...@@ -28,11 +28,11 @@ struct cw1200_platform_data_sdio {
u16 ref_clk; /* REQUIRED (in KHz) */ u16 ref_clk; /* REQUIRED (in KHz) */
/* All others are optional */ /* All others are optional */
const struct resource *irq; /* if using GPIO for IRQ */
bool have_5ghz; bool have_5ghz;
bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */ bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */
const struct resource *reset; /* GPIO to RSTn signal */ int reset; /* GPIO to RSTn signal (0 disables) */
const struct resource *powerup; /* GPIO to POWERUP signal */ int powerup; /* GPIO to POWERUP signal (0 disables) */
int irq; /* IRQ line or 0 to use SDIO IRQ */
int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata, int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata,
bool enable); /* Control 3v3 / 1v8 supply */ bool enable); /* Control 3v3 / 1v8 supply */
int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata, int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata,
...@@ -41,6 +41,41 @@ struct cw1200_platform_data_sdio { ...@@ -41,6 +41,41 @@ struct cw1200_platform_data_sdio {
const char *sdd_file; /* if NULL, will use default for detected hw type */ const char *sdd_file; /* if NULL, will use default for detected hw type */
}; };
const void *cw1200_get_platform_data(void);
/* An example of SPI support in your board setup file:
static struct cw1200_platform_data_spi cw1200_platform_data = {
.ref_clk = 38400,
.spi_bits_per_word = 16,
.reset = GPIO_RF_RESET,
.powerup = GPIO_RF_POWERUP,
.macaddr = wifi_mac_addr,
.sdd_file = "sdd_sagrad_1091_1098.bin",
};
static struct spi_board_info myboard_spi_devices[] __initdata = {
{
.modalias = "cw1200_wlan_spi",
.max_speed_hz = 52000000,
.bus_num = 0,
.irq = WIFI_IRQ,
.platform_data = &cw1200_platform_data,
.chip_select = 0,
},
};
*/
/* An example of SDIO support in your board setup file:
static struct cw1200_platform_data_sdio my_cw1200_platform_data = {
.ref_clk = 38400,
.have_5ghz = false,
.sdd_file = "sdd_myplatform.bin",
};
cw1200_sdio_set_platform_data(&my_cw1200_platform_data);
*/
void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata);
#endif /* CW1200_PLAT_H_INCLUDED */ #endif /* CW1200_PLAT_H_INCLUDED */
...@@ -961,6 +961,7 @@ struct station_info { ...@@ -961,6 +961,7 @@ struct station_info {
* @MONITOR_FLAG_CONTROL: pass control frames * @MONITOR_FLAG_CONTROL: pass control frames
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
*/ */
enum monitor_flags { enum monitor_flags {
MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
...@@ -968,6 +969,7 @@ enum monitor_flags { ...@@ -968,6 +969,7 @@ enum monitor_flags {
MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
MONITOR_FLAG_ACTIVE = 1<<NL80211_MNTR_FLAG_ACTIVE,
}; };
/** /**
...@@ -2867,7 +2869,6 @@ struct cfg80211_cached_keys; ...@@ -2867,7 +2869,6 @@ struct cfg80211_cached_keys;
* @mgmt_registrations_lock: lock for the list * @mgmt_registrations_lock: lock for the list
* @mtx: mutex used to lock data in this struct, may be used by drivers * @mtx: mutex used to lock data in this struct, may be used by drivers
* and some API functions require it held * and some API functions require it held
* @cleanup_work: work struct used for cleanup that can't be done directly
* @beacon_interval: beacon interval used on this device for transmitting * @beacon_interval: beacon interval used on this device for transmitting
* beacons, 0 when not valid * beacons, 0 when not valid
* @address: The address for this device, valid only if @netdev is %NULL * @address: The address for this device, valid only if @netdev is %NULL
......
...@@ -2428,6 +2428,8 @@ enum nl80211_survey_info { ...@@ -2428,6 +2428,8 @@ enum nl80211_survey_info {
* @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
* @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
* overrides all other flags. * overrides all other flags.
* @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
* and ACK incoming unicast packets.
* *
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
...@@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags { ...@@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags {
NL80211_MNTR_FLAG_CONTROL, NL80211_MNTR_FLAG_CONTROL,
NL80211_MNTR_FLAG_OTHER_BSS, NL80211_MNTR_FLAG_OTHER_BSS,
NL80211_MNTR_FLAG_COOK_FRAMES, NL80211_MNTR_FLAG_COOK_FRAMES,
NL80211_MNTR_FLAG_ACTIVE,
/* keep last */ /* keep last */
__NL80211_MNTR_FLAG_AFTER_LAST, __NL80211_MNTR_FLAG_AFTER_LAST,
...@@ -3595,6 +3598,7 @@ enum nl80211_feature_flags { ...@@ -3595,6 +3598,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
NL80211_FEATURE_USERSPACE_MPM = 1 << 16, NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
}; };
/** /**
......
...@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy, ...@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
if (ieee80211_sdata_running(sdata)) { if (ieee80211_sdata_running(sdata)) {
u32 mask = MONITOR_FLAG_COOK_FRAMES |
MONITOR_FLAG_ACTIVE;
/* /*
* Prohibit MONITOR_FLAG_COOK_FRAMES to be * Prohibit MONITOR_FLAG_COOK_FRAMES and
* changed while the interface is up. * MONITOR_FLAG_ACTIVE to be changed while the
* interface is up.
* Else we would need to add a lot of cruft * Else we would need to add a lot of cruft
* to update everything: * to update everything:
* cooked_mntrs, monitor and all fif_* counters * cooked_mntrs, monitor and all fif_* counters
* reconfigure hardware * reconfigure hardware
*/ */
if ((*flags & MONITOR_FLAG_COOK_FRAMES) != if ((*flags & mask) != (sdata->u.mntr_flags & mask))
(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
return -EBUSY; return -EBUSY;
ieee80211_adjust_monitor_flags(sdata, -1); ieee80211_adjust_monitor_flags(sdata, -1);
...@@ -2375,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, ...@@ -2375,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
local->dynamic_ps_forced_timeout = timeout; local->dynamic_ps_forced_timeout = timeout;
/* no change, but if automatic follow powersave */ /* no change, but if automatic follow powersave */
sdata_lock(sdata);
__ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
sdata_unlock(sdata);
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
......
...@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local, ...@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR && (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)))) !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) &&
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
return -EINVAL; return -EINVAL;
trace_drv_add_interface(local, sdata); trace_drv_add_interface(local, sdata);
......
...@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) ...@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr,
bool check_dup)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
u64 new, mask, tmp; u64 new, mask, tmp;
...@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) ...@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
if (!check_dup)
return ret;
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue; continue;
m = sdata->vif.addr; m = sdata->vif.addr;
...@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) ...@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sockaddr *sa = addr; struct sockaddr *sa = addr;
bool check_dup = true;
int ret; int ret;
if (ieee80211_sdata_running(sdata)) if (ieee80211_sdata_running(sdata))
return -EBUSY; return -EBUSY;
ret = ieee80211_verify_mac(sdata->local, sa->sa_data); if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
check_dup = false;
ret = ieee80211_verify_mac(sdata->local, sa->sa_data, check_dup);
if (ret) if (ret)
return ret; return ret;
...@@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) ...@@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
break; break;
} }
if (local->monitors == 0 && local->open_count == 0) { if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
} else if (local->monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local); res = ieee80211_add_virtual_monitor(local);
if (res) if (res)
goto err_stop; goto err_stop;
...@@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
ieee80211_recalc_idle(local); ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
break;
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
break;
/* fall through */
default: default:
if (going_down) if (going_down)
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
...@@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { ...@@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_start_xmit = ieee80211_monitor_start_xmit, .ndo_start_xmit = ieee80211_monitor_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list, .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu, .ndo_change_mtu = ieee80211_change_mtu,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_monitor_select_queue, .ndo_select_queue = ieee80211_monitor_select_queue,
}; };
......
...@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
if (ieee80211_has_order(hdr->frame_control)) if (ieee80211_has_order(hdr->frame_control))
return TX_CONTINUE; return TX_CONTINUE;
if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
info->hw_queue = tx->sdata->vif.cab_queue;
/* no stations in PS mode */ /* no stations in PS mode */
if (!atomic_read(&ps->num_sta_ps)) if (!atomic_read(&ps->num_sta_ps))
return TX_CONTINUE; return TX_CONTINUE;
info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
info->hw_queue = tx->sdata->vif.cab_queue;
/* device releases frame after DTIM beacon */ /* device releases frame after DTIM beacon */
if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
......
...@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces( ...@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MONITOR:
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue;
break;
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
continue; continue;
default: default:
...@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic( ...@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MONITOR:
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue;
break;
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
continue; continue;
default: default:
......
...@@ -2227,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { ...@@ -2227,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
}; };
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
...@@ -2338,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -2338,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
change = true; change = true;
} }
if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) &&
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
return -EOPNOTSUPP;
if (change) if (change)
err = cfg80211_change_iface(rdev, dev, ntype, flags, &params); err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
else else
...@@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags); &flags);
if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
return -EOPNOTSUPP;
wdev = rdev_add_virtual_intf(rdev, wdev = rdev_add_virtual_intf(rdev,
nla_data(info->attrs[NL80211_ATTR_IFNAME]), nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params); type, err ? NULL : &flags, &params);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册