diff options
Diffstat (limited to 'drivers/net/wireless')
76 files changed, 922 insertions, 525 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 174e3442d519..4de4410cd38e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -279,6 +279,7 @@ source "drivers/net/wireless/libertas/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" +source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index a13a602edb13..06f8ca26c5c1 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o +obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 91c5f73b5ba3..1476314afa8a 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1525,8 +1525,7 @@ static void at76_rx_tasklet(unsigned long param) if (priv->device_unplugged) { at76_dbg(DBG_DEVSTART, "device unplugged"); - if (urb) - at76_dbg(DBG_DEVSTART, "urb status %d", urb->status); + at76_dbg(DBG_DEVSTART, "urb status %d", urb->status); return; } diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index cee0191704f5..501050c0296f 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,6 +19,7 @@ #include <linux/skbuff.h> #include <linux/if_ether.h> +#include <linux/spinlock.h> #include <net/mac80211.h> /* @@ -42,6 +43,13 @@ struct ath_ani { struct timer_list timer; }; +struct ath_cycle_counters { + u32 cycles; + u32 rx_busy; + u32 rx_frame; + u32 tx_frame; +}; + enum ath_device_state { ATH_HW_UNAVAILABLE, ATH_HW_INITIALIZED, @@ -145,6 +153,12 @@ struct ath_common { DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); enum ath_crypt_caps crypt_caps; + unsigned int clockrate; + + spinlock_t cc_lock; + struct ath_cycle_counters cc_ani; + struct ath_cycle_counters cc_survey; + struct ath_regulatory regulatory; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; @@ -161,5 +175,7 @@ int ath_key_config(struct ath_common *common, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); bool ath_hw_keyreset(struct ath_common *common, u16 entry); +void ath_hw_cycle_counters_update(struct ath_common *common); +int32_t ath_hw_get_listen_time(struct ath_common *common); #endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index e4a5f046bba4..f1419198a479 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -355,41 +355,28 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) /** - * ath5k_hw_ani_get_listen_time() - Calculate time spent listening + * ath5k_hw_ani_get_listen_time() - Update counters and return listening time * * Return an approximation of the time spent "listening" in milliseconds (ms) - * since the last call of this function by deducting the cycles spent - * transmitting and receiving from the total cycle count. - * Save profile count values for debugging/statistics and because we might want - * to use them later. - * - * We assume no one else clears these registers! + * since the last call of this function. + * Save a snapshot of the counter values for debugging/statistics. */ static int ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) { + struct ath_common *common = ath5k_hw_common(ah); int listen; - /* freeze */ - ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC); - /* read */ - as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE); - as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR); - as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX); - as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX); - /* clear */ - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); - /* un-freeze */ - ath5k_hw_reg_write(ah, 0, AR5K_MIBC); - - /* TODO: where does 44000 come from? (11g clock rate?) */ - listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000; - - if (as->pfc_cycles == 0 || listen < 0) - return 0; + spin_lock_bh(&common->cc_lock); + + ath_hw_cycle_counters_update(common); + memcpy(&as->last_cc, &common->cc_ani, sizeof(as->last_cc)); + + /* clears common->cc_ani */ + listen = ath_hw_get_listen_time(common); + + spin_unlock_bh(&common->cc_lock); + return listen; } diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 55cf26d8522c..d0a664039c87 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -75,10 +75,7 @@ struct ath5k_ani_state { unsigned int cck_errors; /* debug/statistics only: numbers from last ANI calibration */ - unsigned int pfc_tx; - unsigned int pfc_rx; - unsigned int pfc_busy; - unsigned int pfc_cycles; + struct ath_cycle_counters last_cc; unsigned int last_listen; unsigned int last_ofdm_errors; unsigned int last_cck_errors; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 0cba2e315d9a..4a367cdb3eb9 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1201,7 +1201,7 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); /* Clock rate related functions */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); +void ath5k_hw_set_clockrate(struct ath5k_hw *ah); /* Queue Control Unit, DFS Control Unit Functions */ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dad726585637..c9732a6ce87f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -62,6 +62,7 @@ #include "reg.h" #include "debug.h" #include "ani.h" +#include "../debug.h" static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); @@ -517,12 +518,14 @@ struct ath_vif_iter_data { bool need_set_hw_addr; bool found_active; bool any_assoc; + enum nl80211_iftype opmode; }; static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath_vif_iter_data *iter_data = data; int i; + struct ath5k_vif *avf = (void *)vif->drv_priv; if (iter_data->hw_macaddr) for (i = 0; i < ETH_ALEN; i++) @@ -539,13 +542,34 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->need_set_hw_addr = false; if (!iter_data->any_assoc) { - struct ath5k_vif *avf = (void *)vif->drv_priv; if (avf->assoc) iter_data->any_assoc = true; } + + /* Calculate combined mode - when APs are active, operate in AP mode. + * Otherwise use the mode of the new interface. This can currently + * only deal with combinations of APs and STAs. Only one ad-hoc + * interfaces is allowed above. + */ + if (avf->opmode == NL80211_IFTYPE_AP) + iter_data->opmode = NL80211_IFTYPE_AP; + else + if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) + iter_data->opmode = avf->opmode; } -void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) +static void ath_do_set_opmode(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + ath5k_hw_set_opmode(ah, sc->opmode); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", + sc->opmode, + ath_opmode_to_string(sc->opmode) ? + ath_opmode_to_string(sc->opmode) : "UKNOWN"); +} + +void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, + struct ieee80211_vif *vif) { struct ath_common *common = ath5k_hw_common(sc->ah); struct ath_vif_iter_data iter_data; @@ -558,6 +582,7 @@ void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) memset(&iter_data.mask, 0xff, ETH_ALEN); iter_data.found_active = false; iter_data.need_set_hw_addr = true; + iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; if (vif) ath_vif_iter(&iter_data, vif->addr, vif); @@ -567,10 +592,18 @@ void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) &iter_data); memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); + sc->opmode = iter_data.opmode; + if (sc->opmode == NL80211_IFTYPE_UNSPECIFIED) + /* Nothing active, default to station mode */ + sc->opmode = NL80211_IFTYPE_STATION; + + ath_do_set_opmode(sc); + if (iter_data.need_set_hw_addr && iter_data.found_active) ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + if (ath5k_hw_hasbssidmask(sc->ah)) + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); } static void @@ -582,15 +615,9 @@ ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) /* configure rx filter */ rfilt = sc->filter_flags; ath5k_hw_set_rx_filter(ah, rfilt); - - if (ath5k_hw_hasbssidmask(ah)) - ath5k_update_bssid_mask(sc, vif); - - /* configure operational mode */ - ath5k_hw_set_opmode(ah, sc->opmode); - - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); + + ath5k_update_bssid_mask_and_opmode(sc, vif); } static inline int @@ -2688,7 +2715,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) SET_IEEE80211_PERM_ADDR(hw, mac); memcpy(&sc->lladdr, mac, ETH_ALEN); /* All MAC address bits matter for ACKs */ - ath5k_update_bssid_mask(sc, NULL); + ath5k_update_bssid_mask_and_opmode(sc, NULL); regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); @@ -2786,7 +2813,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; int ret; - struct ath5k_hw *ah = sc->ah; struct ath5k_vif *avf = (void *)vif->drv_priv; mutex_lock(&sc->lock); @@ -2850,18 +2876,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->num_adhoc_vifs++; } - /* Set combined mode - when APs are configured, operate in AP mode. - * Otherwise use the mode of the new interface. This can currently - * only deal with combinations of APs and STAs. Only one ad-hoc - * interfaces is allowed above. - */ - if (sc->num_ap_vifs) - sc->opmode = NL80211_IFTYPE_AP; - else - sc->opmode = vif->type; - - ath5k_hw_set_opmode(ah, sc->opmode); - /* Any MAC address is fine, all others are included through the * filter. */ @@ -2905,7 +2919,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, else if (avf->opmode == NL80211_IFTYPE_ADHOC) sc->num_adhoc_vifs--; - ath5k_update_bssid_mask(sc, NULL); + ath5k_update_bssid_mask_and_opmode(sc, NULL); mutex_unlock(&sc->lock); } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index c2d549f871f9..a3b217125331 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -60,6 +60,7 @@ #include "base.h" #include "debug.h" +#include "../debug.h" static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); @@ -492,6 +493,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, char buf[700]; unsigned int len = 0; u32 filt = ath5k_hw_get_rx_filter(sc->ah); + const char *tmp; len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n", sc->bssidmask); @@ -524,6 +526,14 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, else len += snprintf(buf+len, sizeof(buf)-len, "\n"); + tmp = ath_opmode_to_string(sc->opmode); + if (tmp) + len += snprintf(buf+len, sizeof(buf)-len, "opmode: %s\n", + tmp); + else + len += snprintf(buf+len, sizeof(buf)-len, + "opmode: UNKNOWN-%i\n", sc->opmode); + if (len > sizeof(buf)) len = sizeof(buf); @@ -715,20 +725,21 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, len += snprintf(buf+len, sizeof(buf)-len, "beacon RSSI average:\t%d\n", sc->ah->ah_beacon_rssi_avg.avg); + +#define CC_PRINT(_struct, _field) \ + _struct._field, \ + _struct.cycles > 0 ? \ + _struct._field*100/_struct.cycles : 0 + len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n", - as->pfc_tx, - as->pfc_cycles > 0 ? - as->pfc_tx*100/as->pfc_cycles : 0); + CC_PRINT(as->last_cc, tx_frame)); len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n", - as->pfc_rx, - as->pfc_cycles > 0 ? - as->pfc_rx*100/as->pfc_cycles : 0); + CC_PRINT(as->last_cc, rx_frame)); len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n", - as->pfc_busy, - as->pfc_cycles > 0 ? - as->pfc_busy*100/as->pfc_cycles : 0); + CC_PRINT(as->last_cc, rx_busy)); +#undef CC_PRINT len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", - as->pfc_cycles); + as->last_cc.cycles); len += snprintf(buf+len, sizeof(buf)-len, "listen time\t\t%d\tlast: %d\n", as->listen_time, as->last_listen); diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 095d30b50ec7..074b4c644399 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -207,7 +207,8 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) { - return usec * ath5k_hw_get_clockrate(ah); + struct ath_common *common = ath5k_hw_common(ah); + return usec * common->clockrate; } /** @@ -216,17 +217,19 @@ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) */ unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) { - return clock / ath5k_hw_get_clockrate(ah); + struct ath_common *common = ath5k_hw_common(ah); + return clock / common->clockrate; } /** - * ath5k_hw_get_clockrate - Get the clock rate for current mode + * ath5k_hw_set_clockrate - Set common->clockrate for the current channel * * @ah: The &struct ath5k_hw */ -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) +void ath5k_hw_set_clockrate(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; + struct ath_common *common = ath5k_hw_common(ah); int clock; if (channel->hw_value & CHANNEL_5GHZ) @@ -240,7 +243,7 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) if (channel->hw_value & CHANNEL_TURBO) clock *= 2; - return clock; + common->clockrate = clock; } /** diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 61da913e7c8f..219367884e64 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1093,6 +1093,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) ah->ah_current_channel = channel; ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; + ath5k_hw_set_clockrate(ah); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index f2a907b4acb8..3aa8fb1ad77f 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -465,40 +465,6 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); } -static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah) -{ - struct ath9k_channel *chan = ah->curchan; - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - u8 clockrate; /* in MHz */ - - if (!ah->curchan) /* should really check for CCK instead */ - clockrate = ATH9K_CLOCK_RATE_CCK; - else if (conf->channel->band == IEEE80211_BAND_2GHZ) - clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM; - else if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; - else - clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; - - if (conf_is_ht40(conf)) - return clockrate * 2; - - return clockrate; -} - -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) -{ - int32_t listen_time; - int32_t clock_rate; - - ath9k_hw_update_cycle_counters(ah); - clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000; - listen_time = ah->listen_time / clock_rate; - ah->listen_time = 0; - - return listen_time; -} - static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState; @@ -677,7 +643,9 @@ static void ath9k_hw_ani_read_counters(struct ath_hw *ah) u32 phyCnt1, phyCnt2; int32_t listenTime; - listenTime = ath9k_hw_ani_get_listen_time(ah); + ath_hw_cycle_counters_update(common); + listenTime = ath_hw_get_listen_time(common); + if (listenTime < 0) { ah->stats.ast_ani_lneg++; ath9k_ani_restart(ah); @@ -818,54 +786,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); -void ath9k_hw_update_cycle_counters(struct ath_hw *ah) -{ - struct ath_cycle_counters cc; - bool clear; - - memcpy(&cc, &ah->cc, sizeof(cc)); - - /* freeze counters */ - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); - - ah->cc.cycles = REG_READ(ah, AR_CCCNT); - if (ah->cc.cycles < cc.cycles) { - clear = true; - goto skip; - } - - ah->cc.rx_clear = REG_READ(ah, AR_RCCNT); - ah->cc.rx_frame = REG_READ(ah, AR_RFCNT); - ah->cc.tx_frame = REG_READ(ah, AR_TFCNT); - - /* prevent wraparound */ - if (ah->cc.cycles & BIT(31)) - clear = true; - -#define CC_DELTA(_field, _reg) ah->cc_delta._field += ah->cc._field - cc._field - CC_DELTA(cycles, AR_CCCNT); - CC_DELTA(rx_frame, AR_RFCNT); - CC_DELTA(rx_clear, AR_RCCNT); - CC_DELTA(tx_frame, AR_TFCNT); -#undef CC_DELTA - - ah->listen_time += (ah->cc.cycles - cc.cycles) - - ((ah->cc.rx_frame - cc.rx_frame) + - (ah->cc.tx_frame - cc.tx_frame)); - -skip: - if (clear) { - REG_WRITE(ah, AR_CCCNT, 0); - REG_WRITE(ah, AR_RFCNT, 0); - REG_WRITE(ah, AR_RCCNT, 0); - REG_WRITE(ah, AR_TFCNT, 0); - memset(&ah->cc, 0, sizeof(ah->cc)); - } - - /* unfreeze counters */ - REG_WRITE(ah, AR_MIBC, 0); -} - /* * Process a MIB interrupt. We may potentially be invoked because * any of the MIB counters overflow/trigger so don't assume we're diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 98cfd8154c71..0cd6783de883 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -93,13 +93,6 @@ struct ath9k_mib_stats { u32 beacons; }; -struct ath_cycle_counters { - u32 cycles; - u32 rx_frame; - u32 rx_clear; - u32 tx_frame; -}; - /* INI default values for ANI registers */ struct ath9k_ani_default { u16 m1ThreshLow; @@ -164,7 +157,6 @@ struct ar5416Stats { void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); -void ath9k_hw_update_cycle_counters(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index efb05599b84c..669b777729b3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1254,13 +1254,12 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) "** BB mode: BB_gen_controls=0x%08x **\n", REG_READ(ah, AR_PHY_GEN_CTRL)); - ath9k_hw_update_cycle_counters(ah); -#define PCT(_field) (ah->cc_delta._field * 100 / ah->cc_delta.cycles) - if (ah->cc_delta.cycles) +#define PCT(_field) (common->cc_survey._field * 100 / common->cc_survey.cycles) + if (common->cc_survey.cycles) ath_print(common, ATH_DBG_RESET, "** BB busy times: rx_clear=%d%%, " "rx_frame=%d%%, tx_frame=%d%% **\n", - PCT(rx_clear), PCT(rx_frame), PCT(tx_frame)); + PCT(rx_busy), PCT(rx_frame), PCT(tx_frame)); ath_print(common, ATH_DBG_RESET, "==== BB update: done ====\n\n"); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index de2b18ee7f77..4e81fe35aa3f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -593,6 +593,8 @@ struct ath_softc { struct delayed_work wiphy_work; unsigned long wiphy_scheduler_int; int wiphy_scheduler_index; + struct survey_info *cur_survey; + struct survey_info survey[ATH9K_NUM_CHANNELS]; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 05e9935ef160..f5d79177770c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -88,29 +88,32 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) /* Helper Functions */ /********************/ -static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) +static void ath9k_hw_set_clockrate(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + struct ath_common *common = ath9k_hw_common(ah); + unsigned int clockrate; if (!ah->curchan) /* should really check for CCK instead */ - return usecs *ATH9K_CLOCK_RATE_CCK; - if (conf->channel->band == IEEE80211_BAND_2GHZ) - return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK) - return usecs * ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; + clockrate = ATH9K_CLOCK_RATE_CCK; + else if (conf->channel->band == IEEE80211_BAND_2GHZ) + clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM; + else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK) + clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; else - return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM; + clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; + + if (conf_is_ht40(conf)) + clockrate *= 2; + + common->clockrate = clockrate; } static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) { - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + struct ath_common *common = ath9k_hw_common(ah); - if (conf_is_ht40(conf)) - return ath9k_hw_mac_clks(ah, usecs) * 2; - else - return ath9k_hw_mac_clks(ah, usecs); + return usecs * common->clockrate; } bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) @@ -1156,6 +1159,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, "Failed to set channel\n"); return false; } + ath9k_hw_set_clockrate(ah); ah->eep_ops->set_txpower(ah, chan, ath9k_regd_get_ctl(regulatory, chan), @@ -1368,6 +1372,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (r) return r; + ath9k_hw_set_clockrate(ah); + ENABLE_REGWRITE_BUFFER(ah); for (i = 0; i < AR_NUM_DCU; i++) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 87627dd63463..6b9233472fbf 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -61,6 +61,8 @@ #define ATH9K_RSSI_BAD -128 +#define ATH9K_NUM_CHANNELS 38 + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) @@ -618,7 +620,7 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath9k_channel channels[38]; + struct ath9k_channel channels[ATH9K_NUM_CHANNELS]; struct ath9k_channel *curchan; union { @@ -740,8 +742,6 @@ struct ath_hw { int coarse_low[5]; int firpwr[5]; enum ath9k_ani_cmd ani_function; - struct ath_cycle_counters cc, cc_delta; - int32_t listen_time; /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d76003c06fe4..a4c5ed41b176 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -481,6 +481,10 @@ static int ath9k_init_channels_rates(struct ath_softc *sc) { void *channels; + BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + + ARRAY_SIZE(ath9k_5ghz_chantable) != + ATH9K_NUM_CHANNELS); + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { channels = kmemdup(ath9k_2ghz_chantable, sizeof(ath9k_2ghz_chantable), GFP_KERNEL); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 74c2dc8a8b8a..865649120075 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -175,6 +175,44 @@ static void ath_start_ani(struct ath_common *common) msecs_to_jiffies((u32)ah->config.ani_poll_interval)); } +static void ath_update_survey_nf(struct ath_softc *sc, int channel) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_channel *chan = &ah->channels[channel]; + struct survey_info *survey = &sc->survey[channel]; + + if (chan->noisefloor) { + survey->filled |= SURVEY_INFO_NOISE_DBM; + survey->noise = chan->noisefloor; + } +} + +static void ath_update_survey_stats(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int pos = ah->curchan - &ah->channels[0]; + struct survey_info *survey = &sc->survey[pos]; + struct ath_cycle_counters *cc = &common->cc_survey; + unsigned int div = common->clockrate * 1000; + + ath_hw_cycle_counters_update(common); + + if (cc->cycles > 0) { + survey->filled |= SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_RX | + SURVEY_INFO_CHANNEL_TIME_TX; + survey->channel_time += cc->cycles / div; + survey->channel_time_busy += cc->rx_busy / div; + survey->channel_time_rx += cc->rx_frame / div; + survey->channel_time_tx += cc->tx_frame / div; + } + memset(cc, 0, sizeof(*cc)); + + ath_update_survey_nf(sc, pos); +} + /* * Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending @@ -399,6 +437,7 @@ void ath_ani_calibrate(unsigned long data) bool aniflag = false; unsigned int timestamp = jiffies_to_msecs(jiffies); u32 cal_interval, short_cal_interval, long_cal_interval; + unsigned long flags; if (ah->caldata && ah->caldata->nfcal_interference) long_cal_interval = ATH_LONG_CALINTERVAL_INT; @@ -449,8 +488,12 @@ void ath_ani_calibrate(unsigned long data) /* Skip all processing if there's nothing to do. */ if (longcal || shortcal || aniflag) { /* Call ANI routine if necessary */ - if (aniflag) + if (aniflag) { + spin_lock_irqsave(&common->cc_lock, flags); ath9k_hw_ani_monitor(ah, ah->curchan); + ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + } /* Perform calibration if necessary */ if (longcal || shortcal) { @@ -635,6 +678,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; bool sched = false; @@ -684,7 +728,12 @@ irqreturn_t ath_isr(int irq, void *dev) if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && (status & ATH9K_INT_BB_WATCHDOG)) { + + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); ar9003_hw_bb_watchdog_dbg_info(ah); + spin_unlock(&common->cc_lock); + goto chip_reset; } @@ -1522,7 +1571,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; bool disable_radio; @@ -1588,6 +1638,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; + int old_pos = -1; + unsigned long flags; + + if (ah->curchan) + old_pos = ah->curchan - &ah->channels[0]; aphy->chan_idx = pos; aphy->chan_is_ht = conf_is_ht(conf); @@ -1615,12 +1670,45 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_chainmask(sc, conf_is_ht(conf)); + /* update survey stats for the old channel before switching */ + spin_lock_irqsave(&common->cc_lock, flags); + ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + + /* + * If the operating channel changes, change the survey in-use flags + * along with it. + * Reset the survey data for the new channel, unless we're switching + * back to the operating channel from an off-channel operation. + */ + if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && + sc->cur_survey != &sc->survey[pos]) { + + if (sc->cur_survey) + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + + sc->cur_survey = &sc->survey[pos]; + + memset(sc->cur_survey, 0, sizeof(struct survey_info)); + sc->cur_survey->filled |= SURVEY_INFO_IN_USE; + } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { + memset(&sc->survey[pos], 0, sizeof(struct survey_info)); + } + if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { ath_print(common, ATH_DBG_FATAL, "Unable to set channel\n"); mutex_unlock(&sc->mutex); return -EINVAL; } + + /* + * The most recent snapshot of channel->noisefloor for the old + * channel is only available after the hardware reset. Copy it to + * the survey stats now. + */ + if (old_pos >= 0) + ath_update_survey_nf(sc, old_pos); } skip_chan_change: @@ -1990,9 +2078,15 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_supported_band *sband; - struct ath9k_channel *chan; + struct ieee80211_channel *chan; + unsigned long flags; + int pos; + + spin_lock_irqsave(&common->cc_lock, flags); + if (idx == 0) + ath_update_survey_stats(sc); sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { @@ -2003,21 +2097,17 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, if (!sband) sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; - if (!sband || idx >= sband->n_channels) - return -ENOENT; - - survey->channel = &sband->channels[idx]; - chan = &ah->channels[survey->channel->hw_value]; - survey->filled = 0; - - if (chan == ah->curchan) - survey->filled |= SURVEY_INFO_IN_USE; - - if (chan->noisefloor) { - survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = chan->noisefloor; + if (!sband || idx >= sband->n_channels) { + spin_unlock_irqrestore(&common->cc_lock, flags); + return -ENOENT; } + chan = &sband->channels[idx]; + pos = chan->hw_value; + memcpy(survey, &sc->survey[pos], sizeof(*survey)); + survey->channel = chan; + spin_unlock_irqrestore(&common->cc_lock, flags); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ce1cd6d85847..13f9e88e1187 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1375,6 +1375,12 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) return; + if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) { + tx_info->status.ampdu_ack_len = + (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); + tx_info->status.ampdu_len = 1; + } + /* * If an underrun error is seen assume it as an excessive retry only * if max frame trigger level has been reached (2 KB for singel stream, diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 6d01e501b9b4..017617894533 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -107,12 +107,6 @@ #define AR_RXCFG_DMASZ_256B 6 #define AR_RXCFG_DMASZ_512B 7 -#define AR_MIBC 0x0040 -#define AR_MIBC_COW 0x00000001 -#define AR_MIBC_FMC 0x00000002 -#define AR_MIBC_CMC 0x00000004 -#define AR_MIBC_MCS 0x00000008 - #define AR_TOPS 0x0044 #define AR_TOPS_MASK 0x0000FFFF @@ -1524,11 +1518,6 @@ enum { #define AR_TPC_CHIRP 0x003f0000 #define AR_TPC_CHIRP_S 0x16 -#define AR_TFCNT 0x80ec -#define AR_RFCNT 0x80f0 -#define AR_RCCNT 0x80f4 -#define AR_CCCNT 0x80f8 - #define AR_QUIET1 0x80fc #define AR_QUIET1_NEXT_QUIET_S 0 #define AR_QUIET1_NEXT_QUIET_M 0x0000ffff diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index aa447770eb2b..9a11099dd86a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -317,6 +317,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true; struct ieee80211_tx_rate rates[4]; + int nframes; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -325,6 +326,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, hw = bf->aphy->hw; memcpy(rates, tx_info->control.rates, sizeof(rates)); + nframes = bf->bf_nframes; rcu_read_lock(); @@ -341,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, !bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_rc_status(bf, ts, 0, 0, false); + ath_tx_rc_status(bf, ts, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -446,6 +448,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); + bf->bf_nframes = nframes; ath_tx_rc_status(bf, ts, nbad, txok, true); rc_update = false; } else { @@ -1979,9 +1982,15 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if (ts->ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + BUG_ON(nbad > bf->bf_nframes); + + tx_info->status.ampdu_len = bf->bf_nframes; + tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; + } + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { @@ -1991,8 +2000,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, if ((ts->ts_status & ATH9K_TXERR_XRETRY) || (ts->ts_status & ATH9K_TXERR_FIFO)) tx_info->pad[0] |= ATH_TX_INFO_XRETRY; - tx_info->status.ampdu_len = bf->bf_nframes; - tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; } } @@ -2102,7 +2109,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) */ if (ts.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &ts, 0, txok, true); + ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true); } if (bf_isampdu(bf)) @@ -2220,7 +2227,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) if (!bf_isampdu(bf)) { if (txs.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &txs, 0, txok, true); + ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true); } if (bf_isampdu(bf)) diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 671dbc429547..939a0e96ed1f 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -576,6 +576,41 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) } } +static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) +{ + __le16 fc; + + if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) { + /* + * This frame is not part of an aMPDU. + * Therefore it is not subjected to any + * of the following content restrictions. + */ + return true; + } + + /* + * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts + * certain frame types can be part of an aMPDU. + * + * In order to keep the processing cost down, I opted for a + * stateless filter solely based on the frame control field. + */ + + fc = ((struct ieee80211_hdr *)buf)->frame_control; + if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc)) + return true; + + if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) || + ieee80211_is_back_req(fc)) + return true; + + if (ieee80211_is_action(fc)) + return true; + + return false; +} + /* * If the frame alignment is right (or the kernel has * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there @@ -594,24 +629,19 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) struct ieee80211_rx_status status; struct sk_buff *skb; int mpdu_len; + u8 mac_status; if (!IS_STARTED(ar)) return; - if (unlikely(len < sizeof(*mac))) { - ar->rx_dropped++; - return; - } + if (unlikely(len < sizeof(*mac))) + goto drop; mpdu_len = len - sizeof(*mac); mac = (void *)(buf + mpdu_len); - if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { - ar->rx_dropped++; - return; - } - - switch (mac->status & AR9170_RX_STATUS_MPDU) { + mac_status = mac->status; + switch (mac_status & AR9170_RX_STATUS_MPDU) { case AR9170_RX_STATUS_MPDU_FIRST: /* Aggregated MPDUs start with an PLCP header */ if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { @@ -638,8 +668,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) "is clipped.\n"); } - ar->rx_dropped++; - return; + goto drop; } break; @@ -659,8 +688,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) "is clipped.\n"); } - ar->rx_dropped++; - return; + goto drop; } case AR9170_RX_STATUS_MPDU_MIDDLE: @@ -672,8 +700,7 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) wiphy_err(ar->hw->wiphy, "rx stream does not start " "with a first_mpdu frame tag.\n"); - ar->rx_dropped++; - return; + goto drop; } head = &ar->rx_plcp; @@ -696,16 +723,15 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) } /* FC + DU + RA + FCS */ - if (unlikely(mpdu_len < (2 + 2 + 6 + FCS_LEN))) { - ar->rx_dropped++; - return; - } + if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) + goto drop; memset(&status, 0, sizeof(status)); - if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) { - ar->rx_dropped++; - return; - } + if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) + goto drop; + + if (!carl9170_ampdu_check(ar, buf, mac_status)) + goto drop; if (phy) carl9170_rx_phy_status(ar, phy, &status); @@ -713,12 +739,15 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) carl9170_ps_beacon(ar, buf, mpdu_len); skb = carl9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) { - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx(ar->hw, skb); - } else { - ar->rx_dropped++; - } + if (!skb) + goto drop; + + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(ar->hw, skb); + return; + +drop: + ar->rx_dropped++; } static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf, diff --git a/drivers/net/wireless/ath/carl9170/wlan.h b/drivers/net/wireless/ath/carl9170/wlan.h index 48ead2268f50..24d63b583b6b 100644 --- a/drivers/net/wireless/ath/carl9170/wlan.h +++ b/drivers/net/wireless/ath/carl9170/wlan.h @@ -74,6 +74,9 @@ #define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 #define AR9170_RX_STATUS_MPDU_LAST 0x10 +#define AR9170_RX_STATUS_CONT_AGGR 0x40 +#define AR9170_RX_STATUS_TOTAL_ERROR 0x80 + #define AR9170_RX_ERROR_RXTO 0x01 #define AR9170_RX_ERROR_OVERRUN 0x02 #define AR9170_RX_ERROR_DECRYPT 0x04 @@ -81,7 +84,6 @@ #define AR9170_RX_ERROR_WRONG_RA 0x10 #define AR9170_RX_ERROR_PLCP 0x20 #define AR9170_RX_ERROR_MMIC 0x40 -#define AR9170_RX_ERROR_FATAL 0x80 /* these are either-or */ #define AR9170_TX_MAC_PROT_RTS 0x0001 @@ -329,13 +331,15 @@ struct _carl9170_tx_superframe { #define CARL9170_TX_SUPERDESC_LEN 24 #define AR9170_TX_HWDESC_LEN 8 -#define AR9170_TX_SUPERFRAME_LEN (CARL9170_TX_HWDESC_LEN + \ - AR9170_TX_SUPERDESC_LEN) +#define CARL9170_TX_SUPERFRAME_LEN (CARL9170_TX_SUPERDESC_LEN + \ + AR9170_TX_HWDESC_LEN) struct ar9170_rx_head { u8 plcp[12]; } __packed; +#define AR9170_RX_HEAD_LEN 12 + struct ar9170_rx_phystatus { union { struct { @@ -350,12 +354,16 @@ struct ar9170_rx_phystatus { u8 phy_err; } __packed; +#define AR9170_RX_PHYSTATUS_LEN 20 + struct ar9170_rx_macstatus { u8 SAidx, DAidx; u8 error; u8 status; } __packed; +#define AR9170_RX_MACSTATUS_LEN 4 + struct ar9170_rx_frame_single { struct ar9170_rx_head phy_head; struct ieee80211_hdr i3e; diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index 53e77bd131b9..a9eb7876dbe1 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -30,3 +30,32 @@ void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) va_end(args); } EXPORT_SYMBOL(ath_print); + +const char *ath_opmode_to_string(enum nl80211_iftype opmode) +{ + switch (opmode) { + case NL80211_IFTYPE_UNSPECIFIED: + return "UNSPEC"; + case NL80211_IFTYPE_ADHOC: + return "ADHOC"; + case NL80211_IFTYPE_STATION: + return "STATION"; + case NL80211_IFTYPE_AP: + return "AP"; + case NL80211_IFTYPE_AP_VLAN: + return "AP-VLAN"; + case NL80211_IFTYPE_WDS: + return "WDS"; + case NL80211_IFTYPE_MONITOR: + return "MONITOR"; + case NL80211_IFTYPE_MESH_POINT: + return "MESH"; + case NL80211_IFTYPE_P2P_CLIENT: + return "P2P-CLIENT"; + case NL80211_IFTYPE_P2P_GO: + return "P2P-GO"; + default: + return NULL; + } +} +EXPORT_SYMBOL(ath_opmode_to_string); diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index fd3a020682dc..a3a5a628d24d 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h @@ -77,4 +77,7 @@ ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) } #endif /* CONFIG_ATH_DEBUG */ +/** Returns string describing opmode, or NULL if unknown mode. */ +const char *ath_opmode_to_string(enum nl80211_iftype opmode); + #endif /* ATH_DEBUG_H */ diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index a8f81ea09f14..183c28281385 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -124,3 +124,62 @@ void ath_hw_setbssidmask(struct ath_common *common) REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); } EXPORT_SYMBOL(ath_hw_setbssidmask); + + +/** + * ath_hw_cycle_counters_update - common function to update cycle counters + * + * @common: the ath_common struct for the device. + * + * This function is used to update all cycle counters in one place. + * It has to be called while holding common->cc_lock! + */ +void ath_hw_cycle_counters_update(struct ath_common *common) +{ + u32 cycles, busy, rx, tx; + void *ah = common->ah; + + /* freeze */ + REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC); + + /* read */ + cycles = REG_READ(ah, AR_CCCNT); + busy = REG_READ(ah, AR_RCCNT); + rx = REG_READ(ah, AR_RFCNT); + tx = REG_READ(ah, AR_TFCNT); + + /* clear */ + REG_WRITE(ah, 0, AR_CCCNT); + REG_WRITE(ah, 0, AR_RFCNT); + REG_WRITE(ah, 0, AR_RCCNT); + REG_WRITE(ah, 0, AR_TFCNT); + + /* unfreeze */ + REG_WRITE(ah, 0, AR_MIBC); + + /* update all cycle counters here */ + common->cc_ani.cycles += cycles; + common->cc_ani.rx_busy += busy; + common->cc_ani.rx_frame += rx; + common->cc_ani.tx_frame += tx; + + common->cc_survey.cycles += cycles; + common->cc_survey.rx_busy += busy; + common->cc_survey.rx_frame += rx; + common->cc_survey.tx_frame += tx; +} +EXPORT_SYMBOL(ath_hw_cycle_counters_update); + +int32_t ath_hw_get_listen_time(struct ath_common *common) +{ + struct ath_cycle_counters *cc = &common->cc_ani; + int32_t listen_time; + + listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) / + (common->clockrate * 1000); + + memset(cc, 0, sizeof(*cc)); + + return listen_time; +} +EXPORT_SYMBOL(ath_hw_get_listen_time); diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h index e798ef476581..298e53f3fa48 100644 --- a/drivers/net/wireless/ath/reg.h +++ b/drivers/net/wireless/ath/reg.h @@ -17,6 +17,12 @@ #ifndef ATH_REGISTERS_H #define ATH_REGISTERS_H +#define AR_MIBC 0x0040 +#define AR_MIBC_COW 0x00000001 +#define AR_MIBC_FMC 0x00000002 +#define AR_MIBC_CMC 0x00000004 +#define AR_MIBC_MCS 0x00000008 + /* * BSSID mask registers. See ath_hw_set_bssid_mask() * for detailed documentation about these registers. @@ -24,6 +30,11 @@ #define AR_BSSMSKL 0x80e0 #define AR_BSSMSKU 0x80e4 +#define AR_TFCNT 0x80ec +#define AR_RFCNT 0x80f0 +#define AR_RCCNT 0x80f4 +#define AR_CCCNT 0x80f8 + #define AR_KEYTABLE_0 0x8800 #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) #define AR_KEY_CACHE_SIZE 128 diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index bd480b481bfc..6dcd0334ed02 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -2,6 +2,7 @@ #define LINUX_B43_PHY_COMMON_H_ #include <linux/types.h> +#include <linux/nl80211.h> struct b43_wldev; @@ -250,8 +251,9 @@ struct b43_phy { * check is needed. */ unsigned long next_txpwr_check_time; - /* current channel */ + /* Current channel */ unsigned int channel; + enum nl80211_channel_type channel_type; /* PHY TX errors counter. */ atomic_t txerr_cnt; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 52ce4383a056..e532901246b6 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -74,6 +74,13 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, u16 value, u8 core); +static inline bool b43_channel_type_is_40mhz( + enum nl80211_channel_type channel_type) +{ + return (channel_type == NL80211_CHAN_HT40MINUS || + channel_type == NL80211_CHAN_HT40PLUS); +} + static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec) { return !chanspec->channel && !chanspec->sideband && @@ -3323,24 +3330,25 @@ int b43_phy_initn(struct b43_wldev *dev) } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ -static void b43_nphy_chanspec_setup(struct b43_wldev *dev, +static void b43_nphy_channel_setup(struct b43_wldev *dev, const struct b43_phy_n_sfo_cfg *e, - struct b43_chanspec chanspec) + struct ieee80211_channel *new_channel) { struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; - u16 tmp; + u16 old_band_5ghz; u32 tmp32; - tmp = b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ; - if (chanspec.b_freq == 1 && tmp == 0) { + old_band_5ghz = + b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ; + if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) { tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4); b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32); b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); - } else if (chanspec.b_freq == 1) { + } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) { b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR); b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4); @@ -3350,13 +3358,12 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev, b43_chantab_phy_upload(dev, e); - - if (nphy->radio_chanspec.channel == 14) { + if (new_channel->hw_value == 14) { b43_nphy_classifier(dev, 2, 0); b43_phy_set(dev, B43_PHY_B_TEST, 0x0800); } else { b43_nphy_classifier(dev, 2, 2); - if (chanspec.b_freq == 2) + if (new_channel->band == IEEE80211_BAND_2GHZ) b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840); } @@ -3379,53 +3386,54 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev, } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */ -static int b43_nphy_set_chanspec(struct b43_wldev *dev, - struct b43_chanspec chanspec) +static int b43_nphy_set_channel(struct b43_wldev *dev, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; const struct b43_nphy_channeltab_entry_rev2 *tabent_r2; const struct b43_nphy_channeltab_entry_rev3 *tabent_r3; u8 tmp; - u8 channel = chanspec.channel; if (dev->phy.rev >= 3) { - /* TODO */ + tabent_r3 = b43_nphy_get_chantabent_rev3(dev, + channel->center_freq); tabent_r3 = NULL; if (!tabent_r3) return -ESRCH; } else { - tabent_r2 = b43_nphy_get_chantabent_rev2(dev, channel); + tabent_r2 = b43_nphy_get_chantabent_rev2(dev, + channel->hw_value); if (!tabent_r2) return -ESRCH; } - nphy->radio_chanspec = chanspec; + nphy->radio_chanspec.channel = channel->hw_value; - if (chanspec.b_width != nphy->b_width) - ; /* TODO: BMAC BW Set (chanspec.b_width) */ + if (b43_channel_type_is_40mhz(phy->channel_type) != + b43_channel_type_is_40mhz(channel_type)) + ; /* TODO: BMAC BW Set (channel_type) */ - /* TODO: use defines */ - if (chanspec.b_width == 3) { - if (chanspec.sideband == 2) - b43_phy_set(dev, B43_NPHY_RXCTL, - B43_NPHY_RXCTL_BSELU20); - else - b43_phy_mask(dev, B43_NPHY_RXCTL, - ~B43_NPHY_RXCTL_BSELU20); - } + if (channel_type == NL80211_CHAN_HT40PLUS) + b43_phy_set(dev, B43_NPHY_RXCTL, + B43_NPHY_RXCTL_BSELU20); + else if (channel_type == NL80211_CHAN_HT40MINUS) + b43_phy_mask(dev, B43_NPHY_RXCTL, + ~B43_NPHY_RXCTL_BSELU20); if (dev->phy.rev >= 3) { - tmp = (chanspec.b_freq == 1) ? 4 : 0; + tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0; b43_radio_maskset(dev, 0x08, 0xFFFB, tmp); /* TODO: PHY Radio2056 Setup (dev, tabent_r3); */ - b43_nphy_chanspec_setup(dev, &(tabent_r3->phy_regs), chanspec); + b43_nphy_channel_setup(dev, &(tabent_r3->phy_regs), channel); } else { - tmp = (chanspec.b_freq == 1) ? 0x0020 : 0x0050; + tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 0x0020 : 0x0050; b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, tmp); b43_radio_2055_setup(dev, tabent_r2); - b43_nphy_chanspec_setup(dev, &(tabent_r2->phy_regs), chanspec); + b43_nphy_channel_setup(dev, &(tabent_r2->phy_regs), channel); } return 0; @@ -3567,8 +3575,8 @@ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) static int b43_nphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { - struct b43_phy_n *nphy = dev->phy.n; - struct b43_chanspec chanspec; + struct ieee80211_channel *channel = dev->wl->hw->conf.channel; + enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { if ((new_channel < 1) || (new_channel > 14)) @@ -3578,10 +3586,7 @@ static int b43_nphy_op_switch_channel(struct b43_wldev *dev, return -EINVAL; } - chanspec = nphy->radio_chanspec; - chanspec.channel = new_channel; - - return b43_nphy_set_chanspec(dev, chanspec); + return b43_nphy_set_channel(dev, channel, channel_type); } static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 8b6d570dd0aa..e7acae278be0 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -984,7 +984,6 @@ struct b43_phy_n { u16 papd_epsilon_offset[2]; s32 preamble_override; u32 bb_mult_save; - u8 b_width; struct b43_chanspec radio_chanspec; bool gain_boost; diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index d96e870ab8fe..e74b8eb5795c 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -325,7 +325,7 @@ void b2055_upload_inittab(struct b43_wldev *dev, .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 -static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab[] = { +static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = { { .channel = 184, .freq = 4920, /* MHz */ .unk2 = 3280, @@ -1326,8 +1326,8 @@ b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel) const struct b43_nphy_channeltab_entry_rev2 *e; unsigned int i; - for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) { - e = &(b43_nphy_channeltab[i]); + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev2); i++) { + e = &(b43_nphy_channeltab_rev2[i]); if (e->channel == channel) return e; } @@ -1335,6 +1335,24 @@ b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel) return NULL; } +static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { +}; + +const struct b43_nphy_channeltab_entry_rev3 * +b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) +{ + const struct b43_nphy_channeltab_entry_rev3 *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev3); i++) { + e = &(b43_nphy_channeltab_rev3[i]); + if (e->freq == freq) + return e; + } + + return NULL; +} + static const u8 b43_ntab_adjustpower0[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 8fc1da9f8fe5..3eedb869f492 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -90,10 +90,12 @@ void b2055_upload_inittab(struct b43_wldev *dev, bool ghz5, bool ignore_uploadflag); -/* Get the NPHY Channel Switch Table entry for a channel number. +/* Get the NPHY Channel Switch Table entry for a channel. * Returns NULL on failure to find an entry. */ const struct b43_nphy_channeltab_entry_rev2 * b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel); +const struct b43_nphy_channeltab_entry_rev3 * +b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq); /* The N-PHY tables. */ diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4b88909275a1..095cb6982d7a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1104,7 +1104,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); - rt2x00queue_map_txskb(rt2x00dev, entry->skb); + rt2x00queue_map_txskb(entry); /* * Write the TX descriptor for the beacon. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 46ef692e404d..7d85bf9bd253 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1258,7 +1258,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); - rt2x00queue_map_txskb(rt2x00dev, entry->skb); + rt2x00queue_map_txskb(entry); /* * Write the TX descriptor for the beacon. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 7f040b0eac36..b9433fe2855a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -499,7 +499,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_write_tx_data); -static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) +static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) { int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0); int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 85a134cd62bf..b26739535986 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -573,7 +573,7 @@ static void rt2800pci_kick_tx_queue(struct data_queue *queue) { struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - unsigned int qidx = 0; + unsigned int qidx; if (queue->qid == QID_MGMT) qidx = 5; @@ -676,7 +676,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) break; } - qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_TYPE) - 1; + qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); if (qid >= QID_RX) { /* * Unknown queue, this shouldn't happen. Just drop diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 75ac6624bf9e..94fe589acfaa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -338,6 +338,11 @@ struct link { /* * Work structure for scheduling periodic watchdog monitoring. + * This work must be scheduled on the kernel workqueue, while + * all other work structures must be queued on the mac80211 + * workqueue. This guarantees that the watchdog can schedule + * other work structures and wait for their completion in order + * to bring the device/driver back into the desired state. */ struct delayed_work watchdog_work; }; @@ -1036,17 +1041,15 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev) /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to map. + * @entry: Pointer to &struct queue_entry */ -void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00queue_map_txskb(struct queue_entry *entry); /** * rt2x00queue_unmap_skb - Unmap a skb from DMA. - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to unmap. + * @entry: Pointer to &struct queue_entry */ -void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00queue_unmap_skb(struct queue_entry *entry); /** * rt2x00queue_get_queue - Convert queue index to queue pointer @@ -1093,8 +1096,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry); void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc); void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status); -void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +void rt2x00lib_rxdone(struct queue_entry *entry); /* * mac80211 handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 6f442b02b83e..5ba79b935f09 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -253,6 +253,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); void rt2x00lib_dmadone(struct queue_entry *entry) { + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); } EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); @@ -273,7 +274,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Unmap the skb. */ - rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + rt2x00queue_unmap_skb(entry); /* * Remove the extra tx headroom from the skb. @@ -432,42 +433,50 @@ static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, struct ieee80211_supported_band *sband; const struct rt2x00_rate *rate; unsigned int i; - int signal; - int type; + int signal = rxdesc->signal; + int type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); - /* - * For non-HT rates the MCS value needs to contain the - * actually used rate modulation (CCK or OFDM). - */ - if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) - signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal); - else - signal = rxdesc->signal; - - type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); - - sband = &rt2x00dev->bands[rt2x00dev->curr_band]; - for (i = 0; i < sband->n_bitrates; i++) { - rate = rt2x00_get_rate(sband->bitrates[i].hw_value); - - if (((type == RXDONE_SIGNAL_PLCP) && - (rate->plcp == signal)) || - ((type == RXDONE_SIGNAL_BITRATE) && - (rate->bitrate == signal)) || - ((type == RXDONE_SIGNAL_MCS) && - (rate->mcs == signal))) { - return i; + switch (rxdesc->rate_mode) { + case RATE_MODE_CCK: + case RATE_MODE_OFDM: + /* + * For non-HT rates the MCS value needs to contain the + * actually used rate modulation (CCK or OFDM). + */ + if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) + signal = RATE_MCS(rxdesc->rate_mode, signal); + + sband = &rt2x00dev->bands[rt2x00dev->curr_band]; + for (i = 0; i < sband->n_bitrates; i++) { + rate = rt2x00_get_rate(sband->bitrates[i].hw_value); + if (((type == RXDONE_SIGNAL_PLCP) && + (rate->plcp == signal)) || + ((type == RXDONE_SIGNAL_BITRATE) && + (rate->bitrate == signal)) || + ((type == RXDONE_SIGNAL_MCS) && + (rate->mcs == signal))) { + return i; + } } + break; + case RATE_MODE_HT_MIX: + case RATE_MODE_HT_GREENFIELD: + if (signal >= 0 && signal <= 76) + return signal; + break; + default: + break; } WARNING(rt2x00dev, "Frame received with unrecognized signal, " - "signal=0x%.4x, type=%d.\n", signal, type); + "mode=0x%.4x, signal=0x%.4x, type=%d.\n", + rxdesc->rate_mode, signal, type); return 0; } -void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +void rt2x00lib_rxdone(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rxdone_entry_desc rxdesc; struct sk_buff *skb; struct ieee80211_rx_status *rx_status; @@ -481,14 +490,14 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. */ - skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry); + skb = rt2x00queue_alloc_rxskb(entry); if (!skb) - return; + goto submit_entry; /* * Unmap the skb. */ - rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + rt2x00queue_unmap_skb(entry); /* * Extract the RXD details. @@ -523,18 +532,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, skb_trim(entry->skb, rxdesc.size); /* - * Check if the frame was received using HT. In that case, - * the rate is the MCS index and should be passed to mac80211 - * directly. Otherwise we need to translate the signal to - * the correct bitrate index. + * Translate the signal to the correct bitrate index. */ - if (rxdesc.rate_mode == RATE_MODE_CCK || - rxdesc.rate_mode == RATE_MODE_OFDM) { - rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); - } else { + rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); + if (rxdesc.rate_mode == RATE_MODE_HT_MIX || + rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD) rxdesc.flags |= RX_FLAG_HT; - rate_idx = rxdesc.signal; - } /* * Update extra components diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 70c85ac2e53e..619da23b7b56 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -100,18 +100,15 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, /** * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes. - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @queue: The queue for which the skb will be applicable. + * @entry: The entry for which the skb will be applicable. */ -struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry); /** * rt2x00queue_free_skb - free a skb - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to free. + * @entry: The entry for which the skb will be applicable. */ -void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +void rt2x00queue_free_skb(struct queue_entry *entry); /** * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 4d534e9dc628..b971d8798ebf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -236,6 +236,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; /* + * No need to update the stats for !=STA interfaces + */ + if (!rt2x00dev->intf_sta_count) + return; + + /* * Frame was received successfully since non-succesfull * frames would have been dropped by the hardware. */ @@ -411,8 +417,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) return; - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL); } void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) @@ -436,8 +441,7 @@ static void rt2x00link_watchdog(struct work_struct *work) rt2x00dev->ops->lib->watchdog(rt2x00dev); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL); } void rt2x00link_register(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 63c2cc408e15..2449d785cf8d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -84,7 +84,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(rt2x00dev, entry); + rt2x00lib_rxdone(entry); } } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 6d41599a090c..7e30144c5cfa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,9 +33,9 @@ #include "rt2x00.h" #include "rt2x00lib.h" -struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct sk_buff *skb; struct skb_frame_desc *skbdesc; unsigned int frame_size; @@ -97,41 +97,42 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, return skb; } -void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +void rt2x00queue_map_txskb(struct queue_entry *entry) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct device *dev = entry->queue->rt2x00dev->dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); skbdesc->skb_dma = - dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); + dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE); skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; } EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); -void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +void rt2x00queue_unmap_skb(struct queue_entry *entry) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + struct device *dev = entry->queue->rt2x00dev->dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len, DMA_FROM_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX; - } - - if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + } else if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { + dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; } } EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb); -void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) +void rt2x00queue_free_skb(struct queue_entry *entry) { - if (!skb) + if (!entry->skb) return; - rt2x00queue_unmap_skb(rt2x00dev, skb); - dev_kfree_skb_any(skb); + rt2x00queue_unmap_skb(entry); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; } void rt2x00queue_align_frame(struct sk_buff *skb) @@ -440,7 +441,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, * Map the skb to DMA. */ if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) - rt2x00queue_map_txskb(rt2x00dev, entry->skb); + rt2x00queue_map_txskb(entry); return 0; } @@ -491,7 +492,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, if (unlikely(rt2x00queue_full(queue))) return -ENOBUFS; - if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, + &entry->flags))) { ERROR(queue->rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", @@ -586,8 +588,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, /* * Clean up the beacon skb. */ - rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); - intf->beacon->skb = NULL; + rt2x00queue_free_skb(intf->beacon); if (!enable_beacon) { rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue); @@ -828,8 +829,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, return 0; } -static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static void rt2x00queue_free_skbs(struct data_queue *queue) { unsigned int i; @@ -837,19 +837,17 @@ static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev, return; for (i = 0; i < queue->limit; i++) { - if (queue->entries[i].skb) - rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb); + rt2x00queue_free_skb(&queue->entries[i]); } } -static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static int rt2x00queue_alloc_rxskbs(struct data_queue *queue) { unsigned int i; struct sk_buff *skb; for (i = 0; i < queue->limit; i++) { - skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]); + skb = rt2x00queue_alloc_rxskb(&queue->entries[i]); if (!skb) return -ENOMEM; queue->entries[i].skb = skb; @@ -884,7 +882,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) goto exit; } - status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx); + status = rt2x00queue_alloc_rxskbs(rt2x00dev->rx); if (status) goto exit; @@ -902,7 +900,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; - rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx); + rt2x00queue_free_skbs(rt2x00dev->rx); queue_for_each(rt2x00dev, queue) { kfree(queue->entries); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 4c5ae3d45625..b3317df7a7d4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -208,7 +208,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -220,7 +220,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Check if the frame was correctly uploaded */ if (urb->status) - __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); /* * Schedule the delayed work for reading the TX status @@ -253,7 +253,10 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) { + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + rt2x00lib_dmadone(entry); + } } void rt2x00usb_kick_tx_queue(struct data_queue *queue) @@ -280,14 +283,6 @@ static void rt2x00usb_kill_tx_entry(struct queue_entry *entry) if ((entry->queue->qid == QID_BEACON) && (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) usb_kill_urb(bcn_priv->guardian_urb); - - /* - * We need a short delay here to wait for - * the URB to be canceled - */ - do { - udelay(100); - } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)); } void rt2x00usb_kill_tx_queue(struct data_queue *queue) @@ -363,10 +358,12 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { - if (rt2x00queue_dma_timeout(queue)) - rt2x00usb_watchdog_tx_dma(queue); - if (rt2x00queue_timeout(queue)) - rt2x00usb_watchdog_tx_status(queue); + if (!rt2x00queue_empty(queue)) { + if (rt2x00queue_dma_timeout(queue)) + rt2x00usb_watchdog_tx_dma(queue); + if (rt2x00queue_timeout(queue)) + rt2x00usb_watchdog_tx_status(queue); + } } } EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); @@ -398,7 +395,7 @@ static void rt2x00usb_work_rxdone(struct work_struct *work) /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(rt2x00dev, entry); + rt2x00lib_rxdone(entry); } } @@ -407,7 +404,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -421,7 +418,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * a problem. */ if (urb->actual_length < entry->queue->desc_size || urb->status) - __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); /* * Schedule the delayed work for reading the RX status @@ -467,7 +464,10 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) rt2x00usb_interrupt_rxdone, entry); set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) { + set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); + rt2x00lib_dmadone(entry); + } } } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); @@ -542,9 +542,9 @@ static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static int rt2x00usb_alloc_entries(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv; struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; @@ -561,7 +561,7 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, * no guardian byte was required for the beacon, * then we are done. */ - if (rt2x00dev->bcn != queue || + if (queue->qid != QID_BEACON || !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) return 0; @@ -575,9 +575,9 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, return 0; } -static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, - struct data_queue *queue) +static void rt2x00usb_free_entries(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv; struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; @@ -596,7 +596,7 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, * no guardian byte was required for the beacon, * then we are done. */ - if (rt2x00dev->bcn != queue || + if (queue->qid != QID_BEACON || !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) return; @@ -623,7 +623,7 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) * Allocate DMA */ queue_for_each(rt2x00dev, queue) { - status = rt2x00usb_alloc_urb(rt2x00dev, queue); + status = rt2x00usb_alloc_entries(queue); if (status) goto exit; } @@ -642,7 +642,7 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; queue_for_each(rt2x00dev, queue) - rt2x00usb_free_urb(rt2x00dev, queue); + rt2x00usb_free_entries(queue); } EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize); diff --git a/drivers/net/wireless/wl1251/Kconfig b/drivers/net/wireless/wl1251/Kconfig new file mode 100644 index 000000000000..1fb65849414f --- /dev/null +++ b/drivers/net/wireless/wl1251/Kconfig @@ -0,0 +1,33 @@ +menuconfig WL1251 + tristate "TI wl1251 driver support" + depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS + select FW_LOADER + select CRC7 + ---help--- + This will enable TI wl1251 driver support. The drivers make + use of the mac80211 stack. + + If you choose to build a module, it'll be called wl1251. Say + N if unsure. + +config WL1251_SPI + tristate "TI wl1251 SPI support" + depends on WL1251 && SPI_MASTER + ---help--- + This module adds support for the SPI interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SPI bus. + + If you choose to build a module, it'll be called wl1251_spi. + Say N if unsure. + +config WL1251_SDIO + tristate "TI wl1251 SDIO support" + depends on WL1251 && MMC + ---help--- + This module adds support for the SDIO interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SDIO bus. + + If you choose to build a module, it'll be called + wl1251_sdio. Say N if unsure. diff --git a/drivers/net/wireless/wl1251/Makefile b/drivers/net/wireless/wl1251/Makefile new file mode 100644 index 000000000000..4fe246824db3 --- /dev/null +++ b/drivers/net/wireless/wl1251/Makefile @@ -0,0 +1,6 @@ +wl1251-objs = main.o event.o tx.o rx.o ps.o cmd.o \ + acx.o boot.o init.o debugfs.o io.o + +obj-$(CONFIG_WL1251) += wl1251.o +obj-$(CONFIG_WL1251_SPI) += spi.o +obj-$(CONFIG_WL1251_SDIO) += sdio.o diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl1251/acx.c index 2f8a2ba744dc..64a0214cfb29 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl1251/acx.c @@ -1,13 +1,13 @@ -#include "wl1251_acx.h" +#include "acx.h" #include <linux/module.h> #include <linux/slab.h> #include <linux/crc7.h> #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_cmd.h" -#include "wl1251_ps.h" +#include "reg.h" +#include "cmd.h" +#include "ps.h" int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod) diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl1251/acx.h index c7cc5c1e8a75..e54b21a4f8b1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl1251/acx.h @@ -24,7 +24,7 @@ #define __WL1251_ACX_H__ #include "wl1251.h" -#include "wl1251_cmd.h" +#include "cmd.h" /* Target's information element */ struct acx_header { diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl1251/boot.c index 468b47b0328a..61572dfa1f60 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl1251/boot.c @@ -22,12 +22,12 @@ #include <linux/gpio.h> #include <linux/slab.h> -#include "wl1251_reg.h" -#include "wl1251_boot.h" -#include "wl1251_io.h" -#include "wl1251_spi.h" -#include "wl1251_event.h" -#include "wl1251_acx.h" +#include "reg.h" +#include "boot.h" +#include "io.h" +#include "spi.h" +#include "event.h" +#include "acx.h" void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl1251/boot.h index 7661bc5e4662..7661bc5e4662 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl1251/boot.h diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl1251/cmd.c index 15fb68c6b542..0ade4bd617c0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl1251/cmd.c @@ -1,14 +1,14 @@ -#include "wl1251_cmd.h" +#include "cmd.h" #include <linux/module.h> #include <linux/slab.h> #include <linux/crc7.h> #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_ps.h" -#include "wl1251_acx.h" +#include "reg.h" +#include "io.h" +#include "ps.h" +#include "acx.h" /** * send command to firmware diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl1251/cmd.h index e5c74c631374..e5c74c631374 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl1251/debugfs.c index 6ffe4cd58561..6e5caaa9f613 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl1251/debugfs.c @@ -19,14 +19,14 @@ * */ -#include "wl1251_debugfs.h" +#include "debugfs.h" #include <linux/skbuff.h> #include <linux/slab.h> #include "wl1251.h" -#include "wl1251_acx.h" -#include "wl1251_ps.h" +#include "acx.h" +#include "ps.h" /* ms */ #define WL1251_DEBUGFS_STATS_LIFETIME 1000 diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl1251/debugfs.h index b3417c02a218..b3417c02a218 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ b/drivers/net/wireless/wl1251/debugfs.h diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl1251/event.c index 54223556b308..712372e50a87 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl1251/event.c @@ -21,10 +21,10 @@ */ #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_event.h" -#include "wl1251_ps.h" +#include "reg.h" +#include "io.h" +#include "event.h" +#include "ps.h" static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl1251/event.h index 30eb5d150bf7..30eb5d150bf7 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.h +++ b/drivers/net/wireless/wl1251/event.h diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl1251/init.c index c5daec05d9ee..89b43d35473c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl1251/init.c @@ -23,11 +23,11 @@ #include <linux/module.h> #include <linux/slab.h> -#include "wl1251_init.h" +#include "init.h" #include "wl12xx_80211.h" -#include "wl1251_acx.h" -#include "wl1251_cmd.h" -#include "wl1251_reg.h" +#include "acx.h" +#include "cmd.h" +#include "reg.h" int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl1251/init.h index 543f17582ead..543f17582ead 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl1251/init.h diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl1251/io.c index ad6ca68b303f..cdcadbf6ac2c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl1251/io.c @@ -20,8 +20,8 @@ */ #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" +#include "reg.h" +#include "io.h" /* FIXME: this is static data nowadays and the table can be removed */ static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl1251/io.h index c545e9d5f512..c545e9d5f512 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ b/drivers/net/wireless/wl1251/io.h diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl1251/main.c index faf221ca3f41..7a8762553cdc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -31,16 +31,16 @@ #include "wl1251.h" #include "wl12xx_80211.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_cmd.h" -#include "wl1251_event.h" -#include "wl1251_tx.h" -#include "wl1251_rx.h" -#include "wl1251_ps.h" -#include "wl1251_init.h" -#include "wl1251_debugfs.h" -#include "wl1251_boot.h" +#include "reg.h" +#include "io.h" +#include "cmd.h" +#include "event.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" +#include "debugfs.h" +#include "boot.h" void wl1251_enable_interrupts(struct wl1251 *wl) { diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl1251/ps.c index 0b997bdfec09..5ed47c8373d2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl1251/ps.c @@ -19,10 +19,10 @@ * */ -#include "wl1251_reg.h" -#include "wl1251_ps.h" -#include "wl1251_cmd.h" -#include "wl1251_io.h" +#include "reg.h" +#include "ps.h" +#include "cmd.h" +#include "io.h" /* in ms */ #define WL1251_WAKEUP_TIMEOUT 100 diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl1251/ps.h index e5db81fc1dfc..55c3dda75e69 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ b/drivers/net/wireless/wl1251/ps.h @@ -24,7 +24,7 @@ #define __WL1251_PS_H__ #include "wl1251.h" -#include "wl1251_acx.h" +#include "acx.h" int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); void wl1251_ps_elp_sleep(struct wl1251 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl1251/reg.h index a5809019c5c1..a5809019c5c1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl1251/reg.h diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl1251/rx.c index 25764592a596..efa53607d5c9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl1251/rx.c @@ -25,11 +25,11 @@ #include <net/mac80211.h> #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_rx.h" -#include "wl1251_cmd.h" -#include "wl1251_acx.h" +#include "reg.h" +#include "io.h" +#include "rx.h" +#include "cmd.h" +#include "acx.h" static void wl1251_rx_header(struct wl1251 *wl, struct wl1251_rx_descriptor *desc) diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl1251/rx.h index 4448f635a4d8..4448f635a4d8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl1251/rx.h diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl1251/sdio.c index 74ba9ced5393..74ba9ced5393 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl1251/spi.c index 320de79667a6..88fa8e69d0d1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -27,8 +27,8 @@ #include <linux/wl12xx.h> #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_spi.h" +#include "reg.h" +#include "spi.h" static irqreturn_t wl1251_irq(int irq, void *cookie) { diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl1251/spi.h index 7dcf3cf7ae40..16d506955cc0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl1251/spi.h @@ -23,9 +23,9 @@ #ifndef __WL1251_SPI_H__ #define __WL1251_SPI_H__ -#include "wl1251_cmd.h" -#include "wl1251_acx.h" -#include "wl1251_reg.h" +#include "cmd.h" +#include "acx.h" +#include "reg.h" #define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_WRITE 0x00000000 diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl1251/tx.c index 388492a7f41f..554b4f9a3d3e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl1251/tx.c @@ -24,10 +24,10 @@ #include <linux/module.h> #include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_tx.h" -#include "wl1251_ps.h" -#include "wl1251_io.h" +#include "reg.h" +#include "tx.h" +#include "ps.h" +#include "io.h" static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) { diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl1251/tx.h index 96011e78cd5a..81338d39b43e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl1251/tx.h @@ -24,7 +24,7 @@ #define __WL1251_TX_H__ #include <linux/bitops.h> -#include "wl1251_acx.h" +#include "acx.h" /* * diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index e113d4c1fb35..e113d4c1fb35 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h new file mode 100644 index 000000000000..184628027213 --- /dev/null +++ b/drivers/net/wireless/wl1251/wl12xx_80211.h @@ -0,0 +1,156 @@ +#ifndef __WL12XX_80211_H__ +#define __WL12XX_80211_H__ + +#include <linux/if_ether.h> /* ETH_ALEN */ + +/* RATES */ +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + + +/* This really should be 8, but not for our firmware */ +#define MAX_SUPPORTED_RATES 32 +#define COUNTRY_STRING_LEN 3 +#define MAX_COUNTRY_TRIPLETS 32 + +/* Headers */ +struct ieee80211_header { + __le16 frame_ctl; + __le16 duration_id; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __packed; + +struct wl12xx_ie_header { + u8 id; + u8 len; +} __packed; + +/* IEs */ + +struct wl12xx_ie_ssid { + struct wl12xx_ie_header header; + char ssid[IW_ESSID_MAX_SIZE]; +} __packed; + +struct wl12xx_ie_rates { + struct wl12xx_ie_header header; + u8 rates[MAX_SUPPORTED_RATES]; +} __packed; + +struct wl12xx_ie_ds_params { + struct wl12xx_ie_header header; + u8 channel; +} __packed; + +struct country_triplet { + u8 channel; + u8 num_channels; + u8 max_tx_power; +} __packed; + +struct wl12xx_ie_country { + struct wl12xx_ie_header header; + u8 country_string[COUNTRY_STRING_LEN]; + struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; +} __packed; + + +/* Templates */ + +struct wl12xx_beacon_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __packed; + +struct wl12xx_null_data_template { + struct ieee80211_header header; +} __packed; + +struct wl12xx_ps_poll_template { + __le16 fc; + __le16 aid; + u8 bssid[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} __packed; + +struct wl12xx_qos_null_data_template { + struct ieee80211_header header; + __le16 qos_ctl; +} __packed; + +struct wl12xx_probe_req_template { + struct ieee80211_header header; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; +} __packed; + + +struct wl12xx_probe_resp_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __packed; + +#endif diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 4a8bb25c1739..b447559f1db5 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -5,40 +5,6 @@ menuconfig WL12XX This will enable TI wl12xx driver support. The drivers make use of the mac80211 stack. -config WL1251 - tristate "TI wl1251 support" - depends on WL12XX && GENERIC_HARDIRQS - select FW_LOADER - select CRC7 - ---help--- - This module adds support for wireless adapters based on - TI wl1251 chipset. - - If you choose to build a module, it'll be called wl1251. Say - N if unsure. - -config WL1251_SPI - tristate "TI wl1251 SPI support" - depends on WL1251 && SPI_MASTER - ---help--- - This module adds support for the SPI interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SPI bus. - - If you choose to build a module, it'll be called wl1251_spi. - Say N if unsure. - -config WL1251_SDIO - tristate "TI wl1251 SDIO support" - depends on WL1251 && MMC - ---help--- - This module adds support for the SDIO interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SDIO bus. - - If you choose to build a module, it'll be called - wl1251_sdio. Say N if unsure. - config WL1271 tristate "TI wl1271 support" depends on WL12XX && GENERIC_HARDIRQS diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 0d334d6f86f4..3a807444b2af 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,12 +1,3 @@ -wl1251-objs = wl1251_main.o wl1251_event.o \ - wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ - wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_debugfs.o wl1251_io.o - -obj-$(CONFIG_WL1251) += wl1251.o -obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o -obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o - wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ wl1271_ps.o wl1271_acx.o wl1271_boot.o \ diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index 4c250d7dc3fa..784ef3432641 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -30,6 +30,7 @@ #include <linux/mmc/card.h> #include <linux/gpio.h> #include <linux/wl12xx.h> +#include <linux/pm_runtime.h> #include "wl1271.h" #include "wl12xx_80211.h" @@ -160,12 +161,19 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, static int wl1271_sdio_power_on(struct wl1271 *wl) { struct sdio_func *func = wl_to_func(wl); + int ret; + + /* Power up the card */ + ret = pm_runtime_get_sync(&func->dev); + if (ret < 0) + goto out; sdio_claim_host(func); sdio_enable_func(func); sdio_release_host(func); - return 0; +out: + return ret; } static int wl1271_sdio_power_off(struct wl1271 *wl) @@ -176,15 +184,12 @@ static int wl1271_sdio_power_off(struct wl1271 *wl) sdio_disable_func(func); sdio_release_host(func); - return 0; + /* Power down the card */ + return pm_runtime_put_sync(&func->dev); } static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) { - /* Let the SDIO stack handle wlan_enable control, so we - * keep host claimed while wlan is in use to keep wl1271 - * alive. - */ if (enable) return wl1271_sdio_power_on(wl); else @@ -256,6 +261,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, sdio_set_drvdata(func, wl); + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + wl1271_notice("initialized"); return 0; @@ -274,16 +282,39 @@ static void __devexit wl1271_remove(struct sdio_func *func) { struct wl1271 *wl = sdio_get_drvdata(func); + /* Undo decrement done above in wl1271_probe */ + pm_runtime_get_noresume(&func->dev); + wl1271_unregister_hw(wl); free_irq(wl->irq, wl); wl1271_free_hw(wl); } +static int wl1271_suspend(struct device *dev) +{ + /* Tell MMC/SDIO core it's OK to power down the card + * (if it isn't already), but not to remove it completely */ + return 0; +} + +static int wl1271_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops wl1271_sdio_pm_ops = { + .suspend = wl1271_suspend, + .resume = wl1271_resume, +}; + static struct sdio_driver wl1271_sdio_driver = { .name = "wl1271_sdio", .id_table = wl1271_devices, .probe = wl1271_probe, .remove = __devexit_p(wl1271_remove), + .drv = { + .pm = &wl1271_sdio_pm_ops, + }, }; static int __init wl1271_init(void) |