提交 51217cee 编写于 作者: J Johannes Berg

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

Merge to get the wil6210 changes that a cfg80211 change needs.
A conflict in drivers/net/wireless/ath/ath9k/init.c was just
whitespace changes.

Also fix a semantic conflict due to cw1200 using WoWLAN which
I had modified in my tree.
Signed-off-by: NJohannes Berg <johannes.berg@intel.com>
...@@ -2299,6 +2299,11 @@ M: Jaya Kumar <jayakumar.alsa@gmail.com> ...@@ -2299,6 +2299,11 @@ M: Jaya Kumar <jayakumar.alsa@gmail.com>
S: Maintained S: Maintained
F: sound/pci/cs5535audio/ F: sound/pci/cs5535audio/
CW1200 WLAN driver
M: Solomon Peachy <pizza@shaftnet.org>
S: Maintained
F: drivers/net/wireless/cw1200/
CX18 VIDEO4LINUX DRIVER CX18 VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net> M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
......
...@@ -72,12 +72,12 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, ...@@ -72,12 +72,12 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
* R/W ops. * R/W ops.
**************************************************/ **************************************************/
static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom) static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
size_t words)
{ {
int i; int i;
for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) for (i = 0; i < words; i++)
sprom[i] = bcma_read16(bus->drv_cc.core, sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
offset + (i * 2));
} }
/************************************************** /**************************************************
...@@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data) ...@@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data)
return t[crc ^ data]; return t[crc ^ data];
} }
static u8 bcma_sprom_crc(const u16 *sprom) static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
{ {
int word; int word;
u8 crc = 0xFF; u8 crc = 0xFF;
for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) { for (word = 0; word < words - 1; word++) {
crc = bcma_crc8(crc, sprom[word] & 0x00FF); crc = bcma_crc8(crc, sprom[word] & 0x00FF);
crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8); crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
} }
crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF); crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
crc ^= 0xFF; crc ^= 0xFF;
return crc; return crc;
} }
static int bcma_sprom_check_crc(const u16 *sprom) static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
{ {
u8 crc; u8 crc;
u8 expected_crc; u8 expected_crc;
u16 tmp; u16 tmp;
crc = bcma_sprom_crc(sprom); crc = bcma_sprom_crc(sprom, words);
tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC; tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
if (crc != expected_crc) if (crc != expected_crc)
return -EPROTO; return -EPROTO;
...@@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom) ...@@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom)
return 0; return 0;
} }
static int bcma_sprom_valid(const u16 *sprom) static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
size_t words)
{ {
u16 revision; u16 revision;
int err; int err;
err = bcma_sprom_check_crc(sprom); err = bcma_sprom_check_crc(sprom, words);
if (err) if (err)
return err; return err;
revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
if (revision != 8 && revision != 9) { if (revision != 8 && revision != 9 && revision != 10) {
pr_err("Unsupported SPROM revision: %d\n", revision); pr_err("Unsupported SPROM revision: %d\n", revision);
return -ENOENT; return -ENOENT;
} }
bus->sprom.revision = revision;
bcma_debug(bus, "Found SPROM revision %d\n", revision);
return 0; return 0;
} }
...@@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) ...@@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
ARRAY_SIZE(bus->sprom.core_pwr_info)); ARRAY_SIZE(bus->sprom.core_pwr_info));
bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
SSB_SPROM_REVISION_REV;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
...@@ -502,7 +503,6 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) ...@@ -502,7 +503,6 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
case BCMA_CHIP_ID_BCM4331: case BCMA_CHIP_ID_BCM4331:
present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
break; break;
case BCMA_CHIP_ID_BCM43224: case BCMA_CHIP_ID_BCM43224:
case BCMA_CHIP_ID_BCM43225: case BCMA_CHIP_ID_BCM43225:
/* for these chips OTP is always available */ /* for these chips OTP is always available */
...@@ -550,7 +550,9 @@ int bcma_sprom_get(struct bcma_bus *bus) ...@@ -550,7 +550,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
{ {
u16 offset = BCMA_CC_SPROM; u16 offset = BCMA_CC_SPROM;
u16 *sprom; u16 *sprom;
int err = 0; size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
SSB_SPROMSIZE_WORDS_R10, };
int i, err = 0;
if (!bus->drv_cc.core) if (!bus->drv_cc.core)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -579,32 +581,37 @@ int bcma_sprom_get(struct bcma_bus *bus) ...@@ -579,32 +581,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
} }
} }
sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
GFP_KERNEL);
if (!sprom)
return -ENOMEM;
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
bcma_debug(bus, "SPROM offset 0x%x\n", offset); bcma_debug(bus, "SPROM offset 0x%x\n", offset);
bcma_sprom_read(bus, offset, sprom); for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
size_t words = sprom_sizes[i];
sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
if (!sprom)
return -ENOMEM;
bcma_sprom_read(bus, offset, sprom, words);
err = bcma_sprom_valid(bus, sprom, words);
if (!err)
break;
kfree(sprom);
}
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom);
if (err) { if (err) {
bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n"); bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
goto out; } else {
bcma_sprom_extract_r8(bus, sprom);
kfree(sprom);
} }
bcma_sprom_extract_r8(bus, sprom);
out:
kfree(sprom);
return err; return err;
} }
...@@ -280,5 +280,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig" ...@@ -280,5 +280,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig" source "drivers/net/wireless/mwifiex/Kconfig"
source "drivers/net/wireless/cw1200/Kconfig"
endif # WLAN endif # WLAN
...@@ -57,3 +57,5 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ ...@@ -57,3 +57,5 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/
obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMFMAC) += brcm80211/
obj-$(CONFIG_BRCMSMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/
obj-$(CONFIG_CW1200) += cw1200/
...@@ -84,14 +84,6 @@ config ATH9K_DFS_CERTIFIED ...@@ -84,14 +84,6 @@ config ATH9K_DFS_CERTIFIED
developed. At this point enabling this option won't do anything developed. At this point enabling this option won't do anything
except increase code size. except increase code size.
config ATH9K_MAC_DEBUG
bool "Atheros MAC statistics"
depends on ATH9K_DEBUGFS
default y
---help---
This option enables collection of statistics for Rx/Tx status
data and some other MAC related statistics
config ATH9K_RATE_CONTROL config ATH9K_RATE_CONTROL
bool "Atheros ath9k rate control" bool "Atheros ath9k rate control"
depends on ATH9K depends on ATH9K
......
...@@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah) ...@@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
aniState->listenTime = 0; aniState->listenTime = 0;
ENABLE_REGWRITE_BUFFER(ah); ENABLE_REGWRITE_BUFFER(ah);
...@@ -143,7 +143,7 @@ static void ath9k_ani_restart(struct ath_hw *ah) ...@@ -143,7 +143,7 @@ static void ath9k_ani_restart(struct ath_hw *ah)
static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
bool scan) bool scan)
{ {
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck; const struct ani_cck_level_entry *entry_cck;
...@@ -195,10 +195,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) ...@@ -195,10 +195,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
...@@ -210,7 +210,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) ...@@ -210,7 +210,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
bool scan) bool scan)
{ {
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck; const struct ani_cck_level_entry *entry_cck;
...@@ -251,10 +251,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) ...@@ -251,10 +251,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
...@@ -269,7 +269,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ...@@ -269,7 +269,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
{ {
struct ar5416AniState *aniState; struct ar5416AniState *aniState;
aniState = &ah->curchan->ani; aniState = &ah->ani;
/* lower OFDM noise immunity */ /* lower OFDM noise immunity */
if (aniState->ofdmNoiseImmunityLevel > 0 && if (aniState->ofdmNoiseImmunityLevel > 0 &&
...@@ -292,12 +292,12 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ...@@ -292,12 +292,12 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
*/ */
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
{ {
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int ofdm_nil, cck_nil; int ofdm_nil, cck_nil;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
BUG_ON(aniState == NULL); BUG_ON(aniState == NULL);
...@@ -380,7 +380,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) ...@@ -380,7 +380,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ar5416AniState *aniState = &ah->curchan->ani; struct ar5416AniState *aniState = &ah->ani;
u32 phyCnt1, phyCnt2; u32 phyCnt1, phyCnt2;
int32_t listenTime; int32_t listenTime;
...@@ -415,10 +415,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -415,10 +415,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
u32 ofdmPhyErrRate, cckPhyErrRate; u32 ofdmPhyErrRate, cckPhyErrRate;
if (!DO_ANI(ah)) if (!ah->curchan)
return; return;
aniState = &ah->curchan->ani; aniState = &ah->ani;
if (!ath9k_hw_ani_read_counters(ah)) if (!ath9k_hw_ani_read_counters(ah))
return; return;
...@@ -490,32 +490,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); ...@@ -490,32 +490,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
void ath9k_hw_ani_init(struct ath_hw *ah) void ath9k_hw_ani_init(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int i; struct ar5416AniState *ani = &ah->ani;
ath_dbg(common, ANI, "Initialize ANI\n"); ath_dbg(common, ANI, "Initialize ANI\n");
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
struct ath9k_channel *chan = &ah->channels[i]; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
struct ar5416AniState *ani = &chan->ani; ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
ani->ofdmsTurn = true;
ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->ofdmWeakSigDetect = true;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
ani->ofdmsTurn = true;
ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
}
/* /*
* since we expect some ongoing maintenance on the tables, let's sanity * since we expect some ongoing maintenance on the tables, let's sanity
...@@ -524,9 +514,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ...@@ -524,9 +514,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ah->aniperiod = ATH9K_ANI_PERIOD; ah->aniperiod = ATH9K_ANI_PERIOD;
ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
if (ah->config.enable_ani)
ah->proc_phyerr |= HAL_PROCESS_ANI;
ath9k_ani_restart(ah); ath9k_ani_restart(ah);
ath9k_enable_mib_counters(ah); ath9k_enable_mib_counters(ah);
} }
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
#ifndef ANI_H #ifndef ANI_H
#define ANI_H #define ANI_H
#define HAL_PROCESS_ANI 0x00000001
#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan)
#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
/* units are errors per second */ /* units are errors per second */
...@@ -38,11 +34,7 @@ ...@@ -38,11 +34,7 @@
#define ATH9K_ANI_CCK_TRIG_LOW 300 #define ATH9K_ANI_CCK_TRIG_LOW 300
#define ATH9K_ANI_NOISE_IMMUNE_LVL 4 #define ATH9K_ANI_NOISE_IMMUNE_LVL 4
#define ATH9K_ANI_USE_OFDM_WEAK_SIG true
#define ATH9K_ANI_CCK_WEAK_SIG_THR false
#define ATH9K_ANI_SPUR_IMMUNE_LVL 3 #define ATH9K_ANI_SPUR_IMMUNE_LVL 3
#define ATH9K_ANI_FIRSTEP_LVL 2 #define ATH9K_ANI_FIRSTEP_LVL 2
#define ATH9K_ANI_RSSI_THR_HIGH 40 #define ATH9K_ANI_RSSI_THR_HIGH 40
...@@ -111,7 +103,7 @@ struct ar5416AniState { ...@@ -111,7 +103,7 @@ struct ar5416AniState {
u8 mrcCCK; u8 mrcCCK;
u8 spurImmunityLevel; u8 spurImmunityLevel;
u8 firstepLevel; u8 firstepLevel;
u8 ofdmWeakSigDetect; bool ofdmWeakSigDetect;
u32 listenTime; u32 listenTime;
u32 ofdmPhyErrCount; u32 ofdmPhyErrCount;
u32 cckPhyErrCount; u32 cckPhyErrCount;
...@@ -119,8 +111,6 @@ struct ar5416AniState { ...@@ -119,8 +111,6 @@ struct ar5416AniState {
}; };
struct ar5416Stats { struct ar5416Stats {
u32 ast_ani_niup;
u32 ast_ani_nidown;
u32 ast_ani_spurup; u32 ast_ani_spurup;
u32 ast_ani_spurdown; u32 ast_ani_spurdown;
u32 ast_ani_ofdmon; u32 ast_ani_ofdmon;
......
...@@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, ...@@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &chan->ani; struct ar5416AniState *aniState = &ah->ani;
s32 value, value2; s32 value, value2;
switch (cmd & ah->ani_function) { switch (cmd & ah->ani_function) {
...@@ -1207,7 +1207,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1207,7 +1207,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &chan->ani; struct ar5416AniState *aniState = &ah->ani;
struct ath9k_ani_default *iniDef; struct ath9k_ani_default *iniDef;
u32 val; u32 val;
...@@ -1251,7 +1251,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1251,7 +1251,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* these levels just got reset to defaults by the INI */ /* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; aniState->ofdmWeakSigDetect = true;
aniState->mrcCCK = false; /* not available on pre AR9003 */ aniState->mrcCCK = false; /* not available on pre AR9003 */
} }
......
...@@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah) ...@@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
else else
INIT_INI_ARRAY(&ah->iniPcieSerdes, INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9280PciePhy_clkreq_always_on_L1_9280); ar9280PciePhy_clkreq_always_on_L1_9280);
#ifdef CONFIG_PM_SLEEP
INIT_INI_ARRAY(&ah->iniPcieSerdesWow,
ar9280PciePhy_awow);
#endif
if (AR_SREV_9287_11_OR_LATER(ah)) { if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);
......
...@@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { ...@@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000}, {0x00004044, 0x00000000},
}; };
static const u32 ar9280PciePhy_awow[][2] = {
/* Addr allmodes */
{0x00004040, 0x9248fd00},
{0x00004040, 0x24924924},
{0x00004040, 0xa8000019},
{0x00004040, 0x13160820},
{0x00004040, 0xe5980560},
{0x00004040, 0xc01dcffd},
{0x00004040, 0x1aaabe41},
{0x00004040, 0xbe105554},
{0x00004040, 0x00043007},
{0x00004044, 0x00000000},
};
static const u32 ar9285Modes_9285_1_2[][5] = { static const u32 ar9285Modes_9285_1_2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
......
...@@ -469,6 +469,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, ...@@ -469,6 +469,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_status = 0; rxs->rs_status = 0;
rxs->rs_flags = 0; rxs->rs_flags = 0;
rxs->flag = 0;
rxs->rs_datalen = rxsp->status2 & AR_DataLen; rxs->rs_datalen = rxsp->status2 & AR_DataLen;
rxs->rs_tstamp = rxsp->status3; rxs->rs_tstamp = rxsp->status3;
...@@ -493,8 +494,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, ...@@ -493,8 +494,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0;
rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; rxs->flag |= (rxsp->status4 & AR_GI) ? RX_FLAG_SHORT_GI : 0;
rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; rxs->flag |= (rxsp->status4 & AR_2040) ? RX_FLAG_40MHZ : 0;
rxs->evm0 = rxsp->status6; rxs->evm0 = rxsp->status6;
rxs->evm1 = rxsp->status7; rxs->evm1 = rxsp->status7;
......
...@@ -454,6 +454,8 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) ...@@ -454,6 +454,8 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
if (accum_cnt <= thresh_accum_cnt) if (accum_cnt <= thresh_accum_cnt)
continue; continue;
max_index++;
/* sum(tx amplitude) */ /* sum(tx amplitude) */
accum_tx = ((data_L[i] >> 16) & 0xffff) | accum_tx = ((data_L[i] >> 16) & 0xffff) |
((data_U[i] & 0x7ff) << 16); ((data_U[i] & 0x7ff) << 16);
...@@ -468,20 +470,21 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) ...@@ -468,20 +470,21 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
accum_tx <<= scale_factor; accum_tx <<= scale_factor;
accum_rx <<= scale_factor; accum_rx <<= scale_factor;
x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >> x_est[max_index] =
scale_factor; (((accum_tx + accum_cnt) / accum_cnt) + 32) >>
scale_factor;
Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> Y[max_index] =
((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
scale_factor) + scale_factor) +
(1 << scale_factor) * max_index + 16; (1 << scale_factor) * i + 16;
if (accum_ang >= (1 << 26)) if (accum_ang >= (1 << 26))
accum_ang -= 1 << 27; accum_ang -= 1 << 27;
theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) / theta[max_index] =
accum_cnt; ((accum_ang * (1 << scale_factor)) + accum_cnt) /
accum_cnt;
max_index++;
} }
/* /*
......
...@@ -904,7 +904,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, ...@@ -904,7 +904,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan; struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &chan->ani; struct ar5416AniState *aniState = &ah->ani;
s32 value, value2; s32 value, value2;
switch (cmd & ah->ani_function) { switch (cmd & ah->ani_function) {
...@@ -1172,7 +1172,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1172,7 +1172,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
struct ath9k_ani_default *iniDef; struct ath9k_ani_default *iniDef;
u32 val; u32 val;
aniState = &ah->curchan->ani; aniState = &ah->ani;
iniDef = &aniState->iniDef; iniDef = &aniState->iniDef;
ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
...@@ -1213,7 +1213,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) ...@@ -1213,7 +1213,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* these levels just got reset to defaults by the INI */ /* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; aniState->ofdmWeakSigDetect = true;
aniState->mrcCCK = true; aniState->mrcCCK = true;
} }
......
...@@ -646,6 +646,7 @@ enum sc_op_flags { ...@@ -646,6 +646,7 @@ enum sc_op_flags {
SC_OP_ANI_RUN, SC_OP_ANI_RUN,
SC_OP_PRIM_STA_VIF, SC_OP_PRIM_STA_VIF,
SC_OP_HW_RESET, SC_OP_HW_RESET,
SC_OP_SCANNING,
}; };
/* Powersave flags */ /* Powersave flags */
...@@ -759,7 +760,6 @@ struct ath_softc { ...@@ -759,7 +760,6 @@ struct ath_softc {
struct rchan *rfs_chan_spec_scan; struct rchan *rfs_chan_spec_scan;
enum spectral_mode spectral_mode; enum spectral_mode spectral_mode;
struct ath_spec_scan spec_config; struct ath_spec_scan spec_config;
int scanning;
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
atomic_t wow_got_bmiss_intr; atomic_t wow_got_bmiss_intr;
......
...@@ -39,7 +39,8 @@ static void ath9k_beaconq_config(struct ath_softc *sc) ...@@ -39,7 +39,8 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
/* Always burst out beacon and CAB traffic. */ /* Always burst out beacon and CAB traffic. */
qi.tqi_aifs = 1; qi.tqi_aifs = 1;
qi.tqi_cwmin = 0; qi.tqi_cwmin = 0;
...@@ -273,7 +274,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) ...@@ -273,7 +274,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
u64 tsf; u64 tsf;
int slot; int slot;
if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) { if (sc->sc_ah->opmode != NL80211_IFTYPE_AP &&
sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) {
ath_dbg(common, BEACON, "slot 0, tsf: %llu\n", ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
ath9k_hw_gettsf64(sc->sc_ah)); ath9k_hw_gettsf64(sc->sc_ah));
return 0; return 0;
...@@ -765,10 +767,10 @@ void ath9k_set_beacon(struct ath_softc *sc) ...@@ -765,10 +767,10 @@ void ath9k_set_beacon(struct ath_softc *sc)
switch (sc->sc_ah->opmode) { switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
ath9k_beacon_config_ap(sc, cur_conf); ath9k_beacon_config_ap(sc, cur_conf);
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath9k_beacon_config_adhoc(sc, cur_conf); ath9k_beacon_config_adhoc(sc, cur_conf);
break; break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
......
...@@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = { ...@@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t read_file_disable_ani(struct file *file, char __user *user_buf, static ssize_t read_file_ani(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32]; struct ath_hw *ah = sc->sc_ah;
unsigned int len; unsigned int len = 0, size = 1024;
ssize_t retval = 0;
char *buf;
len = sprintf(buf, "%d\n", common->disable_ani); buf = kzalloc(size, GFP_KERNEL);
return simple_read_from_buffer(user_buf, count, ppos, buf, len); if (buf == NULL)
return -ENOMEM;
if (common->disable_ani) {
len += snprintf(buf + len, size - len, "%s: %s\n",
"ANI", "DISABLED");
goto exit;
}
len += snprintf(buf + len, size - len, "%15s: %s\n",
"ANI", "ENABLED");
len += snprintf(buf + len, size - len, "%15s: %u\n",
"ANI RESET", ah->stats.ast_ani_reset);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"SPUR UP", ah->stats.ast_ani_spurup);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"SPUR DOWN", ah->stats.ast_ani_spurup);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"MRC-CCK ON", ah->stats.ast_ani_ccklow);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"FIR-STEP UP", ah->stats.ast_ani_stepup);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
len += snprintf(buf + len, size - len, "%15s: %u\n",
"CCK ERRORS", ah->stats.ast_ani_cckerrs);
exit:
if (len > size)
len = size;
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
} }
static ssize_t write_file_disable_ani(struct file *file, static ssize_t write_file_ani(struct file *file,
const char __user *user_buf, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath_softc *sc = file->private_data; struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long disable_ani; unsigned long ani;
char buf[32]; char buf[32];
ssize_t len; ssize_t len;
...@@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file, ...@@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file,
return -EFAULT; return -EFAULT;
buf[len] = '\0'; buf[len] = '\0';
if (strict_strtoul(buf, 0, &disable_ani)) if (strict_strtoul(buf, 0, &ani))
return -EINVAL; return -EINVAL;
common->disable_ani = !!disable_ani; if (ani < 0 || ani > 1)
return -EINVAL;
common->disable_ani = !ani;
if (disable_ani) { if (common->disable_ani) {
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_stop_ani(sc); ath_stop_ani(sc);
} else { } else {
...@@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file, ...@@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file,
return count; return count;
} }
static const struct file_operations fops_disable_ani = { static const struct file_operations fops_ani = {
.read = read_file_disable_ani, .read = read_file_ani,
.write = write_file_disable_ani, .write = write_file_ani,
.open = simple_open, .open = simple_open,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = default_llseek, .llseek = default_llseek,
...@@ -738,8 +785,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, ...@@ -738,8 +785,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, struct ath_txq *txq, struct ath_tx_status *ts, struct ath_txq *txq,
unsigned int flags) unsigned int flags)
{ {
#define TX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].ts\
[sc->debug.tsidx].c)
int qnum = txq->axq_qnum; int qnum = txq->axq_qnum;
TX_STAT_INC(qnum, tx_pkts_all); TX_STAT_INC(qnum, tx_pkts_all);
...@@ -771,37 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, ...@@ -771,37 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
TX_STAT_INC(qnum, data_underrun); TX_STAT_INC(qnum, data_underrun);
if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
TX_STAT_INC(qnum, delim_underrun); TX_STAT_INC(qnum, delim_underrun);
#ifdef CONFIG_ATH9K_MAC_DEBUG
spin_lock(&sc->debug.samp_lock);
TX_SAMP_DBG(jiffies) = jiffies;
TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0;
TX_SAMP_DBG(rssi_ctl1) = ts->ts_rssi_ctl1;
TX_SAMP_DBG(rssi_ctl2) = ts->ts_rssi_ctl2;
TX_SAMP_DBG(rssi_ext0) = ts->ts_rssi_ext0;
TX_SAMP_DBG(rssi_ext1) = ts->ts_rssi_ext1;
TX_SAMP_DBG(rssi_ext2) = ts->ts_rssi_ext2;
TX_SAMP_DBG(rateindex) = ts->ts_rateindex;
TX_SAMP_DBG(isok) = !!(ts->ts_status & ATH9K_TXERR_MASK);
TX_SAMP_DBG(rts_fail_cnt) = ts->ts_shortretry;
TX_SAMP_DBG(data_fail_cnt) = ts->ts_longretry;
TX_SAMP_DBG(rssi) = ts->ts_rssi;
TX_SAMP_DBG(tid) = ts->tid;
TX_SAMP_DBG(qid) = ts->qid;
if (ts->ts_flags & ATH9K_TX_BA) {
TX_SAMP_DBG(ba_low) = ts->ba_low;
TX_SAMP_DBG(ba_high) = ts->ba_high;
} else {
TX_SAMP_DBG(ba_low) = 0;
TX_SAMP_DBG(ba_high) = 0;
}
sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES;
spin_unlock(&sc->debug.samp_lock);
#endif
#undef TX_SAMP_DBG
} }
static const struct file_operations fops_xmit = { static const struct file_operations fops_xmit = {
...@@ -915,8 +929,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, ...@@ -915,8 +929,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
{ {
#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
#define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\
[sc->debug.rsidx].c)
RX_STAT_INC(rx_pkts_all); RX_STAT_INC(rx_pkts_all);
sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;
...@@ -940,27 +952,7 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) ...@@ -940,27 +952,7 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
RX_PHY_ERR_INC(rs->rs_phyerr); RX_PHY_ERR_INC(rs->rs_phyerr);
} }
#ifdef CONFIG_ATH9K_MAC_DEBUG
spin_lock(&sc->debug.samp_lock);
RX_SAMP_DBG(jiffies) = jiffies;
RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0;
RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1;
RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2;
RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0;
RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1;
RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2;
RX_SAMP_DBG(antenna) = rs->rs_antenna;
RX_SAMP_DBG(rssi) = rs->rs_rssi;
RX_SAMP_DBG(rate) = rs->rs_rate;
RX_SAMP_DBG(is_mybeacon) = rs->is_mybeacon;
sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES;
spin_unlock(&sc->debug.samp_lock);
#endif
#undef RX_PHY_ERR_INC #undef RX_PHY_ERR_INC
#undef RX_SAMP_DBG
} }
static const struct file_operations fops_recv = { static const struct file_operations fops_recv = {
...@@ -1485,283 +1477,6 @@ static const struct file_operations fops_modal_eeprom = { ...@@ -1485,283 +1477,6 @@ static const struct file_operations fops_modal_eeprom = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
#ifdef CONFIG_ATH9K_MAC_DEBUG
void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
{
#define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
int i;
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->debug.samp_lock);
spin_lock_irqsave(&common->cc_lock, flags);
ath_hw_cycle_counters_update(common);
ATH_SAMP_DBG(cc.cycles) = common->cc_ani.cycles;
ATH_SAMP_DBG(cc.rx_busy) = common->cc_ani.rx_busy;
ATH_SAMP_DBG(cc.rx_frame) = common->cc_ani.rx_frame;
ATH_SAMP_DBG(cc.tx_frame) = common->cc_ani.tx_frame;
spin_unlock_irqrestore(&common->cc_lock, flags);
ATH_SAMP_DBG(noise) = ah->noise;
REG_WRITE_D(ah, AR_MACMISC,
((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
(AR_MACMISC_MISC_OBS_BUS_1 <<
AR_MACMISC_MISC_OBS_BUS_MSB_S)));
for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++)
ATH_SAMP_DBG(dma_dbg_reg_vals[i]) = REG_READ_D(ah,
AR_DMADBG_0 + (i * sizeof(u32)));
ATH_SAMP_DBG(pcu_obs) = REG_READ_D(ah, AR_OBS_BUS_1);
ATH_SAMP_DBG(pcu_cr) = REG_READ_D(ah, AR_CR);
memcpy(ATH_SAMP_DBG(nfCalHist), sc->caldata.nfCalHist,
sizeof(ATH_SAMP_DBG(nfCalHist)));
sc->debug.sampidx = (sc->debug.sampidx + 1) % ATH_DBG_MAX_SAMPLES;
spin_unlock_bh(&sc->debug.samp_lock);
ath9k_ps_restore(sc);
#undef ATH_SAMP_DBG
}
static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
{
#define ATH_SAMP_DBG(c) bb_mac_samp[sampidx].c
struct ath_softc *sc = inode->i_private;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf;
struct ath_dbg_bb_mac_samp *bb_mac_samp;
struct ath9k_nfcal_hist *h;
int i, j, qcuOffset = 0, dcuOffset = 0;
u32 *qcuBase, *dcuBase, size = 30000, len = 0;
u32 sampidx = 0;
u8 *buf;
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
u8 nread;
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return -EAGAIN;
buf = vmalloc(size);
if (!buf)
return -ENOMEM;
bb_mac_samp = vmalloc(sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES);
if (!bb_mac_samp) {
vfree(buf);
return -ENOMEM;
}
/* Account the current state too */
ath9k_debug_samp_bb_mac(sc);
spin_lock_bh(&sc->debug.samp_lock);
memcpy(bb_mac_samp, sc->debug.bb_mac_samp,
sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES);
len += snprintf(buf + len, size - len,
"Current Sample Index: %d\n", sc->debug.sampidx);
spin_unlock_bh(&sc->debug.samp_lock);
len += snprintf(buf + len, size - len,
"Raw DMA Debug Dump:\n");
len += snprintf(buf + len, size - len, "Sample |\t");
for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++)
len += snprintf(buf + len, size - len, " DMA Reg%d |\t", i);
len += snprintf(buf + len, size - len, "\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
len += snprintf(buf + len, size - len, "%d\t", sampidx);
for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++)
len += snprintf(buf + len, size - len, " %08x\t",
ATH_SAMP_DBG(dma_dbg_reg_vals[i]));
len += snprintf(buf + len, size - len, "\n");
}
len += snprintf(buf + len, size - len, "\n");
len += snprintf(buf + len, size - len,
"Sample Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]);
dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]);
for (i = 0; i < ATH9K_NUM_QUEUES; i++,
qcuOffset += 4, dcuOffset += 5) {
if (i == 8) {
qcuOffset = 0;
qcuBase++;
}
if (i == 6) {
dcuOffset = 0;
dcuBase++;
}
if (!sc->debug.stats.txstats[i].queued)
continue;
len += snprintf(buf + len, size - len,
"%4d %7d %2x %1x %2x %2x\n",
sampidx, i,
(*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
(*qcuBase & (0x8 << qcuOffset)) >>
(qcuOffset + 3),
ATH_SAMP_DBG(dma_dbg_reg_vals[2]) &
(0x7 << (i * 3)) >> (i * 3),
(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
}
len += snprintf(buf + len, size - len, "\n");
}
len += snprintf(buf + len, size - len,
"samp qcu_sh qcu_fh qcu_comp dcu_comp dcu_arb dcu_fp "
"ch_idle_dur ch_idle_dur_val txfifo_val0 txfifo_val1 "
"txfifo_dcu0 txfifo_dcu1 pcu_obs AR_CR\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]);
dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]);
len += snprintf(buf + len, size - len, "%4d %5x %5x ", sampidx,
(ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x003c0000) >> 18,
(ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x03c00000) >> 22);
len += snprintf(buf + len, size - len, "%7x %8x ",
(ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x1c000000) >> 26,
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x3));
len += snprintf(buf + len, size - len, "%7x %7x ",
(ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x06000000) >> 25,
(ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x38000000) >> 27);
len += snprintf(buf + len, size - len, "%7d %12d ",
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x000003fc) >> 2,
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000400) >> 10);
len += snprintf(buf + len, size - len, "%12d %12d ",
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000800) >> 11,
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00001000) >> 12);
len += snprintf(buf + len, size - len, "%12d %12d ",
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x0001e000) >> 13,
(ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x001e0000) >> 17);
len += snprintf(buf + len, size - len, "0x%07x 0x%07x\n",
ATH_SAMP_DBG(pcu_obs), ATH_SAMP_DBG(pcu_cr));
}
len += snprintf(buf + len, size - len,
"Sample ChNoise Chain privNF #Reading Readings\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
h = ATH_SAMP_DBG(nfCalHist);
if (!ATH_SAMP_DBG(noise))
continue;
for (i = 0; i < NUM_NF_READINGS; i++) {
if (!(chainmask & (1 << i)) ||
((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
continue;
nread = AR_PHY_CCA_FILTERWINDOW_LENGTH -
h[i].invalidNFcount;
len += snprintf(buf + len, size - len,
"%4d %5d %4d\t %d\t %d\t",
sampidx, ATH_SAMP_DBG(noise),
i, h[i].privNF, nread);
for (j = 0; j < nread; j++)
len += snprintf(buf + len, size - len,
" %d", h[i].nfCalBuffer[j]);
len += snprintf(buf + len, size - len, "\n");
}
}
len += snprintf(buf + len, size - len, "\nCycle counters:\n"
"Sample Total Rxbusy Rxframes Txframes\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
if (!ATH_SAMP_DBG(cc.cycles))
continue;
len += snprintf(buf + len, size - len,
"%4d %08x %08x %08x %08x\n",
sampidx, ATH_SAMP_DBG(cc.cycles),
ATH_SAMP_DBG(cc.rx_busy),
ATH_SAMP_DBG(cc.rx_frame),
ATH_SAMP_DBG(cc.tx_frame));
}
len += snprintf(buf + len, size - len, "Tx status Dump :\n");
len += snprintf(buf + len, size - len,
"Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb "
"isok rts_fail data_fail rate tid qid "
"ba_low ba_high tx_before(ms)\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
if (!ATH_SAMP_DBG(ts[i].jiffies))
continue;
len += snprintf(buf + len, size - len, "%-14d"
"%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-8d "
"%-9d %-4d %-3d %-3d %08x %08x %-11d\n",
sampidx,
ATH_SAMP_DBG(ts[i].rssi_ctl0),
ATH_SAMP_DBG(ts[i].rssi_ctl1),
ATH_SAMP_DBG(ts[i].rssi_ctl2),
ATH_SAMP_DBG(ts[i].rssi_ext0),
ATH_SAMP_DBG(ts[i].rssi_ext1),
ATH_SAMP_DBG(ts[i].rssi_ext2),
ATH_SAMP_DBG(ts[i].rssi),
ATH_SAMP_DBG(ts[i].isok),
ATH_SAMP_DBG(ts[i].rts_fail_cnt),
ATH_SAMP_DBG(ts[i].data_fail_cnt),
ATH_SAMP_DBG(ts[i].rateindex),
ATH_SAMP_DBG(ts[i].tid),
ATH_SAMP_DBG(ts[i].qid),
ATH_SAMP_DBG(ts[i].ba_low),
ATH_SAMP_DBG(ts[i].ba_high),
jiffies_to_msecs(jiffies -
ATH_SAMP_DBG(ts[i].jiffies)));
}
}
len += snprintf(buf + len, size - len, "Rx status Dump :\n");
len += snprintf(buf + len, size - len, "Sample rssi:- ctl0 ctl1 ctl2 "
"ext0 ext1 ext2 comb beacon ant rate rx_before(ms)\n");
for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
if (!ATH_SAMP_DBG(rs[i].jiffies))
continue;
len += snprintf(buf + len, size - len, "%-14d"
"%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-9s %-2d %02x %-13d\n",
sampidx,
ATH_SAMP_DBG(rs[i].rssi_ctl0),
ATH_SAMP_DBG(rs[i].rssi_ctl1),
ATH_SAMP_DBG(rs[i].rssi_ctl2),
ATH_SAMP_DBG(rs[i].rssi_ext0),
ATH_SAMP_DBG(rs[i].rssi_ext1),
ATH_SAMP_DBG(rs[i].rssi_ext2),
ATH_SAMP_DBG(rs[i].rssi),
ATH_SAMP_DBG(rs[i].is_mybeacon) ?
"True" : "False",
ATH_SAMP_DBG(rs[i].antenna),
ATH_SAMP_DBG(rs[i].rate),
jiffies_to_msecs(jiffies -
ATH_SAMP_DBG(rs[i].jiffies)));
}
}
vfree(bb_mac_samp);
file->private_data = buf;
return 0;
#undef ATH_SAMP_DBG
}
static const struct file_operations fops_samps = {
.open = open_file_bb_mac_samps,
.read = ath9k_debugfs_read_buf,
.release = ath9k_debugfs_release_buf,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
#endif
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
...@@ -2051,8 +1766,8 @@ int ath9k_init_debug(struct ath_hw *ah) ...@@ -2051,8 +1766,8 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.debugfs_phy, sc, &fops_rx_chainmask); sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_tx_chainmask); sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, debugfs_create_file("ani", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_disable_ani); sc->debug.debugfs_phy, sc, &fops_ani);
debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->sc_ah->config.enable_paprd); &sc->sc_ah->config.enable_paprd);
debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
...@@ -2087,11 +1802,6 @@ int ath9k_init_debug(struct ath_hw *ah) ...@@ -2087,11 +1802,6 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, sc->debug.debugfs_phy, sc,
&fops_spectral_fft_period); &fops_spectral_fft_period);
#ifdef CONFIG_ATH9K_MAC_DEBUG
debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_samps);
#endif
debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
......
...@@ -251,56 +251,10 @@ struct ath_stats { ...@@ -251,56 +251,10 @@ struct ath_stats {
u32 reset[__RESET_TYPE_MAX]; u32 reset[__RESET_TYPE_MAX];
}; };
#define ATH_DBG_MAX_SAMPLES 10
struct ath_dbg_bb_mac_samp {
u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS];
u32 pcu_obs, pcu_cr, noise;
struct {
u64 jiffies;
int8_t rssi_ctl0;
int8_t rssi_ctl1;
int8_t rssi_ctl2;
int8_t rssi_ext0;
int8_t rssi_ext1;
int8_t rssi_ext2;
int8_t rssi;
bool isok;
u8 rts_fail_cnt;
u8 data_fail_cnt;
u8 rateindex;
u8 qid;
u8 tid;
u32 ba_low;
u32 ba_high;
} ts[ATH_DBG_MAX_SAMPLES];
struct {
u64 jiffies;
int8_t rssi_ctl0;
int8_t rssi_ctl1;
int8_t rssi_ctl2;
int8_t rssi_ext0;
int8_t rssi_ext1;
int8_t rssi_ext2;
int8_t rssi;
bool is_mybeacon;
u8 antenna;
u8 rate;
} rs[ATH_DBG_MAX_SAMPLES];
struct ath_cycle_counters cc;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
};
struct ath9k_debug { struct ath9k_debug {
struct dentry *debugfs_phy; struct dentry *debugfs_phy;
u32 regidx; u32 regidx;
struct ath_stats stats; struct ath_stats stats;
#ifdef CONFIG_ATH9K_MAC_DEBUG
spinlock_t samp_lock;
struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES];
u8 sampidx;
u8 tsidx;
u8 rsidx;
#endif
}; };
int ath9k_init_debug(struct ath_hw *ah); int ath9k_init_debug(struct ath_hw *ah);
...@@ -359,17 +313,4 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc, ...@@ -359,17 +313,4 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc,
#endif /* CONFIG_ATH9K_DEBUGFS */ #endif /* CONFIG_ATH9K_DEBUGFS */
#ifdef CONFIG_ATH9K_MAC_DEBUG
void ath9k_debug_samp_bb_mac(struct ath_softc *sc);
#else
static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
{
}
#endif
#endif /* DEBUG_H */ #endif /* DEBUG_H */
...@@ -208,6 +208,9 @@ struct ath9k_htc_target_rx_stats { ...@@ -208,6 +208,9 @@ struct ath9k_htc_target_rx_stats {
case NL80211_IFTYPE_AP: \ case NL80211_IFTYPE_AP: \
_priv->num_ap_vif++; \ _priv->num_ap_vif++; \
break; \ break; \
case NL80211_IFTYPE_MESH_POINT: \
_priv->num_mbss_vif++; \
break; \
default: \ default: \
break; \ break; \
} \ } \
...@@ -224,6 +227,9 @@ struct ath9k_htc_target_rx_stats { ...@@ -224,6 +227,9 @@ struct ath9k_htc_target_rx_stats {
case NL80211_IFTYPE_AP: \ case NL80211_IFTYPE_AP: \
_priv->num_ap_vif--; \ _priv->num_ap_vif--; \
break; \ break; \
case NL80211_IFTYPE_MESH_POINT: \
_priv->num_mbss_vif--; \
break; \
default: \ default: \
break; \ break; \
} \ } \
...@@ -450,6 +456,7 @@ struct ath9k_htc_priv { ...@@ -450,6 +456,7 @@ struct ath9k_htc_priv {
u8 sta_slot; u8 sta_slot;
u8 vif_sta_pos[ATH9K_HTC_MAX_VIF]; u8 vif_sta_pos[ATH9K_HTC_MAX_VIF];
u8 num_ibss_vif; u8 num_ibss_vif;
u8 num_mbss_vif;
u8 num_sta_vif; u8 num_sta_vif;
u8 num_sta_assoc_vif; u8 num_sta_assoc_vif;
u8 num_ap_vif; u8 num_ap_vif;
......
...@@ -28,7 +28,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) ...@@ -28,7 +28,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
if (priv->ah->opmode == NL80211_IFTYPE_AP) { if (priv->ah->opmode == NL80211_IFTYPE_AP ||
priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) {
qi.tqi_aifs = 1; qi.tqi_aifs = 1;
qi.tqi_cwmin = 0; qi.tqi_cwmin = 0;
qi.tqi_cwmax = 0; qi.tqi_cwmax = 0;
...@@ -628,6 +629,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, ...@@ -628,6 +629,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
ath9k_htc_beacon_config_adhoc(priv, cur_conf); ath9k_htc_beacon_config_adhoc(priv, cur_conf);
break; break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
ath9k_htc_beacon_config_ap(priv, cur_conf); ath9k_htc_beacon_config_ap(priv, cur_conf);
break; break;
...@@ -649,6 +651,7 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) ...@@ -649,6 +651,7 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
ath9k_htc_beacon_config_adhoc(priv, cur_conf); ath9k_htc_beacon_config_adhoc(priv, cur_conf);
break; break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
ath9k_htc_beacon_config_ap(priv, cur_conf); ath9k_htc_beacon_config_ap(priv, cur_conf);
break; break;
......
...@@ -698,7 +698,8 @@ static const struct ieee80211_iface_limit if_limits[] = { ...@@ -698,7 +698,8 @@ static const struct ieee80211_iface_limit if_limits[] = {
{ .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) }, BIT(NL80211_IFTYPE_P2P_CLIENT) },
{ .max = 2, .types = BIT(NL80211_IFTYPE_AP) | { .max = 2, .types = BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) }, BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_MESH_POINT) },
}; };
static const struct ieee80211_iface_combination if_comb = { static const struct ieee80211_iface_combination if_comb = {
...@@ -721,6 +722,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, ...@@ -721,6 +722,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
hw->wiphy->interface_modes = hw->wiphy->interface_modes =
...@@ -728,7 +730,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, ...@@ -728,7 +730,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT); BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_MESH_POINT);
hw->wiphy->iface_combinations = &if_comb; hw->wiphy->iface_combinations = &if_comb;
hw->wiphy->n_iface_combinations = 1; hw->wiphy->n_iface_combinations = 1;
......
...@@ -113,7 +113,9 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ...@@ -113,7 +113,9 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct ath9k_htc_priv *priv = data; struct ath9k_htc_priv *priv = data;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
if ((vif->type == NL80211_IFTYPE_AP) && bss_conf->enable_beacon) if ((vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
bss_conf->enable_beacon)
priv->reconfig_beacon = true; priv->reconfig_beacon = true;
if (bss_conf->assoc) { if (bss_conf->assoc) {
...@@ -180,6 +182,8 @@ static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv) ...@@ -180,6 +182,8 @@ static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv)
priv->ah->opmode = NL80211_IFTYPE_ADHOC; priv->ah->opmode = NL80211_IFTYPE_ADHOC;
else if (priv->num_ap_vif) else if (priv->num_ap_vif)
priv->ah->opmode = NL80211_IFTYPE_AP; priv->ah->opmode = NL80211_IFTYPE_AP;
else if (priv->num_mbss_vif)
priv->ah->opmode = NL80211_IFTYPE_MESH_POINT;
else else
priv->ah->opmode = NL80211_IFTYPE_STATION; priv->ah->opmode = NL80211_IFTYPE_STATION;
...@@ -810,8 +814,7 @@ void ath9k_htc_ani_work(struct work_struct *work) ...@@ -810,8 +814,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
} }
/* Verify whether we must check ANI */ /* Verify whether we must check ANI */
if (ah->config.enable_ani && if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
(timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
aniflag = true; aniflag = true;
common->ani.checkani_timer = timestamp; common->ani.checkani_timer = timestamp;
} }
...@@ -841,8 +844,7 @@ void ath9k_htc_ani_work(struct work_struct *work) ...@@ -841,8 +844,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
* short calibration and long calibration. * short calibration and long calibration.
*/ */
cal_interval = ATH_LONG_CALINTERVAL; cal_interval = ATH_LONG_CALINTERVAL;
if (ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
if (!common->ani.caldone) if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval); cal_interval = min(cal_interval, (u32)short_cal_interval);
...@@ -1052,6 +1054,9 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ...@@ -1052,6 +1054,9 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
hvif.opmode = HTC_M_HOSTAP; hvif.opmode = HTC_M_HOSTAP;
break; break;
case NL80211_IFTYPE_MESH_POINT:
hvif.opmode = HTC_M_WDS; /* close enough */
break;
default: default:
ath_err(common, ath_err(common,
"Interface type %d not yet supported\n", vif->type); "Interface type %d not yet supported\n", vif->type);
...@@ -1084,6 +1089,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ...@@ -1084,6 +1089,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
INC_VIF(priv, vif->type); INC_VIF(priv, vif->type);
if ((vif->type == NL80211_IFTYPE_AP) || if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_MESH_POINT) ||
(vif->type == NL80211_IFTYPE_ADHOC)) (vif->type == NL80211_IFTYPE_ADHOC))
ath9k_htc_assign_bslot(priv, vif); ath9k_htc_assign_bslot(priv, vif);
...@@ -1134,6 +1140,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, ...@@ -1134,6 +1140,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
DEC_VIF(priv, vif->type); DEC_VIF(priv, vif->type);
if ((vif->type == NL80211_IFTYPE_AP) || if ((vif->type == NL80211_IFTYPE_AP) ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
(vif->type == NL80211_IFTYPE_ADHOC)) (vif->type == NL80211_IFTYPE_ADHOC))
ath9k_htc_remove_bslot(priv, vif); ath9k_htc_remove_bslot(priv, vif);
...@@ -1525,9 +1532,10 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1525,9 +1532,10 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) { if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
/* /*
* Disable SWBA interrupt only if there are no * Disable SWBA interrupt only if there are no
* AP/IBSS interfaces. * concurrent AP/mesh or IBSS interfaces.
*/ */
if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) { if ((priv->num_ap_vif + priv->num_mbss_vif <= 1) ||
priv->num_ibss_vif) {
ath_dbg(common, CONFIG, ath_dbg(common, CONFIG,
"Beacon disabled for BSS: %pM\n", "Beacon disabled for BSS: %pM\n",
bss_conf->bssid); bss_conf->bssid);
...@@ -1538,12 +1546,15 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1538,12 +1546,15 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BEACON_INT) { if (changed & BSS_CHANGED_BEACON_INT) {
/* /*
* Reset the HW TSF for the first AP interface. * Reset the HW TSF for the first AP or mesh interface.
*/ */
if ((priv->ah->opmode == NL80211_IFTYPE_AP) && if (priv->nvifs == 1 &&
(priv->nvifs == 1) && ((priv->ah->opmode == NL80211_IFTYPE_AP &&
(priv->num_ap_vif == 1) && vif->type == NL80211_IFTYPE_AP &&
(vif->type == NL80211_IFTYPE_AP)) { priv->num_ap_vif == 1) ||
(priv->ah->opmode == NL80211_IFTYPE_MESH_POINT &&
vif->type == NL80211_IFTYPE_MESH_POINT &&
priv->num_mbss_vif == 1))) {
set_bit(OP_TSF_RESET, &priv->op_flags); set_bit(OP_TSF_RESET, &priv->op_flags);
} }
ath_dbg(common, CONFIG, ath_dbg(common, CONFIG,
......
...@@ -887,7 +887,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) ...@@ -887,7 +887,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
if (priv->rxfilter & FIF_PSPOLL) if (priv->rxfilter & FIF_PSPOLL)
rfilt |= ATH9K_RX_FILTER_PSPOLL; rfilt |= ATH9K_RX_FILTER_PSPOLL;
if (priv->nvifs > 1) if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS)
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
return rfilt; return rfilt;
......
...@@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ...@@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.pcie_clock_req = 0; ah->config.pcie_clock_req = 0;
ah->config.pcie_waen = 0; ah->config.pcie_waen = 0;
ah->config.analog_shiftreg = 1; ah->config.analog_shiftreg = 1;
ah->config.enable_ani = true;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
ah->config.spurchans[i][0] = AR_NO_SPUR; ah->config.spurchans[i][0] = AR_NO_SPUR;
...@@ -549,8 +548,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ...@@ -549,8 +548,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_ver(ah),
ah->eep_ops->get_eeprom_rev(ah)); ah->eep_ops->get_eeprom_rev(ah));
if (ah->config.enable_ani) ath9k_hw_ani_init(ah);
ath9k_hw_ani_init(ah);
return 0; return 0;
} }
...@@ -1245,10 +1243,10 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) ...@@ -1245,10 +1243,10 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
switch (opmode) { switch (opmode) {
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
set |= AR_STA_ID1_ADHOC; set |= AR_STA_ID1_ADHOC;
REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
break; break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
set |= AR_STA_ID1_STA_AP; set |= AR_STA_ID1_STA_AP;
/* fall through */ /* fall through */
...@@ -2246,12 +2244,12 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) ...@@ -2246,12 +2244,12 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
switch (ah->opmode) { switch (ah->opmode) {
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
REG_SET_BIT(ah, AR_TXCFG, REG_SET_BIT(ah, AR_TXCFG,
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
flags |= AR_NDP_TIMER_EN; flags |= AR_NDP_TIMER_EN;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon -
...@@ -2595,13 +2593,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ...@@ -2595,13 +2593,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RTT; pCap->hw_caps |= ATH9K_HW_CAP_RTT;
} }
if (AR_SREV_9280_20_OR_LATER(ah)) { if (AR_SREV_9462(ah))
pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE;
ATH9K_HW_WOW_PATTERN_MATCH_EXACT;
if (AR_SREV_9280(ah))
pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD;
}
if (AR_SREV_9300_20_OR_LATER(ah) && if (AR_SREV_9300_20_OR_LATER(ah) &&
ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
......
...@@ -246,9 +246,7 @@ enum ath9k_hw_caps { ...@@ -246,9 +246,7 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_MCI = BIT(15), ATH9K_HW_CAP_MCI = BIT(15),
ATH9K_HW_CAP_DFS = BIT(16), ATH9K_HW_CAP_DFS = BIT(16),
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
ATH9K_HW_WOW_PATTERN_MATCH_EXACT = BIT(18), ATH9K_HW_CAP_PAPRD = BIT(18),
ATH9K_HW_WOW_PATTERN_MATCH_DWORD = BIT(19),
ATH9K_HW_CAP_PAPRD = BIT(20),
}; };
/* /*
...@@ -291,7 +289,6 @@ struct ath9k_ops_config { ...@@ -291,7 +289,6 @@ struct ath9k_ops_config {
u32 ofdm_trig_high; u32 ofdm_trig_high;
u32 cck_trig_high; u32 cck_trig_high;
u32 cck_trig_low; u32 cck_trig_low;
u32 enable_ani;
u32 enable_paprd; u32 enable_paprd;
int serialize_regmode; int serialize_regmode;
bool rx_intr_mitigation; bool rx_intr_mitigation;
...@@ -423,7 +420,6 @@ struct ath9k_hw_cal_data { ...@@ -423,7 +420,6 @@ struct ath9k_hw_cal_data {
struct ath9k_channel { struct ath9k_channel {
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct ar5416AniState ani;
u16 channel; u16 channel;
u32 channelFlags; u32 channelFlags;
u32 chanmode; u32 chanmode;
...@@ -854,10 +850,10 @@ struct ath_hw { ...@@ -854,10 +850,10 @@ struct ath_hw {
u32 globaltxtimeout; u32 globaltxtimeout;
/* ANI */ /* ANI */
u32 proc_phyerr;
u32 aniperiod; u32 aniperiod;
enum ath9k_ani_cmd ani_function; enum ath9k_ani_cmd ani_function;
u32 ani_skip_count; u32 ani_skip_count;
struct ar5416AniState ani;
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
struct ath_btcoex_hw btcoex_hw; struct ath_btcoex_hw btcoex_hw;
...@@ -882,9 +878,6 @@ struct ath_hw { ...@@ -882,9 +878,6 @@ struct ath_hw {
struct ar5416IniArray iniBank6; struct ar5416IniArray iniBank6;
struct ar5416IniArray iniAddac; struct ar5416IniArray iniAddac;
struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdes;
#ifdef CONFIG_PM_SLEEP
struct ar5416IniArray iniPcieSerdesWow;
#endif
struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniPcieSerdesLowPower;
struct ar5416IniArray iniModesFastClock; struct ar5416IniArray iniModesFastClock;
struct ar5416IniArray iniAdditional; struct ar5416IniArray iniAdditional;
...@@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
} }
#endif #endif
#define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_CCK 22
#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/ath9k_platform.h> #include <linux/ath9k_platform.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/relay.h> #include <linux/relay.h>
#include <net/ieee80211_radiotap.h>
#include "ath9k.h" #include "ath9k.h"
...@@ -613,9 +614,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -613,9 +614,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->sc_pm_lock); spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex); mutex_init(&sc->mutex);
#ifdef CONFIG_ATH9K_MAC_DEBUG
spin_lock_init(&sc->debug.samp_lock);
#endif
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
(unsigned long)sc); (unsigned long)sc);
...@@ -778,12 +776,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -778,12 +776,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_RC_TABLE; IEEE80211_HW_SUPPORTS_RC_TABLE;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
if (AR_SREV_9280_20_OR_LATER(ah))
hw->radiotap_mcs_details |=
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
}
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE; hw->flags |= IEEE80211_HW_MFP_CAPABLE;
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
hw->wiphy->interface_modes = hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
...@@ -804,14 +809,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -804,14 +809,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
device_can_wakeup(sc->dev)) device_can_wakeup(sc->dev))
hw->wiphy->wowlan = &ath9k_wowlan_support; hw->wiphy->wowlan = &ath9k_wowlan_support;
atomic_set(&sc->wow_sleep_proc_intr, -1); atomic_set(&sc->wow_sleep_proc_intr, -1);
atomic_set(&sc->wow_got_bmiss_intr, -1); atomic_set(&sc->wow_got_bmiss_intr, -1);
#endif #endif
hw->queues = 4; hw->queues = 4;
......
...@@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data) ...@@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data)
} }
/* Verify whether we must check ANI */ /* Verify whether we must check ANI */
if (sc->sc_ah->config.enable_ani if ((timestamp - common->ani.checkani_timer) >= ah->config.ani_poll_interval) {
&& (timestamp - common->ani.checkani_timer) >=
ah->config.ani_poll_interval) {
aniflag = true; aniflag = true;
common->ani.checkani_timer = timestamp; common->ani.checkani_timer = timestamp;
} }
...@@ -418,7 +416,6 @@ void ath_ani_calibrate(unsigned long data) ...@@ -418,7 +416,6 @@ void ath_ani_calibrate(unsigned long data)
longcal ? "long" : "", shortcal ? "short" : "", longcal ? "long" : "", shortcal ? "short" : "",
aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
ath9k_debug_samp_bb_mac(sc);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
set_timer: set_timer:
...@@ -428,9 +425,7 @@ void ath_ani_calibrate(unsigned long data) ...@@ -428,9 +425,7 @@ void ath_ani_calibrate(unsigned long data)
* short calibration and long calibration. * short calibration and long calibration.
*/ */
cal_interval = ATH_LONG_CALINTERVAL; cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ah->config.ani_poll_interval);
cal_interval = min(cal_interval,
(u32)ah->config.ani_poll_interval);
if (!common->ani.caldone) if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval); cal_interval = min(cal_interval, (u32)short_cal_interval);
......
...@@ -547,6 +547,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ...@@ -547,6 +547,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_status = 0; rs->rs_status = 0;
rs->rs_flags = 0; rs->rs_flags = 0;
rs->flag = 0;
rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
rs->rs_tstamp = ads.AR_RcvTimestamp; rs->rs_tstamp = ads.AR_RcvTimestamp;
...@@ -586,10 +587,17 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ...@@ -586,10 +587,17 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_moreaggr = rs->rs_moreaggr =
(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
rs->rs_flags =
(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; /* directly mapped flags for ieee80211_rx_status */
rs->rs_flags |= rs->flag |=
(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; (ads.ds_rxstatus3 & AR_GI) ? RX_FLAG_SHORT_GI : 0;
rs->flag |=
(ads.ds_rxstatus3 & AR_2040) ? RX_FLAG_40MHZ : 0;
if (AR_SREV_9280_20_OR_LATER(ah))
rs->flag |=
(ads.ds_rxstatus3 & AR_STBC) ?
/* we can only Nss=1 STBC */
(1 << RX_FLAG_STBC_SHIFT) : 0;
if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
......
...@@ -149,6 +149,7 @@ struct ath_rx_status { ...@@ -149,6 +149,7 @@ struct ath_rx_status {
u32 evm2; u32 evm2;
u32 evm3; u32 evm3;
u32 evm4; u32 evm4;
u32 flag; /* see enum mac80211_rx_flags */
}; };
struct ath_htc_rx_status { struct ath_htc_rx_status {
...@@ -533,7 +534,8 @@ struct ar5416_desc { ...@@ -533,7 +534,8 @@ struct ar5416_desc {
#define AR_2040 0x00000002 #define AR_2040 0x00000002
#define AR_Parallel40 0x00000004 #define AR_Parallel40 0x00000004
#define AR_Parallel40_S 2 #define AR_Parallel40_S 2
#define AR_RxStatusRsvd30 0x000000f8 #define AR_STBC 0x00000008 /* on ar9280 and later */
#define AR_RxStatusRsvd30 0x000000f0
#define AR_RxAntenna 0xffffff00 #define AR_RxAntenna 0xffffff00
#define AR_RxAntenna_S 8 #define AR_RxAntenna_S 8
......
...@@ -193,7 +193,6 @@ static bool ath_prepare_reset(struct ath_softc *sc) ...@@ -193,7 +193,6 @@ static bool ath_prepare_reset(struct ath_softc *sc)
ath_stop_ani(sc); ath_stop_ani(sc);
del_timer_sync(&sc->rx_poll_timer); del_timer_sync(&sc->rx_poll_timer);
ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah); ath9k_hw_disable_interrupts(ah);
if (!ath_drain_all_txq(sc)) if (!ath_drain_all_txq(sc))
...@@ -1273,7 +1272,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1273,7 +1272,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
curchan->center_freq); curchan->center_freq);
} else { } else {
/* perform spectral scan if requested. */ /* perform spectral scan if requested. */
if (sc->scanning && if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
sc->spectral_mode == SPECTRAL_CHANSCAN) sc->spectral_mode == SPECTRAL_CHANSCAN)
ath9k_spectral_scan_trigger(hw); ath9k_spectral_scan_trigger(hw);
} }
...@@ -1689,7 +1688,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ...@@ -1689,7 +1688,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
int ret = 0; int ret = 0;
local_bh_disable(); mutex_lock(&sc->mutex);
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_START:
...@@ -1720,7 +1719,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ...@@ -1720,7 +1719,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
} }
local_bh_enable(); mutex_unlock(&sc->mutex);
return ret; return ret;
} }
...@@ -2004,7 +2003,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -2004,7 +2003,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pcaps = &ah->caps;
int pattern_count = 0; int pattern_count = 0;
int i, byte_cnt; int i, byte_cnt;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
...@@ -2074,36 +2072,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -2074,36 +2072,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
/* Create Disassociate pattern mask */ /* Create Disassociate pattern mask */
if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) { dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03;
if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) { dis_deauth_mask[2] = 0xc0;
/*
* for AR9280, because of hardware limitation, the
* first 4 bytes have to be matched for all patterns.
* the mask for disassociation and de-auth pattern
* matching need to enable the first 4 bytes.
* also the duration field needs to be filled.
*/
dis_deauth_mask[0] = 0xf0;
/*
* fill in duration field
FIXME: what is the exact value ?
*/
dis_deauth_pattern[2] = 0xff;
dis_deauth_pattern[3] = 0xff;
} else {
dis_deauth_mask[0] = 0xfe;
}
dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0;
} else {
dis_deauth_mask[0] = 0xef;
dis_deauth_mask[1] = 0x3f;
dis_deauth_mask[2] = 0x00;
dis_deauth_mask[3] = 0xfc;
}
ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
...@@ -2339,15 +2310,13 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) ...@@ -2339,15 +2310,13 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
static void ath9k_sw_scan_start(struct ieee80211_hw *hw) static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
set_bit(SC_OP_SCANNING, &sc->sc_flags);
sc->scanning = 1;
} }
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
clear_bit(SC_OP_SCANNING, &sc->sc_flags);
sc->scanning = 0;
} }
struct ieee80211_ops ath9k_ops = { struct ieee80211_ops ath9k_ops = {
......
...@@ -868,10 +868,7 @@ static int ath9k_process_rate(struct ath_common *common, ...@@ -868,10 +868,7 @@ static int ath9k_process_rate(struct ath_common *common,
if (rx_stats->rs_rate & 0x80) { if (rx_stats->rs_rate & 0x80) {
/* HT rate */ /* HT rate */
rxs->flag |= RX_FLAG_HT; rxs->flag |= RX_FLAG_HT;
if (rx_stats->rs_flags & ATH9K_RX_2040) rxs->flag |= rx_stats->flag;
rxs->flag |= RX_FLAG_40MHZ;
if (rx_stats->rs_flags & ATH9K_RX_GI)
rxs->flag |= RX_FLAG_SHORT_GI;
rxs->rate_idx = rx_stats->rs_rate & 0x7f; rxs->rate_idx = rx_stats->rs_rate & 0x7f;
return 0; return 0;
} }
...@@ -958,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ...@@ -958,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (rx_stats->rs_more) if (rx_stats->rs_more)
return 0; return 0;
ath9k_process_rssi(common, hw, hdr, rx_stats);
if (ath9k_process_rate(common, hw, rx_stats, rx_status)) if (ath9k_process_rate(common, hw, rx_stats, rx_status))
return -EINVAL; return -EINVAL;
ath9k_process_rssi(common, hw, hdr, rx_stats);
rx_status->band = hw->conf.chandef.chan->band; rx_status->band = hw->conf.chandef.chan->band;
rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->signal = ah->noise + rx_stats->rs_rssi;
......
...@@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event) ...@@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event)
} }
EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
static void ath9k_hw_config_serdes_wow_sleep(struct ath_hw *ah)
{
int i;
for (i = 0; i < ah->iniPcieSerdesWow.ia_rows; i++)
REG_WRITE(ah, INI_RA(&ah->iniPcieSerdesWow, i, 0),
INI_RA(&ah->iniPcieSerdesWow, i, 1));
usleep_range(1000, 1500);
}
static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
...@@ -58,15 +47,8 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) ...@@ -58,15 +47,8 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
return; return;
} else {
if (!AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_RXDP, 0x0);
} }
/* AR9280 WoW has sleep issue, do not set it to sleep */
if (AR_SREV_9280_20(ah))
return;
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
} }
...@@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) ...@@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
/* set the transmit buffer */ /* set the transmit buffer */
ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
if (!(AR_SREV_9300_20_OR_LATER(ah)))
ctl[0] += (KAL_ANTENNA_MODE << 25);
ctl[1] = 0; ctl[1] = 0;
ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */
ctl[4] = 0; ctl[4] = 0;
ctl[7] = (ah->txchainmask) << 2; ctl[7] = (ah->txchainmask) << 2;
ctl[2] = 0xf << 16; /* tx_tries 0 */
if (AR_SREV_9300_20_OR_LATER(ah))
ctl[2] = 0xf << 16; /* tx_tries 0 */
else
ctl[2] = 0x7 << 16; /* tx_tries 0 */
for (i = 0; i < KAL_NUM_DESC_WORDS; i++) for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
/* for AR9300 family 13 descriptor words */ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
if (AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
(KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
...@@ -183,9 +154,6 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, ...@@ -183,9 +154,6 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
if (!AR_SREV_9285_12_OR_LATER(ah))
return;
if (pattern_count < 4) { if (pattern_count < 4) {
/* Pattern 0-3 uses AR_WOW_LENGTH1 register */ /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) << set = (pattern_len & AR_WOW_LENGTH_MAX) <<
...@@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
{ {
u32 wow_status = 0; u32 wow_status = 0;
u32 val = 0, rval; u32 val = 0, rval;
/* /*
* read the WoW status register to know * read the WoW status register to know
* the wakeup reason * the wakeup reason
...@@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
val &= ah->wow_event_mask; val &= ah->wow_event_mask;
if (val) { if (val) {
if (val & AR_WOW_MAGIC_PAT_FOUND) if (val & AR_WOW_MAGIC_PAT_FOUND)
wow_status |= AH_WOW_MAGIC_PATTERN_EN; wow_status |= AH_WOW_MAGIC_PATTERN_EN;
if (AR_WOW_PATTERN_FOUND(val)) if (AR_WOW_PATTERN_FOUND(val))
wow_status |= AH_WOW_USER_PATTERN_EN; wow_status |= AH_WOW_USER_PATTERN_EN;
if (val & AR_WOW_KEEP_ALIVE_FAIL) if (val & AR_WOW_KEEP_ALIVE_FAIL)
wow_status |= AH_WOW_LINK_CHANGE; wow_status |= AH_WOW_LINK_CHANGE;
if (val & AR_WOW_BEACON_FAIL) if (val & AR_WOW_BEACON_FAIL)
wow_status |= AH_WOW_BEACON_MISS; wow_status |= AH_WOW_BEACON_MISS;
} }
/* /*
...@@ -254,17 +218,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -254,17 +218,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
REG_WRITE(ah, AR_WOW_PATTERN, REG_WRITE(ah, AR_WOW_PATTERN,
AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
/*
* tie reset register for AR9002 family of chipsets
* NB: not tieing it back might have some repurcussions.
*/
if (!AR_SREV_9300_20_OR_LATER(ah)) {
REG_SET_BIT(ah, AR_WA, AR_WA_UNTIE_RESET_EN |
AR_WA_POR_SHORT | AR_WA_RESET_EN);
}
/* /*
* restore the beacon threshold to init value * restore the beacon threshold to init value
*/ */
...@@ -277,8 +230,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) ...@@ -277,8 +230,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
* reset to our Chip's Power On Reset so that any PCI-E * reset to our Chip's Power On Reset so that any PCI-E
* reset from the bus will not reset our chip * reset from the bus will not reset our chip
*/ */
if (ah->is_pciexpress)
if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, false); ath9k_hw_configpcipowersave(ah, false);
ah->wow_event_mask = 0; ah->wow_event_mask = 0;
...@@ -298,7 +250,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -298,7 +250,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
* are from the 'pattern_enable' in this function and * are from the 'pattern_enable' in this function and
* 'pattern_count' of ath9k_hw_wow_apply_pattern() * 'pattern_count' of ath9k_hw_wow_apply_pattern()
*/ */
wow_event_mask = ah->wow_event_mask; wow_event_mask = ah->wow_event_mask;
/* /*
...@@ -306,50 +257,15 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -306,50 +257,15 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
* WOW sleep, we do want the Reset from the PCI-E to disturb * WOW sleep, we do want the Reset from the PCI-E to disturb
* our hw state * our hw state
*/ */
if (ah->is_pciexpress) { if (ah->is_pciexpress) {
/* /*
* we need to untie the internal POR (power-on-reset) * we need to untie the internal POR (power-on-reset)
* to the external PCI-E reset. We also need to tie * to the external PCI-E reset. We also need to tie
* the PCI-E Phy reset to the PCI-E reset. * the PCI-E Phy reset to the PCI-E reset.
*/ */
set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
if (AR_SREV_9300_20_OR_LATER(ah)) { clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
set = AR_WA_RESET_EN | AR_WA_POR_SHORT; REG_RMW(ah, AR_WA, set, clr);
clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
REG_RMW(ah, AR_WA, set, clr);
} else {
if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
set = AR9285_WA_DEFAULT;
else
set = AR9280_WA_DEFAULT;
/*
* In AR9280 and AR9285, bit 14 in WA register
* (disable L1) should only be set when device
* enters D3 state and be cleared when device
* comes back to D0
*/
if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
set |= AR_WA_D3_L1_DISABLE;
clr = AR_WA_UNTIE_RESET_EN;
set |= AR_WA_RESET_EN | AR_WA_POR_SHORT;
REG_RMW(ah, AR_WA, set, clr);
/*
* for WoW sleep, we reprogram the SerDes so that the
* PLL and CLK REQ are both enabled. This uses more
* power but otherwise WoW sleep is unstable and the
* chip may disappear.
*/
if (AR_SREV_9285_12_OR_LATER(ah))
ath9k_hw_config_serdes_wow_sleep(ah);
}
} }
/* /*
...@@ -378,7 +294,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -378,7 +294,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
* Program default values for pattern backoff, aifs/slot/KAL count, * Program default values for pattern backoff, aifs/slot/KAL count,
* beacon miss timeout, KAL timeout, etc. * beacon miss timeout, KAL timeout, etc.
*/ */
set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
REG_SET_BIT(ah, AR_WOW_PATTERN, set); REG_SET_BIT(ah, AR_WOW_PATTERN, set);
...@@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
/* /*
* Keep alive timo in ms except AR9280 * Keep alive timo in ms except AR9280
*/ */
if (!pattern_enable || AR_SREV_9280(ah)) if (!pattern_enable)
set = AR_WOW_KEEP_ALIVE_NEVER; set = AR_WOW_KEEP_ALIVE_NEVER;
else else
set = KAL_TIMEOUT * 32; set = KAL_TIMEOUT * 32;
...@@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
/* /*
* Configure MAC WoW Registers * Configure MAC WoW Registers
*/ */
set = 0; set = 0;
/* Send keep alive timeouts anyway */ /* Send keep alive timeouts anyway */
clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
...@@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
else else
set = AR_WOW_KEEP_ALIVE_FAIL_DIS; set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
/*
* FIXME: For now disable keep alive frame
* failure. This seems to sometimes trigger
* unnecessary wake up with AR9485 chipsets.
*/
set = AR_WOW_KEEP_ALIVE_FAIL_DIS; set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
/* /*
* we are relying on a bmiss failure. ensure we have * we are relying on a bmiss failure. ensure we have
* enough threshold to prevent false positives * enough threshold to prevent false positives
...@@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
set |= AR_WOW_MAC_INTR_EN; set |= AR_WOW_MAC_INTR_EN;
REG_RMW(ah, AR_WOW_PATTERN, set, clr); REG_RMW(ah, AR_WOW_PATTERN, set, clr);
/* REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
* For AR9285 and later version of chipsets AR_WOW_PATTERN_SUPPORTED);
* enable WoW pattern match for packets less
* than 256 bytes for all patterns
*/
if (AR_SREV_9285_12_OR_LATER(ah))
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
AR_WOW_PATTERN_SUPPORTED);
/* /*
* Set the power states appropriately and enable PME * Set the power states appropriately and enable PME
...@@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ...@@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
clr = 0; clr = 0;
set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
AR_PMCTRL_PWR_PM_CTRL_ENA; AR_PMCTRL_PWR_PM_CTRL_ENA;
/*
* This is needed for AR9300 chipsets to wake-up
* the host.
*/
if (AR_SREV_9300_20_OR_LATER(ah))
clr = AR_PCIE_PM_CTRL_ENA;
clr = AR_PCIE_PM_CTRL_ENA;
REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { /*
/* * this is needed to prevent the chip waking up
* this is needed to prevent the chip waking up * the host within 3-4 seconds with certain
* the host within 3-4 seconds with certain * platform/BIOS. The fix is to enable
* platform/BIOS. The fix is to enable * D1 & D3 to match original definition and
* D1 & D3 to match original definition and * also match the OTP value. Anyway this
* also match the OTP value. Anyway this * is more related to SW WOW.
* is more related to SW WOW. */
*/ clr = AR_PMCTRL_PWR_STATE_D1D3;
clr = AR_PMCTRL_PWR_STATE_D1D3; REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
}
set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
if (AR_SREV_9300_20_OR_LATER(ah)) { /* to bring down WOW power low margin */
/* to bring down WOW power low margin */ set = BIT(13);
set = BIT(13); REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); /* HW WoW */
/* HW WoW */ clr = BIT(5);
clr = BIT(5); REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
}
ath9k_hw_set_powermode_wow_sleep(ah); ath9k_hw_set_powermode_wow_sleep(ah);
ah->wow_event_mask = wow_event_mask; ah->wow_event_mask = wow_event_mask;
......
...@@ -27,3 +27,15 @@ config WIL6210_ISR_COR ...@@ -27,3 +27,15 @@ config WIL6210_ISR_COR
self-clear when accessed for debug purposes, it makes self-clear when accessed for debug purposes, it makes
such monitoring impossible. such monitoring impossible.
Say y unless you debug interrupts Say y unless you debug interrupts
config ATH6KL_TRACING
bool "wil6210 tracing support"
depends on WIL6210
depends on EVENT_TRACING
default y
---help---
Say Y here to enable tracepoints for the wil6210 driver
using the kernel tracing infrastructure. Select this
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
obj-$(CONFIG_WIL6210) += wil6210.o obj-$(CONFIG_WIL6210) += wil6210.o
wil6210-objs := main.o wil6210-y := main.o
wil6210-objs += netdev.o wil6210-y += netdev.o
wil6210-objs += cfg80211.o wil6210-y += cfg80211.o
wil6210-objs += pcie_bus.o wil6210-y += pcie_bus.o
wil6210-objs += debugfs.o wil6210-y += debugfs.o
wil6210-objs += wmi.o wil6210-y += wmi.o
wil6210-objs += interrupt.o wil6210-y += interrupt.o
wil6210-objs += txrx.o wil6210-y += txrx.o
wil6210-y += debug.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
subdir-ccflags-y += -Werror subdir-ccflags-y += -Werror
endif endif
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
subdir-ccflags-y += -D__CHECK_ENDIAN__ subdir-ccflags-y += -D__CHECK_ENDIAN__
...@@ -322,12 +322,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, ...@@ -322,12 +322,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
* FW don't support scan after connection attempt * FW don't support scan after connection attempt
*/ */
set_bit(wil_status_dontscan, &wil->status); set_bit(wil_status_dontscan, &wil->status);
set_bit(wil_status_fwconnecting, &wil->status);
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
if (rc == 0) { if (rc == 0) {
/* Connect can take lots of time */ /* Connect can take lots of time */
mod_timer(&wil->connect_timer, mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000)); jiffies + msecs_to_jiffies(2000));
} else {
clear_bit(wil_status_dontscan, &wil->status);
clear_bit(wil_status_fwconnecting, &wil->status);
} }
out: out:
......
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "wil6210.h"
#include "trace.h"
int wil_err(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = netdev_err(ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
return ret;
}
int wil_info(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = netdev_info(ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf);
va_end(args);
return ret;
}
int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
trace_wil6210_log_dbg(&vaf);
va_end(args);
return 0;
}
...@@ -418,9 +418,15 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) ...@@ -418,9 +418,15 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
if (skb) { if (skb) {
unsigned char printbuf[16 * 3 + 2]; unsigned char printbuf[16 * 3 + 2];
int i = 0; int i = 0;
int len = skb_headlen(skb); int len = le16_to_cpu(d->dma.length);
void *p = skb->data; void *p = skb->data;
if (len != skb_headlen(skb)) {
seq_printf(s, "!!! len: desc = %d skb = %d\n",
len, skb_headlen(skb));
len = min_t(int, len, skb_headlen(skb));
}
seq_printf(s, " len = %d\n", len); seq_printf(s, " len = %d\n", len);
while (i < len) { while (i < len) {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "wil6210.h" #include "wil6210.h"
#include "trace.h"
/** /**
* Theory of operation: * Theory of operation:
...@@ -103,14 +104,14 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) ...@@ -103,14 +104,14 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
clear_bit(wil_status_irqen, &wil->status); clear_bit(wil_status_irqen, &wil->status);
} }
static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
{ {
iowrite32(WIL6210_IMC_TX, wil->csr + iowrite32(WIL6210_IMC_TX, wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) + HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, IMC)); offsetof(struct RGF_ICR, IMC));
} }
static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{ {
iowrite32(WIL6210_IMC_RX, wil->csr + iowrite32(WIL6210_IMC_RX, wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) + HOSTADDR(RGF_DMA_EP_RX_ICR) +
...@@ -168,6 +169,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) ...@@ -168,6 +169,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_RX_ICR) + HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICR)); offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_rx(isr);
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (!isr) { if (!isr) {
...@@ -180,13 +182,14 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) ...@@ -180,13 +182,14 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
wil_dbg_irq(wil, "RX done\n"); wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
wil_rx_handle(wil); wil_dbg_txrx(wil, "NAPI schedule\n");
napi_schedule(&wil->napi_rx);
} }
if (isr) if (isr)
wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
wil6210_unmask_irq_rx(wil); /* Rx IRQ will be enabled when NAPI processing finished */
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -198,6 +201,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) ...@@ -198,6 +201,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_TX_ICR) + HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR)); offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_tx(isr);
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (!isr) { if (!isr) {
...@@ -208,23 +212,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) ...@@ -208,23 +212,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
wil6210_mask_irq_tx(wil); wil6210_mask_irq_tx(wil);
if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
uint i;
wil_dbg_irq(wil, "TX done\n"); wil_dbg_irq(wil, "TX done\n");
napi_schedule(&wil->napi_tx);
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
for (i = 0; i < 24; i++) { /* clear also all VRING interrupts */
u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); isr &= ~(BIT(25) - 1UL);
if (isr & mask) {
isr &= ~mask;
wil_dbg_irq(wil, "TX done(%i)\n", i);
wil_tx_complete(wil, i);
}
}
} }
if (isr) if (isr)
wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
wil6210_unmask_irq_tx(wil); /* Tx IRQ will be enabled when NAPI processing finished */
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -256,6 +254,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) ...@@ -256,6 +254,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_MISC_ICR) + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR)); offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_misc(isr);
wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
if (!isr) { if (!isr) {
...@@ -301,6 +300,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) ...@@ -301,6 +300,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
struct wil6210_priv *wil = cookie; struct wil6210_priv *wil = cookie;
u32 isr = wil->isr_misc; u32 isr = wil->isr_misc;
trace_wil6210_irq_misc_thread(isr);
wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
if (isr & ISR_MISC_FW_ERROR) { if (isr & ISR_MISC_FW_ERROR) {
...@@ -408,6 +408,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) ...@@ -408,6 +408,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
if (wil6210_debug_irq_mask(wil, pseudo_cause)) if (wil6210_debug_irq_mask(wil, pseudo_cause))
return IRQ_NONE; return IRQ_NONE;
trace_wil6210_irq_pseudo(pseudo_cause);
wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
wil6210_mask_irq_pseudo(wil); wil6210_mask_irq_pseudo(wil);
......
...@@ -56,27 +56,21 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) ...@@ -56,27 +56,21 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
{ {
uint i; uint i;
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
wil_dbg_misc(wil, "%s()\n", __func__); wil_dbg_misc(wil, "%s()\n", __func__);
wil_link_off(wil); wil_link_off(wil);
clear_bit(wil_status_fwconnected, &wil->status); if (test_bit(wil_status_fwconnected, &wil->status)) {
clear_bit(wil_status_fwconnected, &wil->status);
switch (wdev->sme_state) { cfg80211_disconnected(ndev,
case CFG80211_SME_CONNECTED: WLAN_STATUS_UNSPECIFIED_FAILURE,
cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE,
NULL, 0, GFP_KERNEL); NULL, 0, GFP_KERNEL);
break; } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
case CFG80211_SME_CONNECTING:
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL); GFP_KERNEL);
break;
default:
break;
} }
clear_bit(wil_status_fwconnecting, &wil->status);
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
wil_vring_fini_tx(wil, i); wil_vring_fini_tx(wil, i);
...@@ -365,6 +359,9 @@ static int __wil_up(struct wil6210_priv *wil) ...@@ -365,6 +359,9 @@ static int __wil_up(struct wil6210_priv *wil)
/* Rx VRING. After MAC and beacon */ /* Rx VRING. After MAC and beacon */
wil_rx_init(wil); wil_rx_init(wil);
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
return 0; return 0;
} }
...@@ -381,6 +378,9 @@ int wil_up(struct wil6210_priv *wil) ...@@ -381,6 +378,9 @@ int wil_up(struct wil6210_priv *wil)
static int __wil_down(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil)
{ {
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
if (wil->scan_request) { if (wil->scan_request) {
cfg80211_scan_done(wil->scan_request, true); cfg80211_scan_done(wil->scan_request, true);
wil->scan_request = NULL; wil->scan_request = NULL;
......
...@@ -40,6 +40,55 @@ static const struct net_device_ops wil_netdev_ops = { ...@@ -40,6 +40,55 @@ static const struct net_device_ops wil_netdev_ops = {
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
}; };
static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
napi_rx);
int quota = budget;
int done;
wil_rx_handle(wil, &quota);
done = budget - quota;
if (done <= 1) { /* burst ends - only one packet processed */
napi_complete(napi);
wil6210_unmask_irq_rx(wil);
wil_dbg_txrx(wil, "NAPI RX complete\n");
}
wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
return done;
}
static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
napi_tx);
int tx_done = 0;
uint i;
/* always process ALL Tx complete, regardless budget - it is fast */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *vring = &wil->vring_tx[i];
if (!vring->va)
continue;
tx_done += wil_tx_complete(wil, i);
}
if (tx_done <= 1) { /* burst ends - only one packet processed */
napi_complete(napi);
wil6210_unmask_irq_tx(wil);
wil_dbg_txrx(wil, "NAPI TX complete\n");
}
wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
return min(tx_done, budget);
}
void *wil_if_alloc(struct device *dev, void __iomem *csr) void *wil_if_alloc(struct device *dev, void __iomem *csr)
{ {
struct net_device *ndev; struct net_device *ndev;
...@@ -81,6 +130,11 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ...@@ -81,6 +130,11 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev; wdev->netdev = ndev;
netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
WIL6210_NAPI_BUDGET);
netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
wil_link_off(wil); wil_link_off(wil);
return wil; return wil;
......
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/module.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM wil6210
#if !defined(WIL6210_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define WIL6210_TRACE_H
#include <linux/tracepoint.h>
#include "wil6210.h"
#include "txrx.h"
/* create empty functions when tracing is disabled */
#if !defined(CONFIG_WIL6210_TRACING) || defined(__CHECKER__)
#undef TRACE_EVENT
#define TRACE_EVENT(name, proto, ...) \
static inline void trace_ ## name(proto) {}
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(...)
#undef DEFINE_EVENT
#define DEFINE_EVENT(evt_class, name, proto, ...) \
static inline void trace_ ## name(proto) {}
#endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */
DECLARE_EVENT_CLASS(wil6210_wmi,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len),
TP_STRUCT__entry(
__field(u16, id)
__field(u16, buf_len)
__dynamic_array(u8, buf, buf_len)
),
TP_fast_assign(
__entry->id = id;
__entry->buf_len = buf_len;
memcpy(__get_dynamic_array(buf), buf, buf_len);
),
TP_printk(
"id 0x%04x len %d",
__entry->id, __entry->buf_len
)
);
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len)
);
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len)
);
#define WIL6210_MSG_MAX (200)
DECLARE_EVENT_CLASS(wil6210_log_event,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf),
TP_STRUCT__entry(
__dynamic_array(char, msg, WIL6210_MSG_MAX)
),
TP_fast_assign(
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
WIL6210_MSG_MAX,
vaf->fmt,
*vaf->va) >= WIL6210_MSG_MAX);
),
TP_printk("%s", __get_str(msg))
);
DEFINE_EVENT(wil6210_log_event, wil6210_log_err,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(wil6210_log_event, wil6210_log_info,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(wil6210_log_event, wil6210_log_dbg,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
#define wil_pseudo_irq_cause(x) __print_flags(x, "|", \
{BIT_DMA_PSEUDO_CAUSE_RX, "Rx" }, \
{BIT_DMA_PSEUDO_CAUSE_TX, "Tx" }, \
{BIT_DMA_PSEUDO_CAUSE_MISC, "Misc" })
TRACE_EVENT(wil6210_irq_pseudo,
TP_PROTO(u32 x),
TP_ARGS(x),
TP_STRUCT__entry(
__field(u32, x)
),
TP_fast_assign(
__entry->x = x;
),
TP_printk("cause 0x%08x : %s", __entry->x,
wil_pseudo_irq_cause(__entry->x))
);
DECLARE_EVENT_CLASS(wil6210_irq,
TP_PROTO(u32 x),
TP_ARGS(x),
TP_STRUCT__entry(
__field(u32, x)
),
TP_fast_assign(
__entry->x = x;
),
TP_printk("cause 0x%08x", __entry->x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_rx,
TP_PROTO(u32 x),
TP_ARGS(x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_tx,
TP_PROTO(u32 x),
TP_ARGS(x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_misc,
TP_PROTO(u32 x),
TP_ARGS(x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_misc_thread,
TP_PROTO(u32 x),
TP_ARGS(x)
);
TRACE_EVENT(wil6210_rx,
TP_PROTO(u16 index, struct vring_rx_desc *d),
TP_ARGS(index, d),
TP_STRUCT__entry(
__field(u16, index)
__field(unsigned int, len)
__field(u8, mid)
__field(u8, cid)
__field(u8, tid)
__field(u8, type)
__field(u8, subtype)
__field(u16, seq)
__field(u8, mcs)
),
TP_fast_assign(
__entry->index = index;
__entry->len = d->dma.length;
__entry->mid = wil_rxdesc_mid(d);
__entry->cid = wil_rxdesc_cid(d);
__entry->tid = wil_rxdesc_tid(d);
__entry->type = wil_rxdesc_ftype(d);
__entry->subtype = wil_rxdesc_subtype(d);
__entry->seq = wil_rxdesc_seq(d);
__entry->mcs = wil_rxdesc_mcs(d);
),
TP_printk("index %d len %d mid %d cid %d tid %d mcs %d seq 0x%03x"
" type 0x%1x subtype 0x%1x", __entry->index, __entry->len,
__entry->mid, __entry->cid, __entry->tid, __entry->mcs,
__entry->seq, __entry->type, __entry->subtype)
);
TRACE_EVENT(wil6210_tx,
TP_PROTO(u8 vring, u16 index, unsigned int len, u8 frags),
TP_ARGS(vring, index, len, frags),
TP_STRUCT__entry(
__field(u8, vring)
__field(u8, frags)
__field(u16, index)
__field(unsigned int, len)
),
TP_fast_assign(
__entry->vring = vring;
__entry->frags = frags;
__entry->index = index;
__entry->len = len;
),
TP_printk("vring %d index %d len %d frags %d",
__entry->vring, __entry->index, __entry->len, __entry->frags)
);
TRACE_EVENT(wil6210_tx_done,
TP_PROTO(u8 vring, u16 index, unsigned int len, u8 err),
TP_ARGS(vring, index, len, err),
TP_STRUCT__entry(
__field(u8, vring)
__field(u8, err)
__field(u16, index)
__field(unsigned int, len)
),
TP_fast_assign(
__entry->vring = vring;
__entry->index = index;
__entry->len = len;
__entry->err = err;
),
TP_printk("vring %d index %d len %d err 0x%02x",
__entry->vring, __entry->index, __entry->len,
__entry->err)
);
#endif /* WIL6210_TRACE_H || TRACE_HEADER_MULTI_READ*/
#if defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__)
/* we don't want to use include/trace/events */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
/* This part must be outside protection */
#include <trace/define_trace.h>
#endif /* defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__) */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "wil6210.h" #include "wil6210.h"
#include "wmi.h" #include "wmi.h"
#include "txrx.h" #include "txrx.h"
#include "trace.h"
static bool rtap_include_phy_info; static bool rtap_include_phy_info;
module_param(rtap_include_phy_info, bool, S_IRUGO); module_param(rtap_include_phy_info, bool, S_IRUGO);
...@@ -89,8 +90,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) ...@@ -89,8 +90,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
* we can use any * we can use any
*/ */
for (i = 0; i < vring->size; i++) { for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *d = &(vring->va[i].tx); volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
d->dma.status = TX_DMA_STATUS_DU; _d->dma.status = TX_DMA_STATUS_DU;
} }
wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
...@@ -106,30 +107,39 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, ...@@ -106,30 +107,39 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
size_t sz = vring->size * sizeof(vring->va[0]); size_t sz = vring->size * sizeof(vring->va[0]);
while (!wil_vring_is_empty(vring)) { while (!wil_vring_is_empty(vring)) {
dma_addr_t pa;
struct sk_buff *skb;
u16 dmalen;
if (tx) { if (tx) {
volatile struct vring_tx_desc *d = struct vring_tx_desc dd, *d = &dd;
volatile struct vring_tx_desc *_d =
&vring->va[vring->swtail].tx; &vring->va[vring->swtail].tx;
dma_addr_t pa = d->dma.addr_low |
((u64)d->dma.addr_high << 32); *d = *_d;
struct sk_buff *skb = vring->ctx[vring->swtail]; pa = wil_desc_addr(&d->dma.addr);
dmalen = le16_to_cpu(d->dma.length);
skb = vring->ctx[vring->swtail];
if (skb) { if (skb) {
dma_unmap_single(dev, pa, d->dma.length, dma_unmap_single(dev, pa, dmalen,
DMA_TO_DEVICE); DMA_TO_DEVICE);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
vring->ctx[vring->swtail] = NULL; vring->ctx[vring->swtail] = NULL;
} else { } else {
dma_unmap_page(dev, pa, d->dma.length, dma_unmap_page(dev, pa, dmalen,
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
vring->swtail = wil_vring_next_tail(vring); vring->swtail = wil_vring_next_tail(vring);
} else { /* rx */ } else { /* rx */
volatile struct vring_rx_desc *d = struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d =
&vring->va[vring->swtail].rx; &vring->va[vring->swtail].rx;
dma_addr_t pa = d->dma.addr_low |
((u64)d->dma.addr_high << 32); *d = *_d;
struct sk_buff *skb = vring->ctx[vring->swhead]; pa = wil_desc_addr(&d->dma.addr);
dma_unmap_single(dev, pa, d->dma.length, dmalen = le16_to_cpu(d->dma.length);
DMA_FROM_DEVICE); skb = vring->ctx[vring->swhead];
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
kfree_skb(skb); kfree_skb(skb);
wil_vring_advance_head(vring, 1); wil_vring_advance_head(vring, 1);
} }
...@@ -151,7 +161,8 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, ...@@ -151,7 +161,8 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
{ {
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
unsigned int sz = RX_BUF_LEN; unsigned int sz = RX_BUF_LEN;
volatile struct vring_rx_desc *d = &(vring->va[i].rx); struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
dma_addr_t pa; dma_addr_t pa;
/* TODO align */ /* TODO align */
...@@ -169,13 +180,13 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, ...@@ -169,13 +180,13 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
} }
d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
d->dma.addr_low = lower_32_bits(pa); wil_desc_addr_set(&d->dma.addr, pa);
d->dma.addr_high = (u16)upper_32_bits(pa);
/* ip_length don't care */ /* ip_length don't care */
/* b11 don't care */ /* b11 don't care */
/* error don't care */ /* error don't care */
d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
d->dma.length = sz; d->dma.length = cpu_to_le16(sz);
*_d = *d;
vring->ctx[i] = skb; vring->ctx[i] = skb;
return 0; return 0;
...@@ -321,11 +332,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -321,11 +332,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
{ {
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil_to_ndev(wil);
volatile struct vring_rx_desc *d; volatile struct vring_rx_desc *_d;
struct vring_rx_desc *d1; struct vring_rx_desc *d;
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t pa; dma_addr_t pa;
unsigned int sz = RX_BUF_LEN; unsigned int sz = RX_BUF_LEN;
u16 dmalen;
u8 ftype; u8 ftype;
u8 ds_bits; u8 ds_bits;
...@@ -334,32 +346,44 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -334,32 +346,44 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
if (wil_vring_is_empty(vring)) if (wil_vring_is_empty(vring))
return NULL; return NULL;
d = &(vring->va[vring->swhead].rx); _d = &(vring->va[vring->swhead].rx);
if (!(d->dma.status & RX_DMA_STATUS_DU)) { if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
/* it is not error, we just reached end of Rx done area */ /* it is not error, we just reached end of Rx done area */
return NULL; return NULL;
} }
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
skb = vring->ctx[vring->swhead]; skb = vring->ctx[vring->swhead];
d = wil_skb_rxdesc(skb);
*d = *_d;
pa = wil_desc_addr(&d->dma.addr);
vring->ctx[vring->swhead] = NULL;
wil_vring_advance_head(vring, 1);
dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
skb_trim(skb, d->dma.length); dmalen = le16_to_cpu(d->dma.length);
d1 = wil_skb_rxdesc(skb); trace_wil6210_rx(vring->swhead, d);
*d1 = *d; wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, dmalen);
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
wil->stats.last_mcs_rx = wil_rxdesc_mcs(d1); if (dmalen > sz) {
wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
kfree_skb(skb);
return NULL;
}
skb_trim(skb, dmalen);
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
/* use radiotap header only if required */ /* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
wil_rx_add_radiotap_header(wil, skb); wil_rx_add_radiotap_header(wil, skb);
wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
wil_vring_advance_head(vring, 1);
/* no extra checks if in sniffer mode */ /* no extra checks if in sniffer mode */
if (ndev->type != ARPHRD_ETHER) if (ndev->type != ARPHRD_ETHER)
return skb; return skb;
...@@ -368,7 +392,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -368,7 +392,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
* Driver should recognize it by frame type, that is found * Driver should recognize it by frame type, that is found
* in Rx descriptor. If type is not data, it is 802.11 frame as is * in Rx descriptor. If type is not data, it is 802.11 frame as is
*/ */
ftype = wil_rxdesc_ftype(d1) << 2; ftype = wil_rxdesc_ftype(d) << 2;
if (ftype != IEEE80211_FTYPE_DATA) { if (ftype != IEEE80211_FTYPE_DATA) {
wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
/* TODO: process it */ /* TODO: process it */
...@@ -383,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -383,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
return NULL; return NULL;
} }
ds_bits = wil_rxdesc_ds_bits(d1); ds_bits = wil_rxdesc_ds_bits(d);
if (ds_bits == 1) { if (ds_bits == 1) {
/* /*
* HW bug - in ToDS mode, i.e. Rx on AP side, * HW bug - in ToDS mode, i.e. Rx on AP side,
...@@ -425,6 +449,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) ...@@ -425,6 +449,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
/* /*
* Pass Rx packet to the netif. Update statistics. * Pass Rx packet to the netif. Update statistics.
* Called in softirq context (NAPI poll).
*/ */
static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
{ {
...@@ -433,10 +458,7 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) ...@@ -433,10 +458,7 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
skb_orphan(skb); skb_orphan(skb);
if (in_interrupt()) rc = netif_receive_skb(skb);
rc = netif_rx(skb);
else
rc = netif_rx_ni(skb);
if (likely(rc == NET_RX_SUCCESS)) { if (likely(rc == NET_RX_SUCCESS)) {
ndev->stats.rx_packets++; ndev->stats.rx_packets++;
...@@ -450,9 +472,9 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) ...@@ -450,9 +472,9 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
/** /**
* Proceed all completed skb's from Rx VRING * Proceed all completed skb's from Rx VRING
* *
* Safe to call from IRQ * Safe to call from NAPI poll, i.e. softirq with interrupts enabled
*/ */
void wil_rx_handle(struct wil6210_priv *wil) void wil_rx_handle(struct wil6210_priv *wil, int *quota)
{ {
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil_to_ndev(wil);
struct vring *v = &wil->vring_rx; struct vring *v = &wil->vring_rx;
...@@ -463,9 +485,8 @@ void wil_rx_handle(struct wil6210_priv *wil) ...@@ -463,9 +485,8 @@ void wil_rx_handle(struct wil6210_priv *wil)
return; return;
} }
wil_dbg_txrx(wil, "%s()\n", __func__); wil_dbg_txrx(wil, "%s()\n", __func__);
while (NULL != (skb = wil_vring_reap_rx(wil, v))) { while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, (*quota)--;
skb->data, skb_headlen(skb), false);
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
skb->dev = ndev; skb->dev = ndev;
...@@ -600,17 +621,15 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, ...@@ -600,17 +621,15 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
return NULL; return NULL;
} }
static int wil_tx_desc_map(volatile struct vring_tx_desc *d, static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len)
dma_addr_t pa, u32 len)
{ {
d->dma.addr_low = lower_32_bits(pa); wil_desc_addr_set(&d->dma.addr, pa);
d->dma.addr_high = (u16)upper_32_bits(pa);
d->dma.ip_length = 0; d->dma.ip_length = 0;
/* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/
d->dma.b11 = 0/*14 | BIT(7)*/; d->dma.b11 = 0/*14 | BIT(7)*/;
d->dma.error = 0; d->dma.error = 0;
d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
d->dma.length = len; d->dma.length = cpu_to_le16((u16)len);
d->dma.d0 = 0; d->dma.d0 = 0;
d->mac.d[0] = 0; d->mac.d[0] = 0;
d->mac.d[1] = 0; d->mac.d[1] = 0;
...@@ -630,7 +649,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -630,7 +649,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
volatile struct vring_tx_desc *d; struct vring_tx_desc dd, *d = &dd;
volatile struct vring_tx_desc *_d;
u32 swhead = vring->swhead; u32 swhead = vring->swhead;
int avail = wil_vring_avail_tx(vring); int avail = wil_vring_avail_tx(vring);
int nr_frags = skb_shinfo(skb)->nr_frags; int nr_frags = skb_shinfo(skb)->nr_frags;
...@@ -648,7 +668,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -648,7 +668,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
1 + nr_frags); 1 + nr_frags);
return -ENOMEM; return -ENOMEM;
} }
d = &(vring->va[i].tx); _d = &(vring->va[i].tx);
/* FIXME FW can accept only unicast frames for the peer */ /* FIXME FW can accept only unicast frames for the peer */
memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
...@@ -667,25 +687,30 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -667,25 +687,30 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_tx_desc_map(d, pa, skb_headlen(skb)); wil_tx_desc_map(d, pa, skb_headlen(skb));
d->mac.d[2] |= ((nr_frags + 1) << d->mac.d[2] |= ((nr_frags + 1) <<
MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
if (nr_frags)
*_d = *d;
/* middle segments */ /* middle segments */
for (f = 0; f < nr_frags; f++) { for (f = 0; f < nr_frags; f++) {
const struct skb_frag_struct *frag = const struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[f]; &skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag); int len = skb_frag_size(frag);
i = (swhead + f + 1) % vring->size; i = (swhead + f + 1) % vring->size;
d = &(vring->va[i].tx); _d = &(vring->va[i].tx);
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, pa))) if (unlikely(dma_mapping_error(dev, pa)))
goto dma_error; goto dma_error;
wil_tx_desc_map(d, pa, len); wil_tx_desc_map(d, pa, len);
vring->ctx[i] = NULL; vring->ctx[i] = NULL;
*_d = *d;
} }
/* for the last seg only */ /* for the last seg only */
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
d->dma.d0 |= BIT(9); /* BUG: undocumented bit */ d->dma.d0 |= BIT(9); /* BUG: undocumented bit */
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
*_d = *d;
wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false); (const void *)d, sizeof(*d), false);
...@@ -693,6 +718,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -693,6 +718,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
/* advance swhead */ /* advance swhead */
wil_vring_advance_head(vring, nr_frags + 1); wil_vring_advance_head(vring, nr_frags + 1);
wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags);
iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
/* hold reference to skb /* hold reference to skb
* to prevent skb release before accounting * to prevent skb release before accounting
...@@ -705,14 +731,18 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -705,14 +731,18 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
/* unmap what we have mapped */ /* unmap what we have mapped */
/* Note: increment @f to operate with positive index */ /* Note: increment @f to operate with positive index */
for (f++; f > 0; f--) { for (f++; f > 0; f--) {
u16 dmalen;
i = (swhead + f) % vring->size; i = (swhead + f) % vring->size;
d = &(vring->va[i].tx); _d = &(vring->va[i].tx);
d->dma.status = TX_DMA_STATUS_DU; *d = *_d;
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); _d->dma.status = TX_DMA_STATUS_DU;
pa = wil_desc_addr(&d->dma.addr);
dmalen = le16_to_cpu(d->dma.length);
if (vring->ctx[i]) if (vring->ctx[i])
dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
else else
dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
} }
return -EINVAL; return -EINVAL;
...@@ -761,7 +791,6 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -761,7 +791,6 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
break; /* goto drop; */ break; /* goto drop; */
} }
drop: drop:
netif_tx_stop_all_queues(ndev);
ndev->stats.tx_dropped++; ndev->stats.tx_dropped++;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -771,41 +800,48 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -771,41 +800,48 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/** /**
* Clean up transmitted skb's from the Tx VRING * Clean up transmitted skb's from the Tx VRING
* *
* Return number of descriptors cleared
*
* Safe to call from IRQ * Safe to call from IRQ
*/ */
void wil_tx_complete(struct wil6210_priv *wil, int ringid) int wil_tx_complete(struct wil6210_priv *wil, int ringid)
{ {
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil_to_ndev(wil);
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid]; struct vring *vring = &wil->vring_tx[ringid];
int done = 0;
if (!vring->va) { if (!vring->va) {
wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
return; return 0;
} }
wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
while (!wil_vring_is_empty(vring)) { while (!wil_vring_is_empty(vring)) {
volatile struct vring_tx_desc *d1 = volatile struct vring_tx_desc *_d =
&vring->va[vring->swtail].tx; &vring->va[vring->swtail].tx;
struct vring_tx_desc dd, *d = &dd; struct vring_tx_desc dd, *d = &dd;
dma_addr_t pa; dma_addr_t pa;
struct sk_buff *skb; struct sk_buff *skb;
u16 dmalen;
dd = *d1; *d = *_d;
if (!(d->dma.status & TX_DMA_STATUS_DU)) if (!(d->dma.status & TX_DMA_STATUS_DU))
break; break;
dmalen = le16_to_cpu(d->dma.length);
trace_wil6210_tx_done(ringid, vring->swtail, dmalen,
d->dma.error);
wil_dbg_txrx(wil, wil_dbg_txrx(wil,
"Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
vring->swtail, d->dma.length, d->dma.status, vring->swtail, dmalen, d->dma.status,
d->dma.error); d->dma.error);
wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false); (const void *)d, sizeof(*d), false);
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); pa = wil_desc_addr(&d->dma.addr);
skb = vring->ctx[vring->swtail]; skb = vring->ctx[vring->swtail];
if (skb) { if (skb) {
if (d->dma.error == 0) { if (d->dma.error == 0) {
...@@ -815,18 +851,21 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) ...@@ -815,18 +851,21 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid)
ndev->stats.tx_errors++; ndev->stats.tx_errors++;
} }
dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
vring->ctx[vring->swtail] = NULL; vring->ctx[vring->swtail] = NULL;
} else { } else {
dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
} }
d->dma.addr_low = 0; d->dma.addr.addr_low = 0;
d->dma.addr_high = 0; d->dma.addr.addr_high = 0;
d->dma.length = 0; d->dma.length = 0;
d->dma.status = TX_DMA_STATUS_DU; d->dma.status = TX_DMA_STATUS_DU;
vring->swtail = wil_vring_next_tail(vring); vring->swtail = wil_vring_next_tail(vring);
done++;
} }
if (wil_vring_avail_tx(vring) > vring->size/4) if (wil_vring_avail_tx(vring) > vring->size/4)
netif_tx_wake_all_queues(wil_to_ndev(wil)); netif_tx_wake_all_queues(wil_to_ndev(wil));
return done;
} }
...@@ -27,6 +27,28 @@ ...@@ -27,6 +27,28 @@
#define WIL6210_RTAP_SIZE (128) #define WIL6210_RTAP_SIZE (128)
/* Tx/Rx path */ /* Tx/Rx path */
/*
* Common representation of physical address in Vring
*/
struct vring_dma_addr {
__le32 addr_low;
__le16 addr_high;
} __packed;
static inline dma_addr_t wil_desc_addr(struct vring_dma_addr *addr)
{
return le32_to_cpu(addr->addr_low) |
((u64)le16_to_cpu(addr->addr_high) << 32);
}
static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
dma_addr_t pa)
{
addr->addr_low = cpu_to_le32(lower_32_bits(pa));
addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa));
}
/* /*
* Tx descriptor - MAC part * Tx descriptor - MAC part
* [dword 0] * [dword 0]
...@@ -216,13 +238,12 @@ struct vring_tx_mac { ...@@ -216,13 +238,12 @@ struct vring_tx_mac {
struct vring_tx_dma { struct vring_tx_dma {
u32 d0; u32 d0;
u32 addr_low; struct vring_dma_addr addr;
u16 addr_high;
u8 ip_length; u8 ip_length;
u8 b11; /* 0..6: mac_length; 7:ip_version */ u8 b11; /* 0..6: mac_length; 7:ip_version */
u8 error; /* 0..2: err; 3..7: reserved; */ u8 error; /* 0..2: err; 3..7: reserved; */
u8 status; /* 0: used; 1..7; reserved */ u8 status; /* 0: used; 1..7; reserved */
u16 length; __le16 length;
} __packed; } __packed;
/* /*
...@@ -315,13 +336,12 @@ struct vring_rx_mac { ...@@ -315,13 +336,12 @@ struct vring_rx_mac {
struct vring_rx_dma { struct vring_rx_dma {
u32 d0; u32 d0;
u32 addr_low; struct vring_dma_addr addr;
u16 addr_high;
u8 ip_length; u8 ip_length;
u8 b11; u8 b11;
u8 error; u8 error;
u8 status; u8 status;
u16 length; __le16 length;
} __packed; } __packed;
struct vring_tx_desc { struct vring_tx_desc {
......
...@@ -34,9 +34,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) ...@@ -34,9 +34,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL) #define WIL6210_MEM_SIZE (2*1024*1024UL)
#define WIL6210_RX_RING_SIZE (128) #define WIL6210_RX_RING_SIZE (128)
#define WIL6210_TX_RING_SIZE (128) #define WIL6210_TX_RING_SIZE (128)
#define WIL6210_MAX_TX_RINGS (24) #define WIL6210_MAX_TX_RINGS (24) /* HW limit */
#define WIL6210_MAX_CID (8) /* HW limit */
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
/* Hardware definitions begin */ /* Hardware definitions begin */
...@@ -184,6 +186,7 @@ struct vring { ...@@ -184,6 +186,7 @@ struct vring {
enum { /* for wil6210_priv.status */ enum { /* for wil6210_priv.status */
wil_status_fwready = 0, wil_status_fwready = 0,
wil_status_fwconnecting,
wil_status_fwconnected, wil_status_fwconnected,
wil_status_dontscan, wil_status_dontscan,
wil_status_reset_done, wil_status_reset_done,
...@@ -239,6 +242,8 @@ struct wil6210_priv { ...@@ -239,6 +242,8 @@ struct wil6210_priv {
* - consumed in thread by wmi_event_worker * - consumed in thread by wmi_event_worker
*/ */
spinlock_t wmi_ev_lock; spinlock_t wmi_ev_lock;
struct napi_struct napi_rx;
struct napi_struct napi_tx;
/* DMA related */ /* DMA related */
struct vring vring_rx; struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS]; struct vring vring_tx[WIL6210_MAX_TX_RINGS];
...@@ -267,9 +272,13 @@ struct wil6210_priv { ...@@ -267,9 +272,13 @@ struct wil6210_priv {
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev) #define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
#define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg) int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) int wil_err(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
wil_dbg_trace(wil, fmt, ##arg); \
} while (0)
#define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) #define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
...@@ -356,10 +365,12 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, ...@@ -356,10 +365,12 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
void wil_vring_fini_tx(struct wil6210_priv *wil, int id); void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
void wil_tx_complete(struct wil6210_priv *wil, int ringid); int wil_tx_complete(struct wil6210_priv *wil, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
/* RX API */ /* RX API */
void wil_rx_handle(struct wil6210_priv *wil); void wil_rx_handle(struct wil6210_priv *wil, int *quota);
void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_iftype_nl2wmi(enum nl80211_iftype type);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "wil6210.h" #include "wil6210.h"
#include "txrx.h" #include "txrx.h"
#include "wmi.h" #include "wmi.h"
#include "trace.h"
/** /**
* WMI event receiving - theory of operations * WMI event receiving - theory of operations
...@@ -246,6 +247,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) ...@@ -246,6 +247,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
iowrite32(r->head = next_head, wil->csr + HOST_MBOX + iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, tx.head)); offsetof(struct wil6210_mbox_ctl, tx.head));
trace_wil6210_wmi_cmd(cmdid, buf, len);
/* interrupt to FW */ /* interrupt to FW */
iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
...@@ -406,7 +409,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) ...@@ -406,7 +409,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) || if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (wdev->sme_state != CFG80211_SME_CONNECTING) { if (!test_bit(wil_status_fwconnecting, &wil->status)) {
wil_err(wil, "Not in connecting state\n"); wil_err(wil, "Not in connecting state\n");
return; return;
} }
...@@ -430,6 +433,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) ...@@ -430,6 +433,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
} }
clear_bit(wil_status_fwconnecting, &wil->status);
set_bit(wil_status_fwconnected, &wil->status); set_bit(wil_status_fwconnected, &wil->status);
/* FIXME FW can transmit only ucast frames to peer */ /* FIXME FW can transmit only ucast frames to peer */
...@@ -635,8 +639,9 @@ void wmi_recv_cmd(struct wil6210_priv *wil) ...@@ -635,8 +639,9 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
hdr.flags); hdr.flags);
if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) { (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
wil_dbg_wmi(wil, "WMI event 0x%04x\n", u16 id = le16_to_cpu(evt->event.wmi.id);
evt->event.wmi.id); wil_dbg_wmi(wil, "WMI event 0x%04x\n", id);
trace_wil6210_wmi_event(id, &evt->event.wmi, len);
} }
wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
&evt->event.hdr, sizeof(hdr) + len, true); &evt->event.hdr, sizeof(hdr) + len, true);
...@@ -724,7 +729,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) ...@@ -724,7 +729,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.bcon_interval = cpu_to_le16(bi), .bcon_interval = cpu_to_le16(bi),
.network_type = wmi_nettype, .network_type = wmi_nettype,
.disable_sec_offload = 1, .disable_sec_offload = 1,
.channel = chan, .channel = chan - 1,
}; };
struct { struct {
struct wil6210_mbox_hdr_wmi wmi; struct wil6210_mbox_hdr_wmi wmi;
......
...@@ -606,7 +606,8 @@ static int brcmf_sdio_pd_remove(struct platform_device *pdev) ...@@ -606,7 +606,8 @@ static int brcmf_sdio_pd_remove(struct platform_device *pdev)
static struct platform_driver brcmf_sdio_pd = { static struct platform_driver brcmf_sdio_pd = {
.remove = brcmf_sdio_pd_remove, .remove = brcmf_sdio_pd_remove,
.driver = { .driver = {
.name = BRCMFMAC_SDIO_PDATA_NAME .name = BRCMFMAC_SDIO_PDATA_NAME,
.owner = THIS_MODULE,
} }
}; };
......
...@@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, ...@@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
if (supr_status) { if (supr_status) {
update_rate = false; update_rate = false;
if (supr_status == TX_STATUS_SUPR_BADCH) { if (supr_status == TX_STATUS_SUPR_BADCH) {
brcms_err(wlc->hw->d11core, brcms_dbg_ht(wlc->hw->d11core,
"%s: Pkt tx suppressed, illegal channel possibly %d\n", "%s: Pkt tx suppressed, illegal channel possibly %d\n",
__func__, CHSPEC_CHANNEL( __func__, CHSPEC_CHANNEL(
wlc->default_bss->chanspec)); wlc->default_bss->chanspec));
......
config CW1200
tristate "CW1200 WLAN support"
depends on MAC80211 && CFG80211
help
This is a driver for the ST-E CW1100 & CW1200 WLAN chipsets.
This option just enables the driver core, see below for
specific bus support.
if CW1200
config CW1200_WLAN_SDIO
tristate "Support SDIO platforms"
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. You will
need to add appropriate platform data glue in your board setup
file.
menu "Driver debug features"
depends on CW1200 && DEBUG_FS
config CW1200_ETF
bool "Enable CW1200 Engineering Test Framework hooks"
help
If you don't know what this is, just say N.
config CW1200_ITP
bool "Enable ITP access"
help
If you don't know what this is, just say N.
endmenu
endif
cw1200_core-y := \
fwio.o \
txrx.o \
main.o \
queue.o \
hwio.o \
bh.o \
wsm.o \
sta.o \
scan.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
obj-$(CONFIG_CW1200) += cw1200_core.o
obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o
obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o
/*
* Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* Based on:
* ST-Ericsson UMAC CW1200 driver, which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@stericsson.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 <net/mac80211.h>
#include <linux/kthread.h>
#include <linux/timer.h>
#include "cw1200.h"
#include "bh.h"
#include "hwio.h"
#include "wsm.h"
#include "hwbus.h"
#include "debug.h"
#include "fwio.h"
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 */
#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)
/* Suspend state privates */
enum cw1200_bh_pm_state {
CW1200_BH_RESUMED = 0,
CW1200_BH_SUSPEND,
CW1200_BH_SUSPENDED,
CW1200_BH_RESUME,
};
typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv,
u8 *data, size_t size);
static void cw1200_bh_work(struct work_struct *work)
{
struct cw1200_common *priv =
container_of(work, struct cw1200_common, bh_work);
cw1200_bh(priv);
}
int cw1200_register_bh(struct cw1200_common *priv)
{
int err = 0;
/* Realtime workqueue */
priv->bh_workqueue = alloc_workqueue("cw1200_bh",
WQ_MEM_RECLAIM | WQ_HIGHPRI
| WQ_CPU_INTENSIVE, 1);
if (!priv->bh_workqueue)
return -ENOMEM;
INIT_WORK(&priv->bh_work, cw1200_bh_work);
pr_debug("[BH] register.\n");
atomic_set(&priv->bh_rx, 0);
atomic_set(&priv->bh_tx, 0);
atomic_set(&priv->bh_term, 0);
atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
priv->bh_error = 0;
priv->hw_bufs_used = 0;
priv->buf_id_tx = 0;
priv->buf_id_rx = 0;
init_waitqueue_head(&priv->bh_wq);
init_waitqueue_head(&priv->bh_evt_wq);
err = !queue_work(priv->bh_workqueue, &priv->bh_work);
WARN_ON(err);
return err;
}
void cw1200_unregister_bh(struct cw1200_common *priv)
{
atomic_add(1, &priv->bh_term);
wake_up(&priv->bh_wq);
flush_workqueue(priv->bh_workqueue);
destroy_workqueue(priv->bh_workqueue);
priv->bh_workqueue = NULL;
pr_debug("[BH] unregistered.\n");
}
void cw1200_irq_handler(struct cw1200_common *priv)
{
pr_debug("[BH] irq.\n");
/* Disable Interrupts! */
/* NOTE: hwbus_ops->lock already held */
__cw1200_irq_enable(priv, 0);
if (/* WARN_ON */(priv->bh_error))
return;
if (atomic_add_return(1, &priv->bh_rx) == 1)
wake_up(&priv->bh_wq);
}
EXPORT_SYMBOL_GPL(cw1200_irq_handler);
void cw1200_bh_wakeup(struct cw1200_common *priv)
{
pr_debug("[BH] wakeup.\n");
if (priv->bh_error) {
pr_err("[BH] wakeup failed (BH error)\n");
return;
}
if (atomic_add_return(1, &priv->bh_tx) == 1)
wake_up(&priv->bh_wq);
}
int cw1200_bh_suspend(struct cw1200_common *priv)
{
pr_debug("[BH] suspend.\n");
if (priv->bh_error) {
wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n");
return -EINVAL;
}
atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND);
wake_up(&priv->bh_wq);
return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
(CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)),
1 * HZ) ? 0 : -ETIMEDOUT;
}
int cw1200_bh_resume(struct cw1200_common *priv)
{
pr_debug("[BH] resume.\n");
if (priv->bh_error) {
wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n");
return -EINVAL;
}
atomic_set(&priv->bh_suspend, CW1200_BH_RESUME);
wake_up(&priv->bh_wq);
return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
(CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)),
1 * HZ) ? 0 : -ETIMEDOUT;
}
static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv)
{
++priv->hw_bufs_used;
}
int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
{
int ret = 0;
int hw_bufs_used = priv->hw_bufs_used;
priv->hw_bufs_used -= count;
if (WARN_ON(priv->hw_bufs_used < 0))
ret = -1;
else if (hw_bufs_used >= priv->wsm_caps.input_buffers)
ret = 1;
if (!priv->hw_bufs_used)
wake_up(&priv->bh_evt_wq);
return ret;
}
static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv,
u16 *ctrl_reg)
{
int ret;
ret = cw1200_reg_read_16(priv,
ST90TDS_CONTROL_REG_ID, ctrl_reg);
if (ret) {
ret = cw1200_reg_read_16(priv,
ST90TDS_CONTROL_REG_ID, ctrl_reg);
if (ret)
pr_err("[BH] Failed to read control register.\n");
}
return ret;
}
static int cw1200_device_wakeup(struct cw1200_common *priv)
{
u16 ctrl_reg;
int ret;
pr_debug("[BH] Device wakeup.\n");
/* First, set the dpll register */
ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID,
cw1200_dpll_from_clk(priv->hw_refclk));
if (WARN_ON(ret))
return ret;
/* To force the device to be always-on, the host sets WLAN_UP to 1 */
ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
ST90TDS_CONT_WUP_BIT);
if (WARN_ON(ret))
return ret;
ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg);
if (WARN_ON(ret))
return ret;
/* If the device returns WLAN_RDY as 1, the device is active and will
* remain active. */
if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
pr_debug("[BH] Device awake.\n");
return 1;
}
return 0;
}
/* Must be called from BH thraed. */
void cw1200_enable_powersave(struct cw1200_common *priv,
bool enable)
{
pr_debug("[BH] Powerave is %s.\n",
enable ? "enabled" : "disabled");
priv->powersave_enabled = enable;
}
static int cw1200_bh_rx_helper(struct cw1200_common *priv,
uint16_t *ctrl_reg,
int *tx)
{
size_t read_len = 0;
struct sk_buff *skb_rx = NULL;
struct wsm_hdr *wsm;
size_t wsm_len;
u16 wsm_id;
u8 wsm_seq;
int rx_resync = 1;
size_t alloc_len;
u8 *data;
read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2;
if (!read_len)
return 0; /* No more work */
if (WARN_ON((read_len < sizeof(struct wsm_hdr)) ||
(read_len > EFFECTIVE_BUF_SIZE))) {
pr_debug("Invalid read len: %zu (%04x)",
read_len, *ctrl_reg);
goto err;
}
/* Add SIZE of PIGGYBACK reg (CONTROL Reg)
* to the NEXT Message length + 2 Bytes for SKB */
read_len = read_len + 2;
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)) {
pr_debug("Read aligned len: %zu\n",
alloc_len);
}
skb_rx = dev_alloc_skb(alloc_len);
if (WARN_ON(!skb_rx))
goto err;
skb_trim(skb_rx, 0);
skb_put(skb_rx, read_len);
data = skb_rx->data;
if (WARN_ON(!data))
goto err;
if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) {
pr_err("rx blew up, len %zu\n", alloc_len);
goto err;
}
/* Piggyback */
*ctrl_reg = __le16_to_cpu(
((__le16 *)data)[alloc_len / 2 - 1]);
wsm = (struct wsm_hdr *)data;
wsm_len = __le16_to_cpu(wsm->len);
if (WARN_ON(wsm_len > read_len))
goto err;
if (priv->wsm_enable_wsm_dumps)
print_hex_dump_bytes("<-- ",
DUMP_PREFIX_NONE,
data, wsm_len);
wsm_id = __le16_to_cpu(wsm->id) & 0xFFF;
wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7;
skb_trim(skb_rx, wsm_len);
if (wsm_id == 0x0800) {
wsm_handle_exception(priv,
&data[sizeof(*wsm)],
wsm_len - sizeof(*wsm));
goto err;
} else if (!rx_resync) {
if (WARN_ON(wsm_seq != priv->wsm_rx_seq))
goto err;
}
priv->wsm_rx_seq = (wsm_seq + 1) & 7;
rx_resync = 0;
if (wsm_id & 0x0400) {
int rc = wsm_release_tx_buffer(priv, 1);
if (WARN_ON(rc < 0))
return rc;
else if (rc > 0)
*tx = 1;
}
/* cw1200_wsm_rx takes care on SKB livetime */
if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx)))
goto err;
if (skb_rx) {
dev_kfree_skb(skb_rx);
skb_rx = NULL;
}
return 0;
err:
if (skb_rx) {
dev_kfree_skb(skb_rx);
skb_rx = NULL;
}
return -1;
}
static int cw1200_bh_tx_helper(struct cw1200_common *priv,
int *pending_tx,
int *tx_burst)
{
size_t tx_len;
u8 *data;
int ret;
struct wsm_hdr *wsm;
if (priv->device_can_sleep) {
ret = cw1200_device_wakeup(priv);
if (WARN_ON(ret < 0)) { /* Error in wakeup */
*pending_tx = 1;
return 0;
} else if (ret) { /* Woke up */
priv->device_can_sleep = false;
} else { /* Did not awake */
*pending_tx = 1;
return 0;
}
}
wsm_alloc_tx_buffer(priv);
ret = wsm_get_tx(priv, &data, &tx_len, tx_burst);
if (ret <= 0) {
wsm_release_tx_buffer(priv, 1);
if (WARN_ON(ret < 0))
return ret; /* Error */
return 0; /* No work */
}
wsm = (struct wsm_hdr *)data;
BUG_ON(tx_len < sizeof(*wsm));
BUG_ON(__le16_to_cpu(wsm->len) != tx_len);
atomic_add(1, &priv->bh_tx);
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))
pr_debug("Write aligned len: %zu\n", tx_len);
wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX));
wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq));
if (WARN_ON(cw1200_data_write(priv, data, tx_len))) {
pr_err("tx blew up, len %zu\n", tx_len);
wsm_release_tx_buffer(priv, 1);
return -1; /* Error */
}
if (priv->wsm_enable_wsm_dumps)
print_hex_dump_bytes("--> ",
DUMP_PREFIX_NONE,
data,
__le16_to_cpu(wsm->len));
wsm_txed(priv, data);
priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX;
if (*tx_burst > 1) {
cw1200_debug_tx_burst(priv);
return 1; /* Work remains */
}
return 0;
}
static int cw1200_bh(void *arg)
{
struct cw1200_common *priv = arg;
int rx, tx, term, suspend;
u16 ctrl_reg = 0;
int tx_allowed;
int pending_tx = 0;
int tx_burst;
long status;
u32 dummy;
int ret;
for (;;) {
if (!priv->hw_bufs_used &&
priv->powersave_enabled &&
!priv->device_can_sleep &&
!atomic_read(&priv->recent_scan)) {
status = 1 * HZ;
pr_debug("[BH] Device wakedown. No data.\n");
cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0);
priv->device_can_sleep = true;
} else if (priv->hw_bufs_used) {
/* Interrupt loss detection */
status = 1 * HZ;
} else {
status = MAX_SCHEDULE_TIMEOUT;
}
/* Dummy Read for SDIO retry mechanism*/
if ((priv->hw_type != -1) &&
(atomic_read(&priv->bh_rx) == 0) &&
(atomic_read(&priv->bh_tx) == 0))
cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID,
&dummy, sizeof(dummy));
pr_debug("[BH] waiting ...\n");
status = wait_event_interruptible_timeout(priv->bh_wq, ({
rx = atomic_xchg(&priv->bh_rx, 0);
tx = atomic_xchg(&priv->bh_tx, 0);
term = atomic_xchg(&priv->bh_term, 0);
suspend = pending_tx ?
0 : atomic_read(&priv->bh_suspend);
(rx || tx || term || suspend || priv->bh_error);
}), status);
pr_debug("[BH] - rx: %d, tx: %d, term: %d, suspend: %d, status: %ld\n",
rx, tx, term, suspend, status);
/* Did an error occur? */
if ((status < 0 && status != -ERESTARTSYS) ||
term || priv->bh_error) {
break;
}
if (!status) { /* wait_event timed out */
unsigned long timestamp = jiffies;
long timeout;
int pending = 0;
int i;
/* Check to see if we have any outstanding frames */
if (priv->hw_bufs_used && (!rx || !tx)) {
wiphy_warn(priv->hw->wiphy,
"Missed interrupt? (%d frames outstanding)\n",
priv->hw_bufs_used);
rx = 1;
/* Get a timestamp of "oldest" frame */
for (i = 0; i < 4; ++i)
pending += cw1200_queue_get_xmit_timestamp(
&priv->tx_queue[i],
&timestamp,
priv->pending_frame_id);
/* Check if frame transmission is timed out.
* Add an extra second with respect to possible
* interrupt loss.
*/
timeout = timestamp +
WSM_CMD_LAST_CHANCE_TIMEOUT +
1 * HZ -
jiffies;
/* And terminate BH thread if the frame is "stuck" */
if (pending && timeout < 0) {
wiphy_warn(priv->hw->wiphy,
"Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n",
priv->hw_bufs_used, pending,
timestamp, jiffies);
break;
}
} else if (!priv->device_can_sleep &&
!atomic_read(&priv->recent_scan)) {
pr_debug("[BH] Device wakedown. Timeout.\n");
cw1200_reg_write_16(priv,
ST90TDS_CONTROL_REG_ID, 0);
priv->device_can_sleep = true;
}
goto done;
} else if (suspend) {
pr_debug("[BH] Device suspend.\n");
if (priv->powersave_enabled) {
pr_debug("[BH] Device wakedown. Suspend.\n");
cw1200_reg_write_16(priv,
ST90TDS_CONTROL_REG_ID, 0);
priv->device_can_sleep = true;
}
atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED);
wake_up(&priv->bh_evt_wq);
status = wait_event_interruptible(priv->bh_wq,
CW1200_BH_RESUME == atomic_read(&priv->bh_suspend));
if (status < 0) {
wiphy_err(priv->hw->wiphy,
"Failed to wait for resume: %ld.\n",
status);
break;
}
pr_debug("[BH] Device resume.\n");
atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
wake_up(&priv->bh_evt_wq);
atomic_add(1, &priv->bh_rx);
goto done;
}
rx:
tx += pending_tx;
pending_tx = 0;
if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
break;
/* Don't bother trying to rx unless we have data to read */
if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
if (ret < 0)
break;
/* Double up here if there's more data.. */
if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
if (ret < 0)
break;
}
}
tx:
if (tx) {
tx = 0;
BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers);
tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used;
tx_allowed = tx_burst > 0;
if (!tx_allowed) {
/* Buffers full. Ensure we process tx
* after we handle rx..
*/
pending_tx = tx;
goto done_rx;
}
ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst);
if (ret < 0)
break;
if (ret > 0) /* More to transmit */
tx = ret;
/* Re-read ctrl reg */
if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
break;
}
done_rx:
if (priv->bh_error)
break;
if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK)
goto rx;
if (tx)
goto tx;
done:
/* Re-enable device interrupts */
priv->hwbus_ops->lock(priv->hwbus_priv);
__cw1200_irq_enable(priv, 1);
priv->hwbus_ops->unlock(priv->hwbus_priv);
}
/* Explicitly disable device interrupts */
priv->hwbus_ops->lock(priv->hwbus_priv);
__cw1200_irq_enable(priv, 0);
priv->hwbus_ops->unlock(priv->hwbus_priv);
if (!term) {
pr_err("[BH] Fatal error, exiting.\n");
priv->bh_error = 1;
/* TODO: schedule_work(recovery) */
}
return 0;
}
/*
* Device handling thread interface for mac80211 ST-Ericsson CW1200 drivers
*
* 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_BH_H
#define CW1200_BH_H
/* extern */ struct cw1200_common;
int cw1200_register_bh(struct cw1200_common *priv);
void cw1200_unregister_bh(struct cw1200_common *priv);
void cw1200_irq_handler(struct cw1200_common *priv);
void cw1200_bh_wakeup(struct cw1200_common *priv);
int cw1200_bh_suspend(struct cw1200_common *priv);
int cw1200_bh_resume(struct cw1200_common *priv);
/* Must be called from BH thread. */
void cw1200_enable_powersave(struct cw1200_common *priv,
bool enable);
int wsm_release_tx_buffer(struct cw1200_common *priv, int count);
#endif /* CW1200_BH_H */
/*
* Common private data for ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* Based on the mac80211 Prism54 code, which is
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
*
* 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_H
#define CW1200_H
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <net/mac80211.h>
#include "queue.h"
#include "wsm.h"
#include "scan.h"
#include "txrx.h"
#include "pm.h"
/* Forward declarations */
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)
#define CW1200_LINK_ID_AFTER_DTIM (CW1200_MAX_STA_IN_AP_MODE + 1)
#define CW1200_LINK_ID_UAPSD (CW1200_MAX_STA_IN_AP_MODE + 2)
#define CW1200_LINK_ID_MAX (CW1200_MAX_STA_IN_AP_MODE + 3)
#define CW1200_MAX_REQUEUE_ATTEMPTS (5)
#define CW1200_MAX_TID (8)
#define CW1200_BLOCK_ACK_CNT (30)
#define CW1200_BLOCK_ACK_THLD (800)
#define CW1200_BLOCK_ACK_HIST (3)
#define CW1200_BLOCK_ACK_INTERVAL (1 * HZ / CW1200_BLOCK_ACK_HIST)
#define CW1200_JOIN_TIMEOUT (1 * HZ)
#define CW1200_AUTH_TIMEOUT (5 * HZ)
struct cw1200_ht_info {
struct ieee80211_sta_ht_cap ht_cap;
enum nl80211_channel_type channel_type;
u16 operation_mode;
};
/* Please keep order */
enum cw1200_join_status {
CW1200_JOIN_STATUS_PASSIVE = 0,
CW1200_JOIN_STATUS_MONITOR,
CW1200_JOIN_STATUS_JOINING,
CW1200_JOIN_STATUS_PRE_STA,
CW1200_JOIN_STATUS_STA,
CW1200_JOIN_STATUS_IBSS,
CW1200_JOIN_STATUS_AP,
};
enum cw1200_link_status {
CW1200_LINK_OFF,
CW1200_LINK_RESERVE,
CW1200_LINK_SOFT,
CW1200_LINK_HARD,
CW1200_LINK_RESET,
CW1200_LINK_RESET_REMAP,
};
extern int cw1200_power_mode;
extern const char * const cw1200_fw_types[];
struct cw1200_link_entry {
unsigned long timestamp;
enum cw1200_link_status status;
enum cw1200_link_status prev_status;
u8 mac[ETH_ALEN];
u8 buffered[CW1200_MAX_TID];
struct sk_buff_head rx_queue;
};
struct cw1200_common {
/* interfaces to the rest of the stack */
struct ieee80211_hw *hw;
struct ieee80211_vif *vif;
struct device *pdev;
/* Statistics */
struct ieee80211_low_level_stats stats;
/* Our macaddr */
u8 mac_addr[ETH_ALEN];
/* Hardware interface */
const struct hwbus_ops *hwbus_ops;
struct hwbus_priv *hwbus_priv;
/* Hardware information */
enum {
HIF_9000_SILICON_VERSATILE = 0,
HIF_8601_VERSATILE,
HIF_8601_SILICON,
} hw_type;
enum {
CW1200_HW_REV_CUT10 = 10,
CW1200_HW_REV_CUT11 = 11,
CW1200_HW_REV_CUT20 = 20,
CW1200_HW_REV_CUT22 = 22,
CW1X60_HW_REV = 40,
} hw_revision;
int hw_refclk;
bool hw_have_5ghz;
const struct firmware *sdd;
char *sdd_path;
struct cw1200_debug_priv *debug;
struct workqueue_struct *workqueue;
struct mutex conf_mutex;
struct cw1200_queue tx_queue[4];
struct cw1200_queue_stats tx_queue_stats;
int tx_burst_idx;
/* firmware/hardware info */
unsigned int tx_hdr_len;
/* Radio data */
int output_power;
/* BBP/MAC state */
struct ieee80211_rate *rates;
struct ieee80211_rate *mcs_rates;
struct ieee80211_channel *channel;
struct wsm_edca_params edca;
struct wsm_tx_queue_params tx_queue_params;
struct wsm_mib_association_mode association_mode;
struct wsm_set_bss_params bss_params;
struct cw1200_ht_info ht_info;
struct wsm_set_pm powersave_mode;
struct wsm_set_pm firmware_ps_mode;
int cqm_rssi_thold;
unsigned cqm_rssi_hyst;
bool cqm_use_rssi;
int cqm_beacon_loss_count;
int channel_switch_in_progress;
wait_queue_head_t channel_switch_done;
u8 long_frame_max_tx_count;
u8 short_frame_max_tx_count;
int mode;
bool enable_beacon;
int beacon_int;
bool listening;
struct wsm_rx_filter rx_filter;
struct wsm_mib_multicast_filter multicast_filter;
bool has_multicast_subscription;
bool disable_beacon_filter;
struct work_struct update_filtering_work;
struct work_struct set_beacon_wakeup_period_work;
u8 ba_rx_tid_mask;
u8 ba_tx_tid_mask;
struct cw1200_pm_state pm_state;
struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo;
struct wsm_uapsd_info uapsd_info;
bool setbssparams_done;
bool bt_present;
u8 conf_listen_interval;
u32 listen_interval;
u32 erp_info;
u32 rts_threshold;
/* BH */
atomic_t bh_rx;
atomic_t bh_tx;
atomic_t bh_term;
atomic_t bh_suspend;
struct workqueue_struct *bh_workqueue;
struct work_struct bh_work;
int bh_error;
wait_queue_head_t bh_wq;
wait_queue_head_t bh_evt_wq;
u8 buf_id_tx;
u8 buf_id_rx;
u8 wsm_rx_seq;
u8 wsm_tx_seq;
int hw_bufs_used;
bool powersave_enabled;
bool device_can_sleep;
/* Scan status */
struct cw1200_scan scan;
/* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid
* FW issue with sleeping/waking up. */
atomic_t recent_scan;
struct delayed_work clear_recent_scan_work;
/* WSM */
struct wsm_startup_ind wsm_caps;
struct mutex wsm_cmd_mux;
struct wsm_buf wsm_cmd_buf;
struct wsm_cmd wsm_cmd;
wait_queue_head_t wsm_cmd_wq;
wait_queue_head_t wsm_startup_done;
int firmware_ready;
atomic_t tx_lock;
/* WSM debug */
int wsm_enable_wsm_dumps;
/* WSM Join */
enum cw1200_join_status join_status;
u32 pending_frame_id;
bool join_pending;
struct delayed_work join_timeout;
struct work_struct unjoin_work;
struct work_struct join_complete_work;
int join_complete_status;
int join_dtim_period;
bool delayed_unjoin;
/* TX/RX and security */
s8 wep_default_key_id;
struct work_struct wep_key_work;
u32 key_map;
struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1];
/* AP powersave */
u32 link_id_map;
struct cw1200_link_entry link_id_db[CW1200_MAX_STA_IN_AP_MODE];
struct work_struct link_id_work;
struct delayed_work link_id_gc_work;
u32 sta_asleep_mask;
u32 pspoll_mask;
bool aid0_bit_set;
spinlock_t ps_state_lock; /* Protect power save state */
bool buffered_multicasts;
bool tx_multicast;
struct work_struct set_tim_work;
struct work_struct set_cts_work;
struct work_struct multicast_start_work;
struct work_struct multicast_stop_work;
struct timer_list mcast_timeout;
/* WSM events and CQM implementation */
spinlock_t event_queue_lock; /* Protect event queue */
struct list_head event_queue;
struct work_struct event_handler;
struct delayed_work bss_loss_work;
spinlock_t bss_loss_lock; /* Protect BSS loss state */
int bss_loss_state;
int bss_loss_confirm_id;
int delayed_link_loss;
struct work_struct bss_params_work;
/* TX rate policy cache */
struct tx_policy_cache tx_policy_cache;
struct work_struct tx_policy_upload_work;
/* legacy PS mode switch in suspend */
int ps_mode_switch_in_progress;
wait_queue_head_t ps_mode_switch_done;
/* Workaround for WFD testcase 6.1.10*/
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 {
int link_id;
};
/* interfaces for the drivers */
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,
const char *sdd_path, bool have_5ghz);
void cw1200_core_release(struct cw1200_common *self);
#define FWLOAD_BLOCK_SIZE (1024)
static inline int cw1200_is_ht(const struct cw1200_ht_info *ht_info)
{
return ht_info->channel_type != NL80211_CHAN_NO_HT;
}
static inline int cw1200_ht_greenfield(const struct cw1200_ht_info *ht_info)
{
return cw1200_is_ht(ht_info) &&
(ht_info->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
!(ht_info->operation_mode &
IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
}
static inline int cw1200_ht_ampdu_density(const struct cw1200_ht_info *ht_info)
{
if (!cw1200_is_ht(ht_info))
return 0;
return ht_info->ht_cap.ampdu_density;
}
#endif /* CW1200_H */
/*
* Mac80211 SDIO driver for ST-Ericsson CW1200 device
*
* 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/gpio.h>
#include <linux/delay.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <net/mac80211.h>
#include "cw1200.h"
#include "hwbus.h"
#include <linux/platform_data/net-cw1200.h>
#include "hwio.h"
MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SDIO driver");
MODULE_LICENSE("GPL");
#define SDIO_BLOCK_SIZE (512)
/* 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;
};
#ifndef SDIO_VENDOR_ID_STE
#define SDIO_VENDOR_ID_STE 0x0020
#endif
#ifndef SDIO_DEVICE_ID_STE_CW1200
#define SDIO_DEVICE_ID_STE_CW1200 0x2280
#endif
static const struct sdio_device_id cw1200_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) },
{ /* end: all zeroes */ },
};
/* hwbus_ops implemetation */
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 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 hwbus_priv *self)
{
sdio_claim_host(self->func);
}
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 hwbus_priv *self = sdio_get_drvdata(func);
/* note: sdio_host already claimed here. */
if (self->core)
cw1200_irq_handler(self->core);
}
static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id)
{
return IRQ_WAKE_THREAD;
}
static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
{
struct hwbus_priv *self = dev_id;
if (self->core) {
sdio_claim_host(self->func);
cw1200_irq_handler(self->core);
sdio_release_host(self->func);
return IRQ_HANDLED;
} else {
return IRQ_NONE;
}
}
static int cw1200_request_irq(struct hwbus_priv *self)
{
int ret;
u8 cccr;
cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
if (WARN_ON(ret))
goto err;
/* Master interrupt enable ... */
cccr |= BIT(0);
/* ... for our function */
cccr |= BIT(self->func->num);
sdio_f0_writeb(self->func, cccr, SDIO_CCCR_IENx, &ret);
if (WARN_ON(ret))
goto err;
ret = enable_irq_wake(self->pdata->irq);
if (WARN_ON(ret))
goto err;
/* Request the IRQ */
ret = request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq,
cw1200_gpio_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"cw1200_wlan_irq", self);
if (WARN_ON(ret))
goto err;
return 0;
err:
return ret;
}
static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self)
{
int ret = 0;
pr_debug("SW IRQ subscribe\n");
sdio_claim_host(self->func);
if (self->pdata->irq)
ret = cw1200_request_irq(self);
else
ret = sdio_claim_irq(self->func, cw1200_sdio_irq_handler);
sdio_release_host(self->func);
return ret;
}
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);
free_irq(self->pdata->irq, self);
} else {
sdio_claim_host(self->func);
ret = sdio_release_irq(self->func);
sdio_release_host(self->func);
}
return ret;
}
static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
{
if (pdata->reset) {
gpio_set_value(pdata->reset, 0);
msleep(30); /* Min is 2 * CLK32K cycles */
gpio_free(pdata->reset);
}
if (pdata->power_ctrl)
pdata->power_ctrl(pdata, false);
if (pdata->clk_ctrl)
pdata->clk_ctrl(pdata, false);
return 0;
}
static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
{
/* Ensure I/Os are pulled low */
if (pdata->reset) {
gpio_request(pdata->reset, "cw1200_wlan_reset");
gpio_direction_output(pdata->reset, 0);
}
if (pdata->powerup) {
gpio_request(pdata->powerup, "cw1200_wlan_powerup");
gpio_direction_output(pdata->powerup, 0);
}
if (pdata->reset || pdata->powerup)
msleep(10); /* Settle time? */
/* Enable 3v3 and 1v8 to hardware */
if (pdata->power_ctrl) {
if (pdata->power_ctrl(pdata, true)) {
pr_err("power_ctrl() failed!\n");
return -1;
}
}
/* Enable CLK32K */
if (pdata->clk_ctrl) {
if (pdata->clk_ctrl(pdata, true)) {
pr_err("clk_ctrl() failed!\n");
return -1;
}
msleep(10); /* Delay until clock is stable for 2 cycles */
}
/* Enable POWERUP signal */
if (pdata->powerup) {
gpio_set_value(pdata->powerup, 1);
msleep(250); /* or more..? */
}
/* Enable RSTn signal */
if (pdata->reset) {
gpio_set_value(pdata->reset, 1);
msleep(50); /* Or more..? */
}
return 0;
}
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);
else
size = sdio_align_size(self->func, size);
return size;
}
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, suspend);
return ret;
}
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,
.power_mgmt = cw1200_sdio_pm,
};
/* 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)
{
struct hwbus_priv *self;
int status;
pr_info("cw1200_wlan_sdio: Probe called\n");
/* 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 hwbus_priv.\n");
return -ENOMEM;
}
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
self->pdata = global_plat_data; /* FIXME */
self->func = func;
sdio_set_drvdata(func, self);
sdio_claim_host(func);
sdio_enable_func(func);
sdio_release_host(func);
status = cw1200_sdio_irq_subscribe(self);
status = cw1200_core_probe(&cw1200_sdio_hwbus_ops,
self, &func->dev, &self->core,
self->pdata->ref_clk,
self->pdata->macaddr,
self->pdata->sdd_file,
self->pdata->have_5ghz);
if (status) {
cw1200_sdio_irq_unsubscribe(self);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
sdio_set_drvdata(func, NULL);
kfree(self);
}
return status;
}
/* Disconnect Function to be called by SDIO stack when
* device is disconnected */
static void cw1200_sdio_disconnect(struct sdio_func *func)
{
struct hwbus_priv *self = sdio_get_drvdata(func);
if (self) {
cw1200_sdio_irq_unsubscribe(self);
if (self->core) {
cw1200_core_release(self->core);
self->core = NULL;
}
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
sdio_set_drvdata(func, NULL);
kfree(self);
}
}
#ifdef CONFIG_PM
static int cw1200_sdio_suspend(struct device *dev)
{
int ret;
struct sdio_func *func = dev_to_sdio_func(dev);
struct hwbus_priv *self = sdio_get_drvdata(func);
if (!cw1200_can_suspend(self->core))
return -EAGAIN;
/* Notify SDIO that CW1200 will remain powered during suspend */
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret)
pr_err("Error setting SDIO pm flags: %i\n", ret);
return ret;
}
static int cw1200_sdio_resume(struct device *dev)
{
return 0;
}
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 */
static int __init cw1200_sdio_init(void)
{
const struct cw1200_platform_data_sdio *pdata;
int ret;
/* FIXME -- this won't support multiple devices */
pdata = global_plat_data;
if (cw1200_sdio_on(pdata)) {
ret = -1;
goto err;
}
ret = sdio_register_driver(&sdio_driver);
if (ret)
goto err;
return 0;
err:
cw1200_sdio_off(pdata);
return ret;
}
/* Called at Driver Unloading */
static void __exit cw1200_sdio_exit(void)
{
const struct cw1200_platform_data_sdio *pdata;
/* FIXME -- this won't support multiple devices */
pdata = global_plat_data;
sdio_unregister_driver(&sdio_driver);
cw1200_sdio_off(pdata);
}
module_init(cw1200_sdio_init);
module_exit(cw1200_sdio_exit);
此差异已折叠。
此差异已折叠。
/*
* DebugFS 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_DEBUG_H_INCLUDED
#define CW1200_DEBUG_H_INCLUDED
#include "itp.h"
struct cw1200_debug_priv {
struct dentry *debugfs_phy;
int tx;
int tx_agg;
int rx;
int rx_agg;
int tx_multi;
int tx_multi_frames;
int tx_cache_miss;
int tx_align;
int tx_ttl;
int tx_burst;
int ba_cnt;
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);
void cw1200_debug_release(struct cw1200_common *priv);
static inline void cw1200_debug_txed(struct cw1200_common *priv)
{
++priv->debug->tx;
}
static inline void cw1200_debug_txed_agg(struct cw1200_common *priv)
{
++priv->debug->tx_agg;
}
static inline void cw1200_debug_txed_multi(struct cw1200_common *priv,
int count)
{
++priv->debug->tx_multi;
priv->debug->tx_multi_frames += count;
}
static inline void cw1200_debug_rxed(struct cw1200_common *priv)
{
++priv->debug->rx;
}
static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv)
{
++priv->debug->rx_agg;
}
static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv)
{
++priv->debug->tx_cache_miss;
}
static inline void cw1200_debug_tx_align(struct cw1200_common *priv)
{
++priv->debug->tx_align;
}
static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv)
{
++priv->debug->tx_ttl;
}
static inline void cw1200_debug_tx_burst(struct cw1200_common *priv)
{
++priv->debug->tx_burst;
}
static inline void cw1200_debug_ba(struct cw1200_common *priv,
int ba_cnt, int ba_acc,
int ba_cnt_rx, int ba_acc_rx)
{
priv->debug->ba_cnt = ba_cnt;
priv->debug->ba_acc = ba_acc;
priv->debug->ba_cnt_rx = ba_cnt_rx;
priv->debug->ba_acc_rx = ba_acc_rx;
}
#endif /* CW1200_DEBUG_H_INCLUDED */
此差异已折叠。
/*
* Firmware API for mac80211 ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* Based on:
* ST-Ericsson UMAC CW1200 driver which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@stericsson.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.
*/
#ifndef FWIO_H_INCLUDED
#define FWIO_H_INCLUDED
#define BOOTLOADER_CW1X60 "boot_cw1x60.bin"
#define FIRMWARE_CW1X60 "wsm_cw1x60.bin"
#define FIRMWARE_CUT22 "wsm_22.bin"
#define FIRMWARE_CUT20 "wsm_20.bin"
#define FIRMWARE_CUT11 "wsm_11.bin"
#define FIRMWARE_CUT10 "wsm_10.bin"
#define SDD_FILE_CW1X60 "sdd_cw1x60.bin"
#define SDD_FILE_22 "sdd_22.bin"
#define SDD_FILE_20 "sdd_20.bin"
#define SDD_FILE_11 "sdd_11.bin"
#define SDD_FILE_10 "sdd_10.bin"
int cw1200_load_firmware(struct cw1200_common *priv);
/* SDD definitions */
#define SDD_PTA_CFG_ELT_ID 0xEB
#define SDD_REFERENCE_FREQUENCY_ELT_ID 0xc5
u32 cw1200_dpll_from_clk(u16 clk);
#endif
/*
* 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 */
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* 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 */
此差异已折叠。
此差异已折叠。
/*
* Mac80211 power management interface for ST-Ericsson CW1200 mac80211 drivers
*
* 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 PM_H_INCLUDED
#define PM_H_INCLUDED
/* ******************************************************************** */
/* mac80211 API */
/* extern */ struct cw1200_common;
/* private */ struct cw1200_suspend_state;
struct cw1200_pm_state {
struct cw1200_suspend_state *suspend_state;
struct timer_list stay_awake;
struct platform_device *pm_dev;
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);
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
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, ...@@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
if ((val & 0x0000ff00) != 0) if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
pci_set_power_state(pci_dev, PCI_D0);
if (!ipw2100_hw_is_adapter_in_system(dev)) { if (!ipw2100_hw_is_adapter_in_system(dev)) {
printk(KERN_WARNING DRV_NAME printk(KERN_WARNING DRV_NAME
"Device not found via register read.\n"); "Device not found via register read.\n");
......
...@@ -76,13 +76,16 @@ ...@@ -76,13 +76,16 @@
#define IWL_INVALID_STATION 255 #define IWL_INVALID_STATION 255
/* device operations */ /* device operations */
extern struct iwl_lib_ops iwl1000_lib; extern const struct iwl_dvm_cfg iwl_dvm_1000_cfg;
extern struct iwl_lib_ops iwl2000_lib; extern const struct iwl_dvm_cfg iwl_dvm_2000_cfg;
extern struct iwl_lib_ops iwl2030_lib; extern const struct iwl_dvm_cfg iwl_dvm_105_cfg;
extern struct iwl_lib_ops iwl5000_lib; extern const struct iwl_dvm_cfg iwl_dvm_2030_cfg;
extern struct iwl_lib_ops iwl5150_lib; extern const struct iwl_dvm_cfg iwl_dvm_5000_cfg;
extern struct iwl_lib_ops iwl6000_lib; extern const struct iwl_dvm_cfg iwl_dvm_5150_cfg;
extern struct iwl_lib_ops iwl6030_lib; extern const struct iwl_dvm_cfg iwl_dvm_6000_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6005_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6050_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg;
#define TIME_UNIT 1024 #define TIME_UNIT 1024
...@@ -291,8 +294,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena); ...@@ -291,8 +294,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
{ {
return priv->cfg->bt_params && return priv->lib->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist; priv->lib->bt_params->advanced_bt_coexist;
} }
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册