mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 18:20:54 +07:00
Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
This commit is contained in:
commit
8e00cc1261
@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416AniState *aniState;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
if (!ah->curchan)
|
||||
return;
|
||||
|
||||
aniState = &ah->curchan->ani;
|
||||
aniState = &ah->ani;
|
||||
aniState->listenTime = 0;
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(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,
|
||||
bool scan)
|
||||
{
|
||||
struct ar5416AniState *aniState = &ah->curchan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
const struct ani_ofdm_level_entry *entry_ofdm;
|
||||
const struct ani_cck_level_entry *entry_cck;
|
||||
@ -195,10 +195,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416AniState *aniState;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
if (!ah->curchan)
|
||||
return;
|
||||
|
||||
aniState = &ah->curchan->ani;
|
||||
aniState = &ah->ani;
|
||||
|
||||
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
|
||||
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)
|
||||
static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
|
||||
bool scan)
|
||||
{
|
||||
struct ar5416AniState *aniState = &ah->curchan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
const struct ani_ofdm_level_entry *entry_ofdm;
|
||||
const struct ani_cck_level_entry *entry_cck;
|
||||
@ -251,10 +251,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416AniState *aniState;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
if (!ah->curchan)
|
||||
return;
|
||||
|
||||
aniState = &ah->curchan->ani;
|
||||
aniState = &ah->ani;
|
||||
|
||||
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
|
||||
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
|
||||
@ -269,7 +269,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416AniState *aniState;
|
||||
|
||||
aniState = &ah->curchan->ani;
|
||||
aniState = &ah->ani;
|
||||
|
||||
/* lower OFDM noise immunity */
|
||||
if (aniState->ofdmNoiseImmunityLevel > 0 &&
|
||||
@ -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)
|
||||
{
|
||||
struct ar5416AniState *aniState = &ah->curchan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
struct ath9k_channel *chan = ah->curchan;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int ofdm_nil, cck_nil;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
if (!ah->curchan)
|
||||
return;
|
||||
|
||||
BUG_ON(aniState == NULL);
|
||||
@ -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)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ar5416AniState *aniState = &ah->curchan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
u32 phyCnt1, phyCnt2;
|
||||
int32_t listenTime;
|
||||
|
||||
@ -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);
|
||||
u32 ofdmPhyErrRate, cckPhyErrRate;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
if (!ah->curchan)
|
||||
return;
|
||||
|
||||
aniState = &ah->curchan->ani;
|
||||
aniState = &ah->ani;
|
||||
if (!ath9k_hw_ani_read_counters(ah))
|
||||
return;
|
||||
|
||||
@ -490,32 +490,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
|
||||
void ath9k_hw_ani_init(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int i;
|
||||
struct ar5416AniState *ani = &ah->ani;
|
||||
|
||||
ath_dbg(common, ANI, "Initialize ANI\n");
|
||||
|
||||
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
|
||||
|
||||
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
|
||||
struct ath9k_channel *chan = &ah->channels[i];
|
||||
struct ar5416AniState *ani = &chan->ani;
|
||||
|
||||
ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
|
||||
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
|
||||
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;
|
||||
}
|
||||
ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
|
||||
ani->ofdmsTurn = true;
|
||||
ani->ofdmWeakSigDetect = true;
|
||||
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
|
||||
@ -524,9 +514,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
|
||||
ah->aniperiod = ATH9K_ANI_PERIOD;
|
||||
ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
|
||||
|
||||
if (ah->config.enable_ani)
|
||||
ah->proc_phyerr |= HAL_PROCESS_ANI;
|
||||
|
||||
ath9k_ani_restart(ah);
|
||||
ath9k_enable_mib_counters(ah);
|
||||
}
|
||||
|
@ -17,10 +17,6 @@
|
||||
#ifndef 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)
|
||||
|
||||
/* units are errors per second */
|
||||
@ -38,11 +34,7 @@
|
||||
#define ATH9K_ANI_CCK_TRIG_LOW 300
|
||||
|
||||
#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_FIRSTEP_LVL 2
|
||||
|
||||
#define ATH9K_ANI_RSSI_THR_HIGH 40
|
||||
@ -111,7 +103,7 @@ struct ar5416AniState {
|
||||
u8 mrcCCK;
|
||||
u8 spurImmunityLevel;
|
||||
u8 firstepLevel;
|
||||
u8 ofdmWeakSigDetect;
|
||||
bool ofdmWeakSigDetect;
|
||||
u32 listenTime;
|
||||
u32 ofdmPhyErrCount;
|
||||
u32 cckPhyErrCount;
|
||||
@ -119,8 +111,6 @@ struct ar5416AniState {
|
||||
};
|
||||
|
||||
struct ar5416Stats {
|
||||
u32 ast_ani_niup;
|
||||
u32 ast_ani_nidown;
|
||||
u32 ast_ani_spurup;
|
||||
u32 ast_ani_spurdown;
|
||||
u32 ast_ani_ofdmon;
|
||||
|
@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_channel *chan = ah->curchan;
|
||||
struct ar5416AniState *aniState = &chan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
s32 value, value2;
|
||||
|
||||
switch (cmd & ah->ani_function) {
|
||||
@ -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 ath9k_channel *chan = ah->curchan;
|
||||
struct ar5416AniState *aniState = &chan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
struct ath9k_ani_default *iniDef;
|
||||
u32 val;
|
||||
|
||||
@ -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 */
|
||||
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_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 */
|
||||
}
|
||||
|
||||
|
@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
|
||||
else
|
||||
INIT_INI_ARRAY(&ah->iniPcieSerdes,
|
||||
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)) {
|
||||
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);
|
||||
|
@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
|
||||
{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] = {
|
||||
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
|
||||
{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
|
||||
|
@ -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_flags = 0;
|
||||
rxs->flag = 0;
|
||||
|
||||
rxs->rs_datalen = rxsp->status2 & AR_DataLen;
|
||||
rxs->rs_tstamp = rxsp->status3;
|
||||
@ -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_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
|
||||
rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
|
||||
rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0;
|
||||
rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0;
|
||||
rxs->flag |= (rxsp->status4 & AR_GI) ? RX_FLAG_SHORT_GI : 0;
|
||||
rxs->flag |= (rxsp->status4 & AR_2040) ? RX_FLAG_40MHZ : 0;
|
||||
|
||||
rxs->evm0 = rxsp->status6;
|
||||
rxs->evm1 = rxsp->status7;
|
||||
|
@ -904,7 +904,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_channel *chan = ah->curchan;
|
||||
struct ar5416AniState *aniState = &chan->ani;
|
||||
struct ar5416AniState *aniState = &ah->ani;
|
||||
s32 value, value2;
|
||||
|
||||
switch (cmd & ah->ani_function) {
|
||||
@ -1172,7 +1172,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
|
||||
struct ath9k_ani_default *iniDef;
|
||||
u32 val;
|
||||
|
||||
aniState = &ah->curchan->ani;
|
||||
aniState = &ah->ani;
|
||||
iniDef = &aniState->iniDef;
|
||||
|
||||
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)
|
||||
/* these levels just got reset to defaults by the INI */
|
||||
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
|
||||
aniState->ofdmWeakSigDetect = true;
|
||||
aniState->mrcCCK = true;
|
||||
}
|
||||
|
||||
|
@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = {
|
||||
.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)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
char buf[32];
|
||||
unsigned int len;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
unsigned int len = 0, size = 1024;
|
||||
ssize_t retval = 0;
|
||||
char *buf;
|
||||
|
||||
len = sprintf(buf, "%d\n", common->disable_ani);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
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,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t write_file_ani(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
unsigned long disable_ani;
|
||||
unsigned long ani;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
|
||||
@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file,
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (strict_strtoul(buf, 0, &disable_ani))
|
||||
if (strict_strtoul(buf, 0, &ani))
|
||||
return -EINVAL;
|
||||
|
||||
common->disable_ani = !!disable_ani;
|
||||
if (ani < 0 || ani > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (disable_ani) {
|
||||
common->disable_ani = !ani;
|
||||
|
||||
if (common->disable_ani) {
|
||||
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
ath_stop_ani(sc);
|
||||
} else {
|
||||
@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_disable_ani = {
|
||||
.read = read_file_disable_ani,
|
||||
.write = write_file_disable_ani,
|
||||
static const struct file_operations fops_ani = {
|
||||
.read = read_file_ani,
|
||||
.write = write_file_ani,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
@ -1719,8 +1766,8 @@ int ath9k_init_debug(struct ath_hw *ah)
|
||||
sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
|
||||
debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
|
||||
debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, sc, &fops_disable_ani);
|
||||
debugfs_create_file("ani", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, sc, &fops_ani);
|
||||
debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
|
||||
&sc->sc_ah->config.enable_paprd);
|
||||
debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
|
||||
|
@ -251,45 +251,6 @@ struct ath_stats {
|
||||
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 dentry *debugfs_phy;
|
||||
u32 regidx;
|
||||
|
@ -814,8 +814,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* Verify whether we must check ANI */
|
||||
if (ah->config.enable_ani &&
|
||||
(timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
|
||||
if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
|
||||
aniflag = true;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
}
|
||||
@ -845,8 +844,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
|
||||
* short calibration and long calibration.
|
||||
*/
|
||||
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)
|
||||
cal_interval = min(cal_interval, (u32)short_cal_interval);
|
||||
|
||||
|
@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
||||
ah->config.pcie_clock_req = 0;
|
||||
ah->config.pcie_waen = 0;
|
||||
ah->config.analog_shiftreg = 1;
|
||||
ah->config.enable_ani = true;
|
||||
|
||||
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
||||
ah->config.spurchans[i][0] = AR_NO_SPUR;
|
||||
@ -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_rev(ah));
|
||||
|
||||
if (ah->config.enable_ani)
|
||||
ath9k_hw_ani_init(ah);
|
||||
ath9k_hw_ani_init(ah);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2595,13 +2593,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_RTT;
|
||||
}
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
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_9462(ah))
|
||||
pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE;
|
||||
|
||||
if (AR_SREV_9300_20_OR_LATER(ah) &&
|
||||
ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
|
||||
|
@ -246,9 +246,7 @@ enum ath9k_hw_caps {
|
||||
ATH9K_HW_CAP_MCI = BIT(15),
|
||||
ATH9K_HW_CAP_DFS = BIT(16),
|
||||
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
|
||||
ATH9K_HW_WOW_PATTERN_MATCH_EXACT = BIT(18),
|
||||
ATH9K_HW_WOW_PATTERN_MATCH_DWORD = BIT(19),
|
||||
ATH9K_HW_CAP_PAPRD = BIT(20),
|
||||
ATH9K_HW_CAP_PAPRD = BIT(18),
|
||||
};
|
||||
|
||||
/*
|
||||
@ -291,7 +289,6 @@ struct ath9k_ops_config {
|
||||
u32 ofdm_trig_high;
|
||||
u32 cck_trig_high;
|
||||
u32 cck_trig_low;
|
||||
u32 enable_ani;
|
||||
u32 enable_paprd;
|
||||
int serialize_regmode;
|
||||
bool rx_intr_mitigation;
|
||||
@ -423,7 +420,6 @@ struct ath9k_hw_cal_data {
|
||||
|
||||
struct ath9k_channel {
|
||||
struct ieee80211_channel *chan;
|
||||
struct ar5416AniState ani;
|
||||
u16 channel;
|
||||
u32 channelFlags;
|
||||
u32 chanmode;
|
||||
@ -854,10 +850,10 @@ struct ath_hw {
|
||||
u32 globaltxtimeout;
|
||||
|
||||
/* ANI */
|
||||
u32 proc_phyerr;
|
||||
u32 aniperiod;
|
||||
enum ath9k_ani_cmd ani_function;
|
||||
u32 ani_skip_count;
|
||||
struct ar5416AniState ani;
|
||||
|
||||
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
|
||||
struct ath_btcoex_hw btcoex_hw;
|
||||
@ -882,9 +878,6 @@ struct ath_hw {
|
||||
struct ar5416IniArray iniBank6;
|
||||
struct ar5416IniArray iniAddac;
|
||||
struct ar5416IniArray iniPcieSerdes;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct ar5416IniArray iniPcieSerdesWow;
|
||||
#endif
|
||||
struct ar5416IniArray iniPcieSerdesLowPower;
|
||||
struct ar5416IniArray iniModesFastClock;
|
||||
struct ar5416IniArray iniAdditional;
|
||||
@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define ATH9K_CLOCK_RATE_CCK 22
|
||||
#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
|
||||
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/ath9k_platform.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/relay.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
@ -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_SUPPORTS_RC_TABLE;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
|
||||
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
|
||||
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)
|
||||
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
|
||||
|
||||
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
@ -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;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
|
||||
device_can_wakeup(sc->dev)) {
|
||||
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT;
|
||||
hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN;
|
||||
hw->wiphy->wowlan.pattern_min_len = 1;
|
||||
hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE;
|
||||
|
||||
}
|
||||
|
||||
atomic_set(&sc->wow_sleep_proc_intr, -1);
|
||||
atomic_set(&sc->wow_got_bmiss_intr, -1);
|
||||
|
||||
#endif
|
||||
|
||||
hw->queues = 4;
|
||||
|
@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data)
|
||||
}
|
||||
|
||||
/* Verify whether we must check ANI */
|
||||
if (sc->sc_ah->config.enable_ani
|
||||
&& (timestamp - common->ani.checkani_timer) >=
|
||||
ah->config.ani_poll_interval) {
|
||||
if ((timestamp - common->ani.checkani_timer) >= ah->config.ani_poll_interval) {
|
||||
aniflag = true;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
}
|
||||
@ -427,9 +425,7 @@ void ath_ani_calibrate(unsigned long data)
|
||||
* short calibration and long calibration.
|
||||
*/
|
||||
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)
|
||||
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,
|
||||
|
||||
rs->rs_status = 0;
|
||||
rs->rs_flags = 0;
|
||||
rs->flag = 0;
|
||||
|
||||
rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
|
||||
rs->rs_tstamp = ads.AR_RcvTimestamp;
|
||||
@ -586,10 +587,17 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
rs->rs_moreaggr =
|
||||
(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
|
||||
rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
|
||||
rs->rs_flags =
|
||||
(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
|
||||
rs->rs_flags |=
|
||||
(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
|
||||
|
||||
/* directly mapped flags for ieee80211_rx_status */
|
||||
rs->flag |=
|
||||
(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)
|
||||
rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
|
||||
|
@ -149,6 +149,7 @@ struct ath_rx_status {
|
||||
u32 evm2;
|
||||
u32 evm3;
|
||||
u32 evm4;
|
||||
u32 flag; /* see enum mac80211_rx_flags */
|
||||
};
|
||||
|
||||
struct ath_htc_rx_status {
|
||||
@ -533,7 +534,8 @@ struct ar5416_desc {
|
||||
#define AR_2040 0x00000002
|
||||
#define AR_Parallel40 0x00000004
|
||||
#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_S 8
|
||||
|
||||
|
@ -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_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_hw_capabilities *pcaps = &ah->caps;
|
||||
int pattern_count = 0;
|
||||
int i, byte_cnt;
|
||||
u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
|
||||
@ -2073,36 +2072,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
|
||||
|
||||
/* Create Disassociate pattern mask */
|
||||
|
||||
if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) {
|
||||
|
||||
if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
dis_deauth_mask[0] = 0xfe;
|
||||
dis_deauth_mask[1] = 0x03;
|
||||
dis_deauth_mask[2] = 0xc0;
|
||||
|
||||
ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
|
||||
|
||||
|
@ -868,10 +868,7 @@ static int ath9k_process_rate(struct ath_common *common,
|
||||
if (rx_stats->rs_rate & 0x80) {
|
||||
/* HT rate */
|
||||
rxs->flag |= RX_FLAG_HT;
|
||||
if (rx_stats->rs_flags & ATH9K_RX_2040)
|
||||
rxs->flag |= RX_FLAG_40MHZ;
|
||||
if (rx_stats->rs_flags & ATH9K_RX_GI)
|
||||
rxs->flag |= RX_FLAG_SHORT_GI;
|
||||
rxs->flag |= rx_stats->flag;
|
||||
rxs->rate_idx = rx_stats->rs_rate & 0x7f;
|
||||
return 0;
|
||||
}
|
||||
@ -958,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
|
||||
if (rx_stats->rs_more)
|
||||
return 0;
|
||||
|
||||
ath9k_process_rssi(common, hw, hdr, rx_stats);
|
||||
|
||||
if (ath9k_process_rate(common, hw, rx_stats, rx_status))
|
||||
return -EINVAL;
|
||||
|
||||
ath9k_process_rssi(common, hw, hdr, rx_stats);
|
||||
|
||||
rx_status->band = hw->conf.chandef.chan->band;
|
||||
rx_status->freq = hw->conf.chandef.chan->center_freq;
|
||||
rx_status->signal = ah->noise + rx_stats->rs_rssi;
|
||||
|
@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event)
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(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",
|
||||
REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
|
||||
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);
|
||||
}
|
||||
|
||||
@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
|
||||
|
||||
/* set the transmit buffer */
|
||||
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[3] = 0xb; /* OFDM_6M hardware value for this rate */
|
||||
ctl[4] = 0;
|
||||
ctl[7] = (ah->txchainmask) << 2;
|
||||
|
||||
if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
ctl[2] = 0xf << 16; /* tx_tries 0 */
|
||||
else
|
||||
ctl[2] = 0x7 << 16; /* tx_tries 0 */
|
||||
|
||||
ctl[2] = 0xf << 16; /* tx_tries 0 */
|
||||
|
||||
for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
|
||||
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
|
||||
|
||||
/* for AR9300 family 13 descriptor words */
|
||||
if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
|
||||
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
|
||||
|
||||
data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
|
||||
(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,
|
||||
|
||||
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) {
|
||||
/* Pattern 0-3 uses AR_WOW_LENGTH1 register */
|
||||
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
|
||||
@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
|
||||
{
|
||||
u32 wow_status = 0;
|
||||
u32 val = 0, rval;
|
||||
|
||||
/*
|
||||
* read the WoW status register to know
|
||||
* the wakeup reason
|
||||
@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
|
||||
val &= ah->wow_event_mask;
|
||||
|
||||
if (val) {
|
||||
|
||||
if (val & AR_WOW_MAGIC_PAT_FOUND)
|
||||
wow_status |= AH_WOW_MAGIC_PATTERN_EN;
|
||||
|
||||
if (AR_WOW_PATTERN_FOUND(val))
|
||||
wow_status |= AH_WOW_USER_PATTERN_EN;
|
||||
|
||||
if (val & AR_WOW_KEEP_ALIVE_FAIL)
|
||||
wow_status |= AH_WOW_LINK_CHANGE;
|
||||
|
||||
if (val & AR_WOW_BEACON_FAIL)
|
||||
wow_status |= AH_WOW_BEACON_MISS;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -254,17 +218,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
|
||||
REG_WRITE(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
|
||||
*/
|
||||
@ -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 from the bus will not reset our chip
|
||||
*/
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress)
|
||||
if (ah->is_pciexpress)
|
||||
ath9k_hw_configpcipowersave(ah, false);
|
||||
|
||||
ah->wow_event_mask = 0;
|
||||
@ -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
|
||||
* 'pattern_count' of ath9k_hw_wow_apply_pattern()
|
||||
*/
|
||||
|
||||
wow_event_mask = ah->wow_event_mask;
|
||||
|
||||
/*
|
||||
@ -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
|
||||
* our hw state
|
||||
*/
|
||||
|
||||
if (ah->is_pciexpress) {
|
||||
|
||||
/*
|
||||
* we need to untie the internal POR (power-on-reset)
|
||||
* to the external PCI-E reset. We also need to tie
|
||||
* the PCI-E Phy reset to the PCI-E reset.
|
||||
*/
|
||||
|
||||
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
|
||||
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);
|
||||
|
||||
}
|
||||
set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
|
||||
clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
|
||||
REG_RMW(ah, AR_WA, set, clr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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,
|
||||
* beacon miss timeout, KAL timeout, etc.
|
||||
*/
|
||||
|
||||
set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
|
||||
REG_SET_BIT(ah, AR_WOW_PATTERN, set);
|
||||
|
||||
@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
||||
/*
|
||||
* Keep alive timo in ms except AR9280
|
||||
*/
|
||||
if (!pattern_enable || AR_SREV_9280(ah))
|
||||
if (!pattern_enable)
|
||||
set = AR_WOW_KEEP_ALIVE_NEVER;
|
||||
else
|
||||
set = KAL_TIMEOUT * 32;
|
||||
@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
||||
/*
|
||||
* Configure MAC WoW Registers
|
||||
*/
|
||||
|
||||
set = 0;
|
||||
/* Send keep alive timeouts anyway */
|
||||
clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
|
||||
@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
||||
else
|
||||
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;
|
||||
|
||||
REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
|
||||
|
||||
|
||||
/*
|
||||
* we are relying on a bmiss failure. ensure we have
|
||||
* enough threshold to prevent false positives
|
||||
@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
||||
set |= AR_WOW_MAC_INTR_EN;
|
||||
REG_RMW(ah, AR_WOW_PATTERN, set, clr);
|
||||
|
||||
/*
|
||||
* For AR9285 and later version of chipsets
|
||||
* 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);
|
||||
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
|
||||
AR_WOW_PATTERN_SUPPORTED);
|
||||
|
||||
/*
|
||||
* Set the power states appropriately and enable PME
|
||||
@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
||||
clr = 0;
|
||||
set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
|
||||
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);
|
||||
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
|
||||
/*
|
||||
* this is needed to prevent the chip waking up
|
||||
* the host within 3-4 seconds with certain
|
||||
* platform/BIOS. The fix is to enable
|
||||
* D1 & D3 to match original definition and
|
||||
* also match the OTP value. Anyway this
|
||||
* is more related to SW WOW.
|
||||
*/
|
||||
clr = AR_PMCTRL_PWR_STATE_D1D3;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* this is needed to prevent the chip waking up
|
||||
* the host within 3-4 seconds with certain
|
||||
* platform/BIOS. The fix is to enable
|
||||
* D1 & D3 to match original definition and
|
||||
* also match the OTP value. Anyway this
|
||||
* is more related to SW WOW.
|
||||
*/
|
||||
clr = AR_PMCTRL_PWR_STATE_D1D3;
|
||||
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);
|
||||
|
||||
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 */
|
||||
set = BIT(13);
|
||||
REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
|
||||
/* HW WoW */
|
||||
clr = BIT(5);
|
||||
REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
|
||||
}
|
||||
/* to bring down WOW power low margin */
|
||||
set = BIT(13);
|
||||
REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
|
||||
/* HW WoW */
|
||||
clr = BIT(5);
|
||||
REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
|
||||
|
||||
ath9k_hw_set_powermode_wow_sleep(ah);
|
||||
ah->wow_event_mask = wow_event_mask;
|
||||
|
@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
|
||||
if (supr_status) {
|
||||
update_rate = false;
|
||||
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",
|
||||
__func__, CHSPEC_CHANNEL(
|
||||
wlc->default_bss->chanspec));
|
||||
|
@ -13,34 +13,18 @@ config CW1200_WLAN_SDIO
|
||||
depends on CW1200 && MMC
|
||||
help
|
||||
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
|
||||
tristate "Support SPI platforms"
|
||||
depends on CW1200 && SPI
|
||||
help
|
||||
Enables support for the CW1200 connected via a SPI bus.
|
||||
|
||||
config CW1200_WLAN_SAGRAD
|
||||
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
|
||||
Enables support for the CW1200 connected via a SPI bus. You will
|
||||
need to add appropriate platform data glue in your board setup
|
||||
file.
|
||||
|
||||
endif
|
||||
|
@ -8,17 +8,14 @@ cw1200_core-y := \
|
||||
wsm.o \
|
||||
sta.o \
|
||||
scan.o \
|
||||
pm.o \
|
||||
debug.o
|
||||
cw1200_core-$(CONFIG_CW1200_ITP) += itp.o
|
||||
cw1200_core-$(CONFIG_PM) += pm.o
|
||||
|
||||
# CFLAGS_sta.o += -DDEBUG
|
||||
|
||||
cw1200_wlan_sdio-y := cw1200_sdio.o
|
||||
cw1200_wlan_spi-y := cw1200_spi.o
|
||||
cw1200_wlan_sagrad-y := cw1200_sagrad.o
|
||||
|
||||
obj-$(CONFIG_CW1200) += cw1200_core.o
|
||||
obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o
|
||||
obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o
|
||||
obj-$(CONFIG_CW1200_WLAN_SAGRAD) += cw1200_wlan_sagrad.o
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "bh.h"
|
||||
#include "hwio.h"
|
||||
#include "wsm.h"
|
||||
#include "sbus.h"
|
||||
#include "hwbus.h"
|
||||
#include "debug.h"
|
||||
#include "fwio.h"
|
||||
|
||||
@ -31,7 +31,8 @@ static int cw1200_bh(void *arg);
|
||||
|
||||
#define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4)
|
||||
/* 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 PIGGYBACK_CTRL_REG (2)
|
||||
#define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG)
|
||||
@ -103,7 +104,7 @@ void cw1200_irq_handler(struct cw1200_common *priv)
|
||||
pr_debug("[BH] irq.\n");
|
||||
|
||||
/* Disable Interrupts! */
|
||||
/* NOTE: sbus_ops->lock already held */
|
||||
/* NOTE: hwbus_ops->lock already held */
|
||||
__cw1200_irq_enable(priv, 0);
|
||||
|
||||
if (/* WARN_ON */(priv->bh_error))
|
||||
@ -217,7 +218,8 @@ static int cw1200_device_wakeup(struct cw1200_common *priv)
|
||||
return ret;
|
||||
|
||||
/* 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) {
|
||||
pr_debug("[BH] Device awake.\n");
|
||||
return 1;
|
||||
@ -262,11 +264,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
alloc_len = priv->sbus_ops->align_size(
|
||||
priv->sbus_priv, read_len);
|
||||
alloc_len = priv->hwbus_ops->align_size(
|
||||
priv->hwbus_priv, read_len);
|
||||
|
||||
/* Check if not exceeding CW1200 capabilities */
|
||||
if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) {
|
||||
@ -384,8 +387,8 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv,
|
||||
|
||||
atomic_add(1, &priv->bh_tx);
|
||||
|
||||
tx_len = priv->sbus_ops->align_size(
|
||||
priv->sbus_priv, tx_len);
|
||||
tx_len = priv->hwbus_ops->align_size(
|
||||
priv->hwbus_priv, tx_len);
|
||||
|
||||
/* Check if not exceeding CW1200 capabilities */
|
||||
if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE))
|
||||
@ -597,15 +600,15 @@ static int cw1200_bh(void *arg)
|
||||
|
||||
done:
|
||||
/* Re-enable device interrupts */
|
||||
priv->sbus_ops->lock(priv->sbus_priv);
|
||||
priv->hwbus_ops->lock(priv->hwbus_priv);
|
||||
__cw1200_irq_enable(priv, 1);
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
}
|
||||
|
||||
/* Explicitly disable device interrupts */
|
||||
priv->sbus_ops->lock(priv->sbus_priv);
|
||||
priv->hwbus_ops->lock(priv->hwbus_priv);
|
||||
__cw1200_irq_enable(priv, 0);
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
|
||||
if (!term) {
|
||||
pr_err("[BH] Fatal error, exiting.\n");
|
||||
|
@ -19,7 +19,6 @@
|
||||
#define CW1200_H
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/mac80211.h>
|
||||
@ -31,16 +30,11 @@
|
||||
#include "pm.h"
|
||||
|
||||
/* Forward declarations */
|
||||
struct sbus_ops;
|
||||
struct hwbus_ops;
|
||||
struct task_struct;
|
||||
struct cw1200_debug_priv;
|
||||
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_STA_IN_AP_MODE (5)
|
||||
@ -110,8 +104,8 @@ struct cw1200_common {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
||||
/* Hardware interface */
|
||||
const struct sbus_ops *sbus_ops;
|
||||
struct sbus_priv *sbus_priv;
|
||||
const struct hwbus_ops *hwbus_ops;
|
||||
struct hwbus_priv *hwbus_priv;
|
||||
|
||||
/* Hardware information */
|
||||
enum {
|
||||
@ -213,7 +207,8 @@ struct cw1200_common {
|
||||
/* Scan status */
|
||||
struct cw1200_scan scan;
|
||||
/* 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;
|
||||
struct delayed_work clear_recent_scan_work;
|
||||
|
||||
@ -288,10 +283,6 @@ struct cw1200_common {
|
||||
struct work_struct linkid_reset_work;
|
||||
u8 action_frame_sa[ETH_ALEN];
|
||||
u8 action_linkid;
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
struct sk_buff_head etf_q;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct cw1200_sta_priv {
|
||||
@ -299,8 +290,8 @@ struct cw1200_sta_priv {
|
||||
};
|
||||
|
||||
/* interfaces for the drivers */
|
||||
int cw1200_core_probe(const struct sbus_ops *sbus_ops,
|
||||
struct sbus_priv *sbus,
|
||||
int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
|
||||
struct hwbus_priv *hwbus,
|
||||
struct device *pdev,
|
||||
struct cw1200_common **pself,
|
||||
int ref_clk, const u8 *macaddr,
|
||||
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* 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 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
@ -20,8 +19,8 @@
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "cw1200.h"
|
||||
#include "sbus.h"
|
||||
#include <linux/cw1200_platform.h>
|
||||
#include "hwbus.h"
|
||||
#include <linux/platform_data/net-cw1200.h>
|
||||
#include "hwio.h"
|
||||
|
||||
MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
|
||||
@ -30,7 +29,22 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
#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 cw1200_common *core;
|
||||
const struct cw1200_platform_data_sdio *pdata;
|
||||
@ -49,35 +63,35 @@ static const struct sdio_device_id cw1200_sdio_ids[] = {
|
||||
{ /* 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,
|
||||
void *dst, int 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,
|
||||
const void *src, int 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);
|
||||
}
|
||||
|
||||
static void cw1200_sdio_unlock(struct sbus_priv *self)
|
||||
static void cw1200_sdio_unlock(struct hwbus_priv *self)
|
||||
{
|
||||
sdio_release_host(self->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. */
|
||||
if (self->core)
|
||||
@ -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)
|
||||
{
|
||||
struct sbus_priv *self = dev_id;
|
||||
struct hwbus_priv *self = dev_id;
|
||||
|
||||
if (self->core) {
|
||||
sdio_claim_host(self->func);
|
||||
@ -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;
|
||||
const struct resource *irq = self->pdata->irq;
|
||||
u8 cccr;
|
||||
|
||||
cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
|
||||
@ -123,15 +136,15 @@ static int cw1200_request_irq(struct sbus_priv *self)
|
||||
if (WARN_ON(ret))
|
||||
goto err;
|
||||
|
||||
ret = enable_irq_wake(irq->start);
|
||||
ret = enable_irq_wake(self->pdata->irq);
|
||||
if (WARN_ON(ret))
|
||||
goto err;
|
||||
|
||||
/* 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,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
irq->name, self);
|
||||
"cw1200_wlan_irq", self);
|
||||
if (WARN_ON(ret))
|
||||
goto err;
|
||||
|
||||
@ -141,7 +154,7 @@ static int cw1200_request_irq(struct sbus_priv *self)
|
||||
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;
|
||||
|
||||
@ -156,15 +169,15 @@ static int cw1200_sdio_irq_subscribe(struct sbus_priv *self)
|
||||
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;
|
||||
|
||||
pr_debug("SW IRQ unsubscribe\n");
|
||||
|
||||
if (self->pdata->irq) {
|
||||
disable_irq_wake(self->pdata->irq->start);
|
||||
free_irq(self->pdata->irq->start, self);
|
||||
disable_irq_wake(self->pdata->irq);
|
||||
free_irq(self->pdata->irq, self);
|
||||
} else {
|
||||
sdio_claim_host(self->func);
|
||||
ret = sdio_release_irq(self->func);
|
||||
@ -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)
|
||||
{
|
||||
const struct resource *reset = pdata->reset;
|
||||
|
||||
if (reset) {
|
||||
gpio_set_value(reset->start, 0);
|
||||
if (pdata->reset) {
|
||||
gpio_set_value(pdata->reset, 0);
|
||||
msleep(30); /* Min is 2 * CLK32K cycles */
|
||||
gpio_free(reset->start);
|
||||
gpio_free(pdata->reset);
|
||||
}
|
||||
|
||||
if (pdata->power_ctrl)
|
||||
@ -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)
|
||||
{
|
||||
const struct resource *reset = pdata->reset;
|
||||
const struct resource *powerup = pdata->reset;
|
||||
|
||||
/* Ensure I/Os are pulled low */
|
||||
if (reset) {
|
||||
gpio_request(reset->start, reset->name);
|
||||
gpio_direction_output(reset->start, 0);
|
||||
if (pdata->reset) {
|
||||
gpio_request(pdata->reset, "cw1200_wlan_reset");
|
||||
gpio_direction_output(pdata->reset, 0);
|
||||
}
|
||||
if (powerup) {
|
||||
gpio_request(powerup->start, powerup->name);
|
||||
gpio_direction_output(powerup->start, 0);
|
||||
if (pdata->powerup) {
|
||||
gpio_request(pdata->powerup, "cw1200_wlan_powerup");
|
||||
gpio_direction_output(pdata->powerup, 0);
|
||||
}
|
||||
if (reset || powerup)
|
||||
msleep(50); /* Settle time */
|
||||
if (pdata->reset || pdata->powerup)
|
||||
msleep(10); /* Settle time? */
|
||||
|
||||
/* Enable 3v3 and 1v8 to hardware */
|
||||
if (pdata->power_ctrl) {
|
||||
@ -226,19 +234,19 @@ static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
|
||||
}
|
||||
|
||||
/* Enable POWERUP signal */
|
||||
if (powerup) {
|
||||
gpio_set_value(powerup->start, 1);
|
||||
if (pdata->powerup) {
|
||||
gpio_set_value(pdata->powerup, 1);
|
||||
msleep(250); /* or more..? */
|
||||
}
|
||||
/* Enable RSTn signal */
|
||||
if (reset) {
|
||||
gpio_set_value(reset->start, 1);
|
||||
if (pdata->reset) {
|
||||
gpio_set_value(pdata->reset, 1);
|
||||
msleep(50); /* Or more..? */
|
||||
}
|
||||
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)
|
||||
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)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static struct sbus_ops cw1200_sdio_sbus_ops = {
|
||||
.sbus_memcpy_fromio = cw1200_sdio_memcpy_fromio,
|
||||
.sbus_memcpy_toio = cw1200_sdio_memcpy_toio,
|
||||
static struct hwbus_ops cw1200_sdio_hwbus_ops = {
|
||||
.hwbus_memcpy_fromio = cw1200_sdio_memcpy_fromio,
|
||||
.hwbus_memcpy_toio = cw1200_sdio_memcpy_toio,
|
||||
.lock = cw1200_sdio_lock,
|
||||
.unlock = cw1200_sdio_unlock,
|
||||
.align_size = cw1200_sdio_align_size,
|
||||
@ -268,26 +276,26 @@ static struct sbus_ops cw1200_sdio_sbus_ops = {
|
||||
|
||||
/* Probe Function to be called by SDIO stack when device is discovered */
|
||||
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;
|
||||
|
||||
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)
|
||||
return -ENODEV;
|
||||
|
||||
self = kzalloc(sizeof(*self), GFP_KERNEL);
|
||||
if (!self) {
|
||||
pr_err("Can't allocate SDIO sbus_priv.\n");
|
||||
pr_err("Can't allocate SDIO hwbus_priv.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
|
||||
|
||||
self->pdata = cw1200_get_platform_data();
|
||||
self->pdata = global_plat_data; /* FIXME */
|
||||
self->func = func;
|
||||
sdio_set_drvdata(func, self);
|
||||
sdio_claim_host(func);
|
||||
@ -296,7 +304,7 @@ static int cw1200_sdio_probe(struct sdio_func *func,
|
||||
|
||||
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->pdata->ref_clk,
|
||||
self->pdata->macaddr,
|
||||
@ -315,10 +323,11 @@ static int cw1200_sdio_probe(struct sdio_func *func,
|
||||
}
|
||||
|
||||
/* Disconnect Function to be called by SDIO stack when
|
||||
* device is disconnected */
|
||||
* device is disconnected
|
||||
*/
|
||||
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) {
|
||||
cw1200_sdio_irq_unsubscribe(self);
|
||||
@ -334,11 +343,12 @@ static void cw1200_sdio_disconnect(struct sdio_func *func)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int cw1200_sdio_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
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))
|
||||
return -EAGAIN;
|
||||
@ -360,15 +370,18 @@ static const struct dev_pm_ops cw1200_pm_ops = {
|
||||
.suspend = cw1200_sdio_suspend,
|
||||
.resume = cw1200_sdio_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct sdio_driver sdio_driver = {
|
||||
.name = "cw1200_wlan_sdio",
|
||||
.id_table = cw1200_sdio_ids,
|
||||
.probe = cw1200_sdio_probe,
|
||||
.remove = cw1200_sdio_disconnect,
|
||||
#ifdef CONFIG_PM
|
||||
.drv = {
|
||||
.pm = &cw1200_pm_ops,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Init Module function -> Called by insmod */
|
||||
@ -377,7 +390,8 @@ static int __init cw1200_sdio_init(void)
|
||||
const struct cw1200_platform_data_sdio *pdata;
|
||||
int ret;
|
||||
|
||||
pdata = cw1200_get_platform_data();
|
||||
/* FIXME -- this won't support multiple devices */
|
||||
pdata = global_plat_data;
|
||||
|
||||
if (cw1200_sdio_on(pdata)) {
|
||||
ret = -1;
|
||||
@ -399,7 +413,9 @@ static int __init cw1200_sdio_init(void)
|
||||
static void __exit cw1200_sdio_exit(void)
|
||||
{
|
||||
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);
|
||||
cw1200_sdio_off(pdata);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
@ -25,8 +24,8 @@
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "cw1200.h"
|
||||
#include "sbus.h"
|
||||
#include <linux/cw1200_platform.h>
|
||||
#include "hwbus.h"
|
||||
#include <linux/platform_data/net-cw1200.h>
|
||||
#include "hwio.h"
|
||||
|
||||
MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
|
||||
@ -36,7 +35,7 @@ MODULE_ALIAS("spi:cw1200_wlan_spi");
|
||||
|
||||
/* #define SPI_DEBUG */
|
||||
|
||||
struct sbus_priv {
|
||||
struct hwbus_priv {
|
||||
struct spi_device *func;
|
||||
struct cw1200_common *core;
|
||||
const struct cw1200_platform_data_spi *pdata;
|
||||
@ -48,18 +47,16 @@ struct sbus_priv {
|
||||
#define SET_WRITE 0x7FFF /* usage: and operation */
|
||||
#define SET_READ 0x8000 /* usage: or operation */
|
||||
|
||||
/*
|
||||
Notes on byte ordering:
|
||||
/* Notes on byte ordering:
|
||||
LE: B0 B1 B2 B3
|
||||
BE: B3 B2 B1 B0
|
||||
|
||||
Hardware expects 32-bit data to be written as 16-bit BE words:
|
||||
|
||||
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,
|
||||
void *dst, int count)
|
||||
{
|
||||
@ -120,7 +117,7 @@ static int cw1200_spi_memcpy_fromio(struct sbus_priv *self,
|
||||
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,
|
||||
const void *src, int count)
|
||||
{
|
||||
@ -188,7 +185,7 @@ static int cw1200_spi_memcpy_toio(struct sbus_priv *self,
|
||||
return rval;
|
||||
}
|
||||
|
||||
static void cw1200_spi_lock(struct sbus_priv *self)
|
||||
static void cw1200_spi_lock(struct hwbus_priv *self)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -210,7 +207,7 @@ static void cw1200_spi_lock(struct sbus_priv *self)
|
||||
return;
|
||||
}
|
||||
|
||||
static void cw1200_spi_unlock(struct sbus_priv *self)
|
||||
static void cw1200_spi_unlock(struct hwbus_priv *self)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
struct sbus_priv *self = dev_id;
|
||||
struct hwbus_priv *self = dev_id;
|
||||
|
||||
if (self->core) {
|
||||
cw1200_irq_handler(self->core);
|
||||
@ -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;
|
||||
|
||||
@ -256,7 +253,7 @@ static int cw1200_spi_irq_subscribe(struct sbus_priv *self)
|
||||
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;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
const struct resource *reset = pdata->reset;
|
||||
|
||||
if (reset) {
|
||||
gpio_set_value(reset->start, 0);
|
||||
if (pdata->reset) {
|
||||
gpio_set_value(pdata->reset, 0);
|
||||
msleep(30); /* Min is 2 * CLK32K cycles */
|
||||
gpio_free(reset->start);
|
||||
gpio_free(pdata->reset);
|
||||
}
|
||||
|
||||
if (pdata->power_ctrl)
|
||||
@ -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)
|
||||
{
|
||||
const struct resource *reset = pdata->reset;
|
||||
const struct resource *powerup = pdata->reset;
|
||||
|
||||
/* Ensure I/Os are pulled low */
|
||||
if (reset) {
|
||||
gpio_request(reset->start, reset->name);
|
||||
gpio_direction_output(reset->start, 0);
|
||||
if (pdata->reset) {
|
||||
gpio_request(pdata->reset, "cw1200_wlan_reset");
|
||||
gpio_direction_output(pdata->reset, 0);
|
||||
}
|
||||
if (powerup) {
|
||||
gpio_request(powerup->start, powerup->name);
|
||||
gpio_direction_output(powerup->start, 0);
|
||||
if (pdata->powerup) {
|
||||
gpio_request(pdata->powerup, "cw1200_wlan_powerup");
|
||||
gpio_direction_output(pdata->powerup, 0);
|
||||
}
|
||||
if (reset || powerup)
|
||||
if (pdata->reset || pdata->powerup)
|
||||
msleep(10); /* Settle time? */
|
||||
|
||||
/* Enable 3v3 and 1v8 to hardware */
|
||||
@ -320,31 +312,31 @@ static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
|
||||
}
|
||||
|
||||
/* Enable POWERUP signal */
|
||||
if (powerup) {
|
||||
gpio_set_value(powerup->start, 1);
|
||||
if (pdata->powerup) {
|
||||
gpio_set_value(pdata->powerup, 1);
|
||||
msleep(250); /* or more..? */
|
||||
}
|
||||
/* Enable RSTn signal */
|
||||
if (reset) {
|
||||
gpio_set_value(reset->start, 1);
|
||||
if (pdata->reset) {
|
||||
gpio_set_value(pdata->reset, 1);
|
||||
msleep(50); /* Or more..? */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static struct sbus_ops cw1200_spi_sbus_ops = {
|
||||
.sbus_memcpy_fromio = cw1200_spi_memcpy_fromio,
|
||||
.sbus_memcpy_toio = cw1200_spi_memcpy_toio,
|
||||
static struct hwbus_ops cw1200_spi_hwbus_ops = {
|
||||
.hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio,
|
||||
.hwbus_memcpy_toio = cw1200_spi_memcpy_toio,
|
||||
.lock = cw1200_spi_lock,
|
||||
.unlock = cw1200_spi_unlock,
|
||||
.align_size = cw1200_spi_align_size,
|
||||
@ -356,7 +348,7 @@ static int cw1200_spi_probe(struct spi_device *func)
|
||||
{
|
||||
const struct cw1200_platform_data_spi *plat_data =
|
||||
func->dev.platform_data;
|
||||
struct sbus_priv *self;
|
||||
struct hwbus_priv *self;
|
||||
int status;
|
||||
|
||||
/* Sanity check speed */
|
||||
@ -390,7 +382,7 @@ static int cw1200_spi_probe(struct spi_device *func)
|
||||
|
||||
self = kzalloc(sizeof(*self), GFP_KERNEL);
|
||||
if (!self) {
|
||||
pr_err("Can't allocate SPI sbus_priv.");
|
||||
pr_err("Can't allocate SPI hwbus_priv.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -402,7 +394,7 @@ static int cw1200_spi_probe(struct spi_device *func)
|
||||
|
||||
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->pdata->ref_clk,
|
||||
self->pdata->macaddr,
|
||||
@ -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 */
|
||||
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) {
|
||||
cw1200_spi_irq_unsubscribe(self);
|
||||
@ -436,9 +428,10 @@ static int cw1200_spi_disconnect(struct spi_device *func)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
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))
|
||||
return -EAGAIN;
|
||||
@ -451,6 +444,7 @@ static int cw1200_spi_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct spi_driver spi_driver = {
|
||||
.probe = cw1200_spi_probe,
|
||||
@ -459,22 +453,11 @@ static struct spi_driver spi_driver = {
|
||||
.name = "cw1200_wlan_spi",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cw1200_spi_suspend,
|
||||
.resume = cw1200_spi_resume,
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
/* Init Module function -> Called by insmod */
|
||||
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);
|
||||
module_spi_driver(spi_driver);
|
||||
|
@ -357,140 +357,6 @@ static const struct file_operations fops_counters = {
|
||||
.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,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
@ -511,7 +377,7 @@ static ssize_t cw1200_wsm_dumps(struct file *file,
|
||||
}
|
||||
|
||||
static const struct file_operations fops_wsm_dumps = {
|
||||
.open = cw1200_generic_open,
|
||||
.open = simple_open,
|
||||
.write = cw1200_wsm_dumps,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
@ -538,27 +404,10 @@ int cw1200_debug_init(struct cw1200_common *priv)
|
||||
priv, &fops_counters))
|
||||
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,
|
||||
priv, &fops_wsm_dumps))
|
||||
goto err;
|
||||
|
||||
ret = cw1200_itp_init(priv);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -572,93 +421,8 @@ void cw1200_debug_release(struct cw1200_common *priv)
|
||||
{
|
||||
struct cw1200_debug_priv *d = priv->debug;
|
||||
if (d) {
|
||||
cw1200_itp_release(priv);
|
||||
debugfs_remove_recursive(d->debugfs_phy);
|
||||
priv->debug = NULL;
|
||||
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 @@
|
||||
#ifndef CW1200_DEBUG_H_INCLUDED
|
||||
#define CW1200_DEBUG_H_INCLUDED
|
||||
|
||||
#include "itp.h"
|
||||
|
||||
struct cw1200_debug_priv {
|
||||
struct dentry *debugfs_phy;
|
||||
int tx;
|
||||
@ -30,9 +28,6 @@ struct cw1200_debug_priv {
|
||||
int ba_acc;
|
||||
int ba_cnt_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);
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "cw1200.h"
|
||||
#include "fwio.h"
|
||||
#include "hwio.h"
|
||||
#include "sbus.h"
|
||||
#include "hwbus.h"
|
||||
#include "bh.h"
|
||||
|
||||
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)
|
||||
val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT;
|
||||
REG_WRITE(ST90TDS_CONFIG_REG_ID, val32);
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
if (etf_mode)
|
||||
fw_path = etf_firmware;
|
||||
#endif
|
||||
|
||||
/* Load a firmware file */
|
||||
ret = request_firmware(&firmware, fw_path, priv->pdev);
|
||||
if (ret) {
|
||||
@ -489,9 +484,9 @@ int cw1200_load_firmware(struct cw1200_common *priv)
|
||||
}
|
||||
|
||||
/* Enable interrupt signalling */
|
||||
priv->sbus_ops->lock(priv->sbus_priv);
|
||||
priv->hwbus_ops->lock(priv->hwbus_priv);
|
||||
ret = __cw1200_irq_enable(priv, 1);
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
if (ret < 0)
|
||||
goto unsubscribe;
|
||||
|
||||
@ -518,8 +513,8 @@ int cw1200_load_firmware(struct cw1200_common *priv)
|
||||
|
||||
unsubscribe:
|
||||
/* Disable interrupt signalling */
|
||||
priv->sbus_ops->lock(priv->sbus_priv);
|
||||
priv->hwbus_ops->lock(priv->hwbus_priv);
|
||||
ret = __cw1200_irq_enable(priv, 0);
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
return ret;
|
||||
}
|
||||
|
33
drivers/net/wireless/cw1200/hwbus.h
Normal file
33
drivers/net/wireless/cw1200/hwbus.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Common hwbus abstraction layer interface for cw1200 wireless driver
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CW1200_HWBUS_H
|
||||
#define CW1200_HWBUS_H
|
||||
|
||||
struct hwbus_priv;
|
||||
|
||||
void cw1200_irq_handler(struct cw1200_common *priv);
|
||||
|
||||
/* This MUST be wrapped with hwbus_ops->lock/unlock! */
|
||||
int __cw1200_irq_enable(struct cw1200_common *priv, int enable);
|
||||
|
||||
struct hwbus_ops {
|
||||
int (*hwbus_memcpy_fromio)(struct hwbus_priv *self, unsigned int addr,
|
||||
void *dst, int count);
|
||||
int (*hwbus_memcpy_toio)(struct hwbus_priv *self, unsigned int addr,
|
||||
const void *src, int count);
|
||||
void (*lock)(struct hwbus_priv *self);
|
||||
void (*unlock)(struct hwbus_priv *self);
|
||||
size_t (*align_size)(struct hwbus_priv *self, size_t size);
|
||||
int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
|
||||
};
|
||||
|
||||
#endif /* CW1200_HWBUS_H */
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "cw1200.h"
|
||||
#include "hwio.h"
|
||||
#include "sbus.h"
|
||||
#include "hwbus.h"
|
||||
|
||||
/* Sdio addr is 4*spi_addr */
|
||||
#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,
|
||||
addr_sdio = SPI_REG_ADDR_TO_SDIO(addr);
|
||||
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,
|
||||
buf, buf_len);
|
||||
}
|
||||
@ -61,7 +61,7 @@ static int __cw1200_reg_write(struct cw1200_common *priv, u16 addr,
|
||||
addr_sdio = SPI_REG_ADDR_TO_SDIO(addr);
|
||||
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,
|
||||
buf, buf_len);
|
||||
}
|
||||
@ -100,9 +100,9 @@ int cw1200_reg_read(struct cw1200_common *priv, u16 addr, void *buf,
|
||||
size_t buf_len)
|
||||
{
|
||||
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);
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -110,9 +110,9 @@ int cw1200_reg_write(struct cw1200_common *priv, u16 addr, const void *buf,
|
||||
size_t buf_len)
|
||||
{
|
||||
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);
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len)
|
||||
int ret, retry = 1;
|
||||
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) {
|
||||
ret = __cw1200_reg_read(priv,
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf,
|
||||
int ret, retry = 1;
|
||||
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) {
|
||||
ret = __cw1200_reg_write(priv,
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -178,10 +178,9 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf,
|
||||
if ((buf_len / 2) >= 0x1000) {
|
||||
pr_err("Can't read more than 0xfff words.\n");
|
||||
return -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->sbus_ops->lock(priv->sbus_priv);
|
||||
priv->hwbus_ops->lock(priv->hwbus_priv);
|
||||
/* Write address */
|
||||
ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr);
|
||||
if (ret < 0) {
|
||||
@ -230,7 +229,7 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf,
|
||||
}
|
||||
|
||||
out:
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -244,7 +243,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->sbus_ops->lock(priv->sbus_priv);
|
||||
priv->hwbus_ops->lock(priv->hwbus_priv);
|
||||
|
||||
/* Write address */
|
||||
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,
|
||||
}
|
||||
|
||||
out:
|
||||
priv->sbus_ops->unlock(priv->sbus_priv);
|
||||
priv->hwbus_ops->unlock(priv->hwbus_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -97,9 +97,8 @@ struct download_cntl_t {
|
||||
|
||||
#define CW1200_APB(addr) (PAC_SHARED_MEMORY_SILICON + (addr))
|
||||
|
||||
/* ***************************************************************
|
||||
*Device register definitions
|
||||
*************************************************************** */
|
||||
/* Device register definitions */
|
||||
|
||||
/* WBF - SPI Register Addresses */
|
||||
#define ST90TDS_ADDR_ID_BASE (0x0000)
|
||||
/* 16/32 bits */
|
||||
|
@ -1,730 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* 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 @@
|
||||
|
||||
#include "cw1200.h"
|
||||
#include "txrx.h"
|
||||
#include "sbus.h"
|
||||
#include "hwbus.h"
|
||||
#include "fwio.h"
|
||||
#include "hwio.h"
|
||||
#include "bh.h"
|
||||
@ -61,12 +61,6 @@ int cw1200_power_mode = wsm_power_mode_quiescent;
|
||||
module_param(cw1200_power_mode, int, 0644);
|
||||
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) \
|
||||
{ \
|
||||
.bitrate = (_rate), \
|
||||
@ -234,8 +228,10 @@ static const struct ieee80211_ops cw1200_ops = {
|
||||
.get_stats = cw1200_get_stats,
|
||||
.ampdu_action = cw1200_ampdu_action,
|
||||
.flush = cw1200_flush,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cw1200_wow_suspend,
|
||||
.resume = cw1200_wow_resume,
|
||||
#endif
|
||||
/* Intentionally not offloaded: */
|
||||
/*.channel_switch = cw1200_channel_switch, */
|
||||
/*.remain_on_channel = cw1200_remain_on_channel, */
|
||||
@ -292,10 +288,12 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* Support only for limited wowlan functionalities */
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
|
||||
WIPHY_WOWLAN_DISCONNECT;
|
||||
hw->wiphy->wowlan.n_patterns = 0;
|
||||
#endif
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
|
||||
@ -414,29 +412,25 @@ static int cw1200_register_common(struct ieee80211_hw *dev)
|
||||
struct cw1200_common *priv = dev->priv;
|
||||
int err;
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
if (etf_mode)
|
||||
goto done;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
err = cw1200_pm_init(&priv->pm_state, priv);
|
||||
if (err) {
|
||||
pr_err("Cannot init PM. (%d).\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ieee80211_register_hw(dev);
|
||||
if (err) {
|
||||
pr_err("Cannot register device (%d).\n",
|
||||
err);
|
||||
#ifdef CONFIG_PM
|
||||
cw1200_pm_deinit(&priv->pm_state);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
done:
|
||||
#endif
|
||||
cw1200_debug_init(priv);
|
||||
|
||||
pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
|
||||
@ -453,13 +447,7 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev)
|
||||
struct cw1200_common *priv = dev->priv;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
if (!etf_mode) {
|
||||
#endif
|
||||
ieee80211_unregister_hw(dev);
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
}
|
||||
#endif
|
||||
ieee80211_unregister_hw(dev);
|
||||
|
||||
del_timer_sync(&priv->mcast_timeout);
|
||||
cw1200_unregister_bh(priv);
|
||||
@ -482,7 +470,9 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev)
|
||||
cw1200_queue_deinit(&priv->tx_queue[i]);
|
||||
|
||||
cw1200_queue_stats_deinit(&priv->tx_queue_stats);
|
||||
#ifdef CONFIG_PM
|
||||
cw1200_pm_deinit(&priv->pm_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Clock is in KHz */
|
||||
@ -518,8 +508,8 @@ u32 cw1200_dpll_from_clk(u16 clk_khz)
|
||||
}
|
||||
}
|
||||
|
||||
int cw1200_core_probe(const struct sbus_ops *sbus_ops,
|
||||
struct sbus_priv *sbus,
|
||||
int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
|
||||
struct hwbus_priv *hwbus,
|
||||
struct device *pdev,
|
||||
struct cw1200_common **core,
|
||||
int ref_clk, const u8 *macaddr,
|
||||
@ -546,8 +536,8 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
|
||||
if (cw1200_sdd_path)
|
||||
priv->sdd_path = cw1200_sdd_path;
|
||||
|
||||
priv->sbus_ops = sbus_ops;
|
||||
priv->sbus_priv = sbus;
|
||||
priv->hwbus_ops = hwbus_ops;
|
||||
priv->hwbus_priv = hwbus;
|
||||
priv->pdev = pdev;
|
||||
SET_IEEE80211_DEV(priv->hw, pdev);
|
||||
|
||||
@ -558,11 +548,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
if (etf_mode)
|
||||
goto skip_fw;
|
||||
#endif
|
||||
|
||||
err = cw1200_load_firmware(priv);
|
||||
if (err)
|
||||
goto err2;
|
||||
@ -584,9 +569,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
|
||||
/* Enable multi-TX confirmation */
|
||||
wsm_use_multi_tx_conf(priv, true);
|
||||
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
skip_fw:
|
||||
#endif
|
||||
err = cw1200_register_common(dev);
|
||||
if (err)
|
||||
goto err2;
|
||||
@ -606,9 +588,9 @@ EXPORT_SYMBOL_GPL(cw1200_core_probe);
|
||||
void cw1200_core_release(struct cw1200_common *self)
|
||||
{
|
||||
/* Disable device interrupts */
|
||||
self->sbus_ops->lock(self->sbus_priv);
|
||||
self->hwbus_ops->lock(self->hwbus_priv);
|
||||
__cw1200_irq_enable(self, 0);
|
||||
self->sbus_ops->unlock(self->sbus_priv);
|
||||
self->hwbus_ops->unlock(self->hwbus_priv);
|
||||
|
||||
/* And then clean up */
|
||||
cw1200_unregister_common(self->hw);
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "pm.h"
|
||||
#include "sta.h"
|
||||
#include "bh.h"
|
||||
#include "sbus.h"
|
||||
#include "hwbus.h"
|
||||
|
||||
#define CW1200_BEACON_SKIPPING_MULTIPLIER 3
|
||||
|
||||
@ -264,7 +264,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
pm_state->suspend_state = state;
|
||||
|
||||
/* 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) {
|
||||
wiphy_err(priv->hw->wiphy,
|
||||
"PM request failed: %d. WoW is disabled.\n", ret);
|
||||
@ -313,7 +313,7 @@ int cw1200_wow_resume(struct ieee80211_hw *hw)
|
||||
pm_state->suspend_state = NULL;
|
||||
|
||||
/* 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
|
||||
* in case when BSS_LOST command arrived the processing of the
|
||||
|
@ -25,14 +25,19 @@ struct cw1200_pm_state {
|
||||
spinlock_t lock; /* Protect access */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int cw1200_pm_init(struct cw1200_pm_state *pm,
|
||||
struct cw1200_common *priv);
|
||||
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,
|
||||
struct cfg80211_wowlan *wowlan);
|
||||
int cw1200_wow_resume(struct ieee80211_hw *hw);
|
||||
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
|
||||
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Common sbus abstraction layer interface for cw1200 wireless driver
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CW1200_SBUS_H
|
||||
#define CW1200_SBUS_H
|
||||
|
||||
/*
|
||||
* sbus priv forward definition.
|
||||
* Implemented and instantiated in particular modules.
|
||||
*/
|
||||
struct sbus_priv;
|
||||
|
||||
void cw1200_irq_handler(struct cw1200_common *priv);
|
||||
|
||||
/* This MUST be wrapped with sbus_ops->lock/unlock! */
|
||||
int __cw1200_irq_enable(struct cw1200_common *priv, int enable);
|
||||
|
||||
struct sbus_ops {
|
||||
int (*sbus_memcpy_fromio)(struct sbus_priv *self, unsigned int addr,
|
||||
void *dst, int count);
|
||||
int (*sbus_memcpy_toio)(struct sbus_priv *self, unsigned int addr,
|
||||
const void *src, int count);
|
||||
void (*lock)(struct sbus_priv *self);
|
||||
void (*unlock)(struct sbus_priv *self);
|
||||
size_t (*align_size)(struct sbus_priv *self, size_t size);
|
||||
int (*power_mgmt)(struct sbus_priv *self, bool suspend);
|
||||
};
|
||||
|
||||
#endif /* CW1200_SBUS_H */
|
@ -483,15 +483,14 @@ void cw1200_update_filtering(struct cw1200_common *priv)
|
||||
bf_tbl.num = __cpu_to_le32(3);
|
||||
}
|
||||
|
||||
/*
|
||||
* When acting as p2p client being connected to p2p GO, in order to
|
||||
* receive frames from a different p2p device, turn off bssid filter.
|
||||
*
|
||||
* WARNING: FW dependency!
|
||||
* This can only be used with FW WSM371 and its successors.
|
||||
* In that FW version even with bssid filter turned off,
|
||||
* device will block most of the unwanted frames.
|
||||
*/
|
||||
/* When acting as p2p client being connected to p2p GO, in order to
|
||||
* receive frames from a different p2p device, turn off bssid filter.
|
||||
*
|
||||
* WARNING: FW dependency!
|
||||
* This can only be used with FW WSM371 and its successors.
|
||||
* In that FW version even with bssid filter turned off,
|
||||
* device will block most of the unwanted frames.
|
||||
*/
|
||||
if (is_p2p)
|
||||
bssid_filtering = false;
|
||||
|
||||
@ -1015,17 +1014,17 @@ void cw1200_event_handler(struct work_struct *work)
|
||||
/* RSSI: signed Q8.0, RCPI: unsigned Q7.1
|
||||
* RSSI = RCPI / 2 - 110
|
||||
*/
|
||||
int rcpiRssi = (int)(event->evt.data & 0xFF);
|
||||
int rcpi_rssi = (int)(event->evt.data & 0xFF);
|
||||
int cqm_evt;
|
||||
if (priv->cqm_use_rssi)
|
||||
rcpiRssi = (s8)rcpiRssi;
|
||||
rcpi_rssi = (s8)rcpi_rssi;
|
||||
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_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,
|
||||
GFP_KERNEL);
|
||||
break;
|
||||
@ -1068,8 +1067,7 @@ void cw1200_bss_params_work(struct work_struct *work)
|
||||
/* ******************************************************************** */
|
||||
/* 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
|
||||
* sdd is a TLV: u8 id, u8 len, u8 data[]
|
||||
*/
|
||||
|
@ -75,9 +75,6 @@ static void tx_policy_build(const struct cw1200_common *priv,
|
||||
BUG_ON(rates[0].idx < 0);
|
||||
memset(policy, 0, sizeof(*policy));
|
||||
|
||||
/* minstrel is buggy a little bit, so distille
|
||||
* incoming rates first. */
|
||||
|
||||
/* Sort rates in descending order. */
|
||||
for (i = 1; i < count; ++i) {
|
||||
if (rates[i].idx < 0) {
|
||||
@ -108,7 +105,8 @@ static void tx_policy_build(const struct cw1200_common *priv,
|
||||
count = i + 1;
|
||||
|
||||
/* 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)
|
||||
limit = count;
|
||||
if (total > limit) {
|
||||
@ -129,7 +127,6 @@ static void tx_policy_build(const struct cw1200_common *priv,
|
||||
if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) &&
|
||||
rates[0].idx > 4 && rates[0].count > 2 &&
|
||||
rates[1].idx < 2) {
|
||||
/* ">> 1" is an equivalent of "/ 2", but faster */
|
||||
int mid_rate = (rates[0].idx + 4) >> 1;
|
||||
|
||||
/* Decrease number of retries for the initial rate */
|
||||
@ -151,7 +148,8 @@ static void tx_policy_build(const struct cw1200_common *priv,
|
||||
/* Fallback to 1 Mbps is a really bad thing,
|
||||
* so let's try to increase probability of
|
||||
* successful transmission on the lowest g rate
|
||||
* even more */
|
||||
* even more
|
||||
*/
|
||||
if (rates[0].count >= 3) {
|
||||
--rates[0].count;
|
||||
++rates[2].count;
|
||||
@ -190,13 +188,12 @@ static void tx_policy_build(const struct cw1200_common *priv,
|
||||
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,
|
||||
rates[0].idx, rates[0].count,
|
||||
rates[1].idx, rates[1].count,
|
||||
rates[2].idx, rates[2].count,
|
||||
rates[3].idx, rates[3].count,
|
||||
rates[4].idx, rates[4].count);
|
||||
rates[3].idx, rates[3].count);
|
||||
}
|
||||
|
||||
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,
|
||||
{
|
||||
/* O(n) complexity. Not so good, but there's only 8 entries in
|
||||
* the cache.
|
||||
* Also lru helps to reduce search time. */
|
||||
* Also lru helps to reduce search time.
|
||||
*/
|
||||
struct tx_policy_cache_entry *it;
|
||||
/* First search for policy in "used" list */
|
||||
list_for_each_entry(it, &cache->used, link) {
|
||||
@ -265,7 +263,8 @@ void tx_policy_clean(struct cw1200_common *priv)
|
||||
for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) {
|
||||
entry = &cache->cache[idx];
|
||||
/* 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)) {
|
||||
entry->policy.usage_count = 0;
|
||||
list_move(&entry->link, &cache->free);
|
||||
@ -320,7 +319,8 @@ static int tx_policy_get(struct cw1200_common *priv,
|
||||
struct tx_policy_cache_entry *entry;
|
||||
*renew = true;
|
||||
/* 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,
|
||||
struct tx_policy_cache_entry, link);
|
||||
entry->policy = wanted;
|
||||
@ -613,7 +613,8 @@ cw1200_tx_h_bt(struct cw1200_common *priv,
|
||||
priv->listen_interval,
|
||||
mgt_frame->u.assoc_req.listen_interval);
|
||||
/* Replace listen interval derieved from
|
||||
* the one read from SDD */
|
||||
* the one read from SDD
|
||||
*/
|
||||
mgt_frame->u.assoc_req.listen_interval =
|
||||
priv->listen_interval;
|
||||
}
|
||||
@ -668,7 +669,8 @@ cw1200_tx_h_rate_policy(struct cw1200_common *priv,
|
||||
pr_debug("[TX] TX policy renew.\n");
|
||||
/* It's not so optimal to stop TX queues every now and then.
|
||||
* Better to reimplement task scheduling with
|
||||
* a counter. TODO. */
|
||||
* a counter. TODO.
|
||||
*/
|
||||
wsm_lock_tx_async(priv);
|
||||
cw1200_tx_queues_lock(priv);
|
||||
if (queue_work(priv->workqueue,
|
||||
@ -833,8 +835,7 @@ static int cw1200_handle_pspoll(struct cw1200_common *priv,
|
||||
priv->pspoll_mask |= pspoll_mask;
|
||||
drop = 0;
|
||||
|
||||
/* Do not report pspols if data for given link id is
|
||||
* queued already. */
|
||||
/* Do not report pspols if data for given link id is queued already. */
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (cw1200_queue_get_num_queued(&priv->tx_queue[i],
|
||||
pspoll_mask)) {
|
||||
@ -862,9 +863,6 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
|
||||
pr_debug("[TX] TX confirm: %d, %d.\n",
|
||||
arg->status, arg->ack_failures);
|
||||
|
||||
if (cw1200_itp_tx_running(priv))
|
||||
return;
|
||||
|
||||
if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) {
|
||||
/* STA is stopped. */
|
||||
return;
|
||||
@ -928,7 +926,8 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
|
||||
cw1200_debug_txed(priv);
|
||||
if (arg->flags & WSM_TX_STATUS_AGGREGATION) {
|
||||
/* Do not report aggregation to mac80211:
|
||||
* it confuses minstrel a lot. */
|
||||
* it confuses minstrel a lot.
|
||||
*/
|
||||
/* tx->flags |= IEEE80211_TX_STAT_AMPDU; */
|
||||
cw1200_debug_txed_agg(priv);
|
||||
}
|
||||
@ -1002,8 +1001,7 @@ void cw1200_skb_dtor(struct cw1200_common *priv,
|
||||
txpriv->raw_link_id, txpriv->tid);
|
||||
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,
|
||||
@ -1049,7 +1047,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
|
||||
ieee80211_is_action(frame->frame_control) &&
|
||||
(mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) {
|
||||
/* Link ID already exists for the ACTION frame.
|
||||
* Reset and Remap */
|
||||
* Reset and Remap
|
||||
*/
|
||||
WARN_ON(work_pending(&priv->linkid_reset_work));
|
||||
memcpy(&priv->action_frame_sa[0],
|
||||
ieee80211_get_SA(frame), ETH_ALEN);
|
||||
@ -1079,7 +1078,6 @@ void cw1200_rx_cb(struct cw1200_common *priv,
|
||||
if (cw1200_handle_pspoll(priv, skb))
|
||||
goto drop;
|
||||
|
||||
hdr->mactime = 0; /* Not supported by WSM */
|
||||
hdr->band = ((arg->channel_number & 0xff00) ||
|
||||
(arg->channel_number > 14)) ?
|
||||
IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
|
||||
@ -1107,7 +1105,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
|
||||
hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED;
|
||||
|
||||
/* 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)) {
|
||||
case WSM_RX_STATUS_WEP:
|
||||
iv_len = 4 /* WEP_IV_LEN */;
|
||||
@ -1154,6 +1153,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
|
||||
hdr->mactime = le64_to_cpu(hdr->mactime);
|
||||
if (skb->len >= 8)
|
||||
skb_trim(skb, skb->len - 8);
|
||||
} else {
|
||||
hdr->mactime = 0;
|
||||
}
|
||||
|
||||
cw1200_debug_rxed(priv);
|
||||
@ -1197,7 +1198,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
|
||||
|
||||
/* Stay awake after frame is received to give
|
||||
* userspace chance to react and acquire appropriate
|
||||
* wakelock. */
|
||||
* wakelock.
|
||||
*/
|
||||
if (ieee80211_is_auth(frame->frame_control))
|
||||
grace_period = 5 * HZ;
|
||||
else if (ieee80211_is_deauth(frame->frame_control))
|
||||
@ -1206,9 +1208,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
|
||||
grace_period = 1 * HZ;
|
||||
cw1200_pm_stay_awake(&priv->pm_state, grace_period);
|
||||
|
||||
if (cw1200_itp_rxed(priv, skb)) {
|
||||
consume_skb(skb);
|
||||
} else if (early_data) {
|
||||
if (early_data) {
|
||||
spin_lock_bh(&priv->ps_state_lock);
|
||||
/* Double-check status with lock held */
|
||||
if (entry->status == CW1200_LINK_SOFT)
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/random.h>
|
||||
@ -22,7 +21,6 @@
|
||||
#include "bh.h"
|
||||
#include "sta.h"
|
||||
#include "debug.h"
|
||||
#include "itp.h"
|
||||
|
||||
#define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */
|
||||
#define WSM_CMD_START_TIMEOUT (7 * HZ)
|
||||
@ -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);
|
||||
if (!event)
|
||||
return -ENOMEM;
|
||||
|
||||
event->evt.id = __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,
|
||||
else
|
||||
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
|
||||
* that it's completely received.
|
||||
*/
|
||||
#ifdef CONFIG_CW1200_ETF
|
||||
if (!etf_mode)
|
||||
#endif
|
||||
buf_len += 4;
|
||||
buf_len += 4;
|
||||
|
||||
/* Fill HI message header */
|
||||
/* BH will add sequence number */
|
||||
@ -1165,29 +1161,6 @@ static int wsm_cmd_send(struct cw1200_common *priv,
|
||||
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 */
|
||||
|
||||
@ -1343,34 +1316,6 @@ int wsm_handle_rx(struct cw1200_common *priv, u16 id,
|
||||
pr_debug("[WSM] <<< 0x%.4X (%td)\n", id,
|
||||
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) {
|
||||
ret = wsm_tx_confirm(priv, &wsm_buf, link_id);
|
||||
} else if (id == WSM_MULTI_TX_CONFIRM_ID) {
|
||||
@ -1732,12 +1677,6 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data,
|
||||
/* More is used only for broadcasts. */
|
||||
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 */
|
||||
++count;
|
||||
spin_lock(&priv->wsm_cmd.lock);
|
||||
|
@ -314,13 +314,16 @@ struct cw1200_common;
|
||||
#define WSM_JOIN_FLAGS_P2P_GO BIT(1)
|
||||
/* Force to join BSS with the BSSID and the
|
||||
* SSID specified without waiting for beacons. The
|
||||
* ProbeForJoin parameter is ignored. */
|
||||
* ProbeForJoin parameter is ignored.
|
||||
*/
|
||||
#define WSM_JOIN_FLAGS_FORCE BIT(2)
|
||||
/* Give probe request/response higher
|
||||
* priority over the BT traffic */
|
||||
* priority over the BT traffic
|
||||
*/
|
||||
#define WSM_JOIN_FLAGS_PRIO BIT(3)
|
||||
/* 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)
|
||||
|
||||
/* Key types */
|
||||
@ -1015,22 +1018,19 @@ struct wsm_add_key {
|
||||
u16 reserved;
|
||||
union {
|
||||
struct {
|
||||
u8 peer[6]; /* MAC address of the
|
||||
* peer station */
|
||||
u8 peer[6]; /* MAC address of the peer station */
|
||||
u8 reserved;
|
||||
u8 keylen; /* Key length in bytes */
|
||||
u8 keydata[16]; /* Key data */
|
||||
} __packed wep_pairwise;
|
||||
struct {
|
||||
u8 keyid; /* Unique per key identifier
|
||||
* (0..3) */
|
||||
u8 keyid; /* Unique per key identifier (0..3) */
|
||||
u8 keylen; /* Key length in bytes */
|
||||
u16 reserved;
|
||||
u8 keydata[16]; /* Key data */
|
||||
} __packed wep_group;
|
||||
struct {
|
||||
u8 peer[6]; /* MAC address of the
|
||||
* peer station */
|
||||
u8 peer[6]; /* MAC address of the peer station */
|
||||
u16 reserved;
|
||||
u8 keydata[16]; /* TKIP key data */
|
||||
u8 rx_mic_key[8]; /* Rx MIC key */
|
||||
@ -1044,8 +1044,7 @@ struct wsm_add_key {
|
||||
u8 rx_seqnum[8]; /* Receive Sequence Counter */
|
||||
} __packed tkip_group;
|
||||
struct {
|
||||
u8 peer[6]; /* MAC address of the
|
||||
* peer station */
|
||||
u8 peer[6]; /* MAC address of the peer station */
|
||||
u16 reserved;
|
||||
u8 keydata[16]; /* AES key data */
|
||||
} __packed aes_pairwise;
|
||||
@ -1056,8 +1055,7 @@ struct wsm_add_key {
|
||||
u8 rx_seqnum[8]; /* Receive Sequence Counter */
|
||||
} __packed aes_group;
|
||||
struct {
|
||||
u8 peer[6]; /* MAC address of the
|
||||
* peer station */
|
||||
u8 peer[6]; /* MAC address of the peer station */
|
||||
u8 keyid; /* Key ID */
|
||||
u8 reserved;
|
||||
u8 keydata[16]; /* WAPI key data */
|
||||
@ -1550,7 +1548,8 @@ struct wsm_tx_rate_retry_policy {
|
||||
* finishes.
|
||||
* BIT(3) - Count initial frame transmission as part of
|
||||
* rate retry counting but not as a retry
|
||||
* attempt */
|
||||
* attempt
|
||||
*/
|
||||
u8 flags;
|
||||
u8 rate_recoveries;
|
||||
u8 reserved[3];
|
||||
@ -1618,24 +1617,24 @@ static inline int wsm_set_udp_port_filter(struct cw1200_common *priv,
|
||||
#define D11_MAX_SSID_LEN (32)
|
||||
|
||||
struct wsm_p2p_device_type {
|
||||
__le16 categoryId;
|
||||
__le16 category_id;
|
||||
u8 oui[4];
|
||||
__le16 subCategoryId;
|
||||
__le16 subcategory_id;
|
||||
} __packed;
|
||||
|
||||
struct wsm_p2p_device_info {
|
||||
struct wsm_p2p_device_type primaryDevice;
|
||||
u8 reserved1[3];
|
||||
u8 devNameSize;
|
||||
u8 localDevName[D11_MAX_SSID_LEN];
|
||||
u8 devname_size;
|
||||
u8 local_devname[D11_MAX_SSID_LEN];
|
||||
u8 reserved2[3];
|
||||
u8 numSecDevSupported;
|
||||
struct wsm_p2p_device_type secondaryDevices[0];
|
||||
u8 num_secdev_supported;
|
||||
struct wsm_p2p_device_type secdevs[0];
|
||||
} __packed;
|
||||
|
||||
/* 4.36 SetWCDMABand - WO */
|
||||
struct wsm_cdma_band {
|
||||
u8 WCDMA_Band;
|
||||
u8 wcdma_band;
|
||||
u8 reserved[3];
|
||||
} __packed;
|
||||
|
||||
@ -1668,19 +1667,19 @@ struct wsm_ht_protection {
|
||||
#define WSM_GPIO_ALL_PINS 0xFF
|
||||
|
||||
struct wsm_gpio_command {
|
||||
u8 GPIO_Command;
|
||||
u8 command;
|
||||
u8 pin;
|
||||
__le16 config;
|
||||
} __packed;
|
||||
|
||||
/* 4.41 TSFCounter - RO */
|
||||
struct wsm_tsf_counter {
|
||||
__le64 TSF_Counter;
|
||||
__le64 tsf_counter;
|
||||
} __packed;
|
||||
|
||||
/* 4.43 Keep alive period */
|
||||
struct wsm_keep_alive_period {
|
||||
__le16 keepAlivePeriod;
|
||||
__le16 period;
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
@ -1688,7 +1687,7 @@ static inline int wsm_keep_alive_period(struct cw1200_common *priv,
|
||||
int period)
|
||||
{
|
||||
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,
|
||||
&arg, sizeof(arg));
|
||||
@ -1739,13 +1738,13 @@ static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv,
|
||||
|
||||
/* P2P Power Save Mode Info - 4.31 */
|
||||
struct wsm_p2p_ps_modeinfo {
|
||||
u8 oppPsCTWindow;
|
||||
u8 opp_ps_ct_window;
|
||||
u8 count;
|
||||
u8 reserved;
|
||||
u8 dtimCount;
|
||||
u8 dtim_count;
|
||||
__le32 duration;
|
||||
__le32 interval;
|
||||
__le32 startTime;
|
||||
__le32 start_time;
|
||||
} __packed;
|
||||
|
||||
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)
|
||||
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 */
|
||||
|
@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
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)) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"Device not found via register read.\n");
|
||||
|
@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
|
||||
.types = BIT(NL80211_IFTYPE_STATION) |
|
||||
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[] = {
|
||||
@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
hw->chanctx_data_size = sizeof(u16);
|
||||
|
||||
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 |
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS |
|
||||
|
@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) },
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
|
||||
};
|
||||
|
||||
static struct ieee80211_iface_combination hwsim_if_comb = {
|
||||
@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void)
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
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 |
|
||||
IEEE80211_HW_SIGNAL_DBM |
|
||||
|
@ -1170,12 +1170,6 @@ static int rt2x00queue_alloc_entries(struct data_queue *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.
|
||||
*/
|
||||
@ -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,
|
||||
struct data_queue *queue, enum data_queue_qid qid)
|
||||
{
|
||||
const struct data_queue_desc *qdesc;
|
||||
|
||||
mutex_init(&queue->status_lock);
|
||||
spin_lock_init(&queue->tx_lock);
|
||||
spin_lock_init(&queue->index_lock);
|
||||
@ -1297,6 +1320,15 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
|
||||
queue->aifs = 2;
|
||||
queue->cw_min = 5;
|
||||
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)
|
||||
|
@ -842,7 +842,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
|
||||
long val_y, ele_c = 0;
|
||||
u8 ofdm_index[2];
|
||||
s8 cck_index = 0;
|
||||
u8 ofdm_index_old[2];
|
||||
u8 ofdm_index_old[2] = {0, 0};
|
||||
s8 cck_index_old = 0;
|
||||
u8 index;
|
||||
int i;
|
||||
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2011
|
||||
*
|
||||
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#ifndef CW1200_PLAT_H_INCLUDED
|
||||
#define CW1200_PLAT_H_INCLUDED
|
||||
|
||||
struct cw1200_platform_data_spi {
|
||||
u8 spi_bits_per_word; /* REQUIRED */
|
||||
u16 ref_clk; /* REQUIRED (in KHz) */
|
||||
|
||||
/* All others are optional */
|
||||
bool have_5ghz;
|
||||
const struct resource *reset; /* GPIO to RSTn signal */
|
||||
const struct resource *powerup; /* GPIO to POWERUP signal */
|
||||
int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata,
|
||||
bool enable); /* Control 3v3 / 1v8 supply */
|
||||
int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata,
|
||||
bool enable); /* Control CLK32K */
|
||||
const u8 *macaddr; /* if NULL, use cw1200_mac_template module parameter */
|
||||
const char *sdd_file; /* if NULL, will use default for detected hw type */
|
||||
};
|
||||
|
||||
struct cw1200_platform_data_sdio {
|
||||
u16 ref_clk; /* REQUIRED (in KHz) */
|
||||
|
||||
/* All others are optional */
|
||||
const struct resource *irq; /* if using GPIO for IRQ */
|
||||
bool have_5ghz;
|
||||
bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */
|
||||
const struct resource *reset; /* GPIO to RSTn signal */
|
||||
const struct resource *powerup; /* GPIO to POWERUP signal */
|
||||
int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata,
|
||||
bool enable); /* Control 3v3 / 1v8 supply */
|
||||
int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata,
|
||||
bool enable); /* Control CLK32K */
|
||||
const u8 *macaddr; /* if NULL, use cw1200_mac_template module parameter */
|
||||
const char *sdd_file; /* if NULL, will use default for detected hw type */
|
||||
};
|
||||
|
||||
const void *cw1200_get_platform_data(void);
|
||||
|
||||
#endif /* CW1200_PLAT_H_INCLUDED */
|
81
include/linux/platform_data/net-cw1200.h
Normal file
81
include/linux/platform_data/net-cw1200.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2011
|
||||
*
|
||||
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#ifndef CW1200_PLAT_H_INCLUDED
|
||||
#define CW1200_PLAT_H_INCLUDED
|
||||
|
||||
struct cw1200_platform_data_spi {
|
||||
u8 spi_bits_per_word; /* REQUIRED */
|
||||
u16 ref_clk; /* REQUIRED (in KHz) */
|
||||
|
||||
/* All others are optional */
|
||||
bool have_5ghz;
|
||||
int reset; /* GPIO to RSTn signal (0 disables) */
|
||||
int powerup; /* GPIO to POWERUP signal (0 disables) */
|
||||
int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata,
|
||||
bool enable); /* Control 3v3 / 1v8 supply */
|
||||
int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata,
|
||||
bool enable); /* Control CLK32K */
|
||||
const u8 *macaddr; /* if NULL, use cw1200_mac_template module parameter */
|
||||
const char *sdd_file; /* if NULL, will use default for detected hw type */
|
||||
};
|
||||
|
||||
struct cw1200_platform_data_sdio {
|
||||
u16 ref_clk; /* REQUIRED (in KHz) */
|
||||
|
||||
/* All others are optional */
|
||||
bool have_5ghz;
|
||||
bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */
|
||||
int reset; /* GPIO to RSTn signal (0 disables) */
|
||||
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,
|
||||
bool enable); /* Control 3v3 / 1v8 supply */
|
||||
int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata,
|
||||
bool enable); /* Control CLK32K */
|
||||
const u8 *macaddr; /* if NULL, use cw1200_mac_template module parameter */
|
||||
const char *sdd_file; /* if NULL, will use default for detected hw type */
|
||||
};
|
||||
|
||||
|
||||
/* 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 */
|
@ -961,6 +961,7 @@ struct station_info {
|
||||
* @MONITOR_FLAG_CONTROL: pass control frames
|
||||
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
|
||||
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing
|
||||
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
|
||||
*/
|
||||
enum monitor_flags {
|
||||
MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
|
||||
@ -968,6 +969,7 @@ enum monitor_flags {
|
||||
MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
|
||||
MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
|
||||
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;
|
||||
* @mgmt_registrations_lock: lock for the list
|
||||
* @mtx: mutex used to lock data in this struct, may be used by drivers
|
||||
* 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
|
||||
* beacons, 0 when not valid
|
||||
* @address: The address for this device, valid only if @netdev is %NULL
|
||||
|
@ -2428,6 +2428,8 @@ enum nl80211_survey_info {
|
||||
* @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
|
||||
* @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
|
||||
* 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_MAX: highest possible monitor flag
|
||||
@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags {
|
||||
NL80211_MNTR_FLAG_CONTROL,
|
||||
NL80211_MNTR_FLAG_OTHER_BSS,
|
||||
NL80211_MNTR_FLAG_COOK_FRAMES,
|
||||
NL80211_MNTR_FLAG_ACTIVE,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_MNTR_FLAG_AFTER_LAST,
|
||||
@ -3595,6 +3598,7 @@ enum nl80211_feature_flags {
|
||||
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
|
||||
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
|
||||
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
|
||||
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
u32 mask = MONITOR_FLAG_COOK_FRAMES |
|
||||
MONITOR_FLAG_ACTIVE;
|
||||
|
||||
/*
|
||||
* Prohibit MONITOR_FLAG_COOK_FRAMES to be
|
||||
* changed while the interface is up.
|
||||
* Prohibit MONITOR_FLAG_COOK_FRAMES and
|
||||
* MONITOR_FLAG_ACTIVE to be changed while the
|
||||
* interface is up.
|
||||
* Else we would need to add a lot of cruft
|
||||
* to update everything:
|
||||
* cooked_mntrs, monitor and all fif_* counters
|
||||
* reconfigure hardware
|
||||
*/
|
||||
if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
|
||||
(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
|
||||
if ((*flags & mask) != (sdata->u.mntr_flags & mask))
|
||||
return -EBUSY;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
@ -2375,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
||||
local->dynamic_ps_forced_timeout = timeout;
|
||||
|
||||
/* no change, but if automatic follow powersave */
|
||||
sdata_lock(sdata);
|
||||
__ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
|
||||
sdata_unlock(sdata);
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
|
@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
|
||||
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
(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;
|
||||
|
||||
trace_drv_add_interface(local, sdata);
|
||||
|
@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
|
||||
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;
|
||||
u64 new, mask, tmp;
|
||||
@ -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[4] << 1*8) | ((u64)m[5] << 0*8);
|
||||
|
||||
if (!check_dup)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
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;
|
||||
|
||||
m = sdata->vif.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 sockaddr *sa = addr;
|
||||
bool check_dup = true;
|
||||
int ret;
|
||||
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
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)
|
||||
return ret;
|
||||
|
||||
@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
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);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
break;
|
||||
|
||||
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
|
||||
break;
|
||||
|
||||
/* fall through */
|
||||
default:
|
||||
if (going_down)
|
||||
drv_remove_interface(local, sdata);
|
||||
@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
|
||||
.ndo_start_xmit = ieee80211_monitor_start_xmit,
|
||||
.ndo_set_rx_mode = ieee80211_set_multicast_list,
|
||||
.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,
|
||||
};
|
||||
|
||||
|
@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
|
||||
if (ieee80211_has_order(hdr->frame_control))
|
||||
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 */
|
||||
if (!atomic_read(&ps->num_sta_ps))
|
||||
return TX_CONTINUE;
|
||||
|
||||
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 */
|
||||
if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
|
||||
|
@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
|
||||
continue;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
continue;
|
||||
default:
|
||||
@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
|
||||
continue;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
continue;
|
||||
default:
|
||||
|
@ -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_OTHER_BSS] = { .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)
|
||||
@ -2338,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (change)
|
||||
err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms);
|
||||
else
|
||||
@ -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 ?
|
||||
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
|
||||
&flags);
|
||||
|
||||
if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
wdev = rdev_add_virtual_intf(rdev,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
type, err ? NULL : &flags, ¶ms);
|
||||
|
Loading…
Reference in New Issue
Block a user