diff options
Diffstat (limited to 'drivers/net/wireless/ath')
62 files changed, 1534 insertions, 1847 deletions
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 32bf79e6a320..a9111e1161fd 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1945,7 +1945,8 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, static int ar9170_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { switch (action) { case IEEE80211_AMPDU_RX_START: diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e43210c8585c..a6c6a466000f 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -108,12 +108,14 @@ enum ath_cipher { * struct ath_ops - Register read/write operations * * @read: Register read + * @multi_read: Multiple register read * @write: Register write * @enable_write_buffer: Enable multiple register writes * @write_flush: flush buffered register writes and disable buffering */ struct ath_ops { unsigned int (*read)(void *, u32 reg_offset); + void (*multi_read)(void *, u32 *addr, u32 *val, u16 count); void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); void (*write_flush) (void *); diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index e0793319389d..e18a9aa7b6ca 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -40,6 +40,17 @@ config ATH5K_DEBUG modprobe ath5k debug=0x00000400 +config ATH5K_TRACER + bool "Atheros 5xxx tracer" + depends on ATH5K + depends on EVENT_TRACING + ---help--- + Say Y here to enable tracepoints for the ath5k driver + using the kernel tracing infrastructure. Select this + option if you are interested in debugging the driver. + + If unsure, say N. + config ATH5K_AHB bool "Atheros 5xxx AHB bus support" depends on (ATHEROS_AR231X && !PCI) diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 707cde149248..ae84b86c3bf2 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -31,7 +31,8 @@ static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz) *csz = L1_CACHE_BYTES >> 2; } -bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) +static bool +ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath5k_softc *sc = common->priv; struct platform_device *pdev = to_platform_device(sc->dev); @@ -46,10 +47,10 @@ bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) eeprom += off; if (eeprom > eeprom_end) - return -EINVAL; + return false; *data = *eeprom; - return 0; + return true; } int ath5k_hw_read_srev(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 407e39c2b10b..e43175a89d67 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -210,14 +210,9 @@ /* Initial values */ #define AR5K_INIT_CYCRSSI_THR1 2 -/* Tx retry limits */ -#define AR5K_INIT_SH_RETRY 10 -#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY -/* For station mode */ -#define AR5K_INIT_SSH_RETRY 32 -#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY -#define AR5K_INIT_TX_RETRY 10 - +/* Tx retry limit defaults from standard */ +#define AR5K_INIT_RETRY_SHORT 7 +#define AR5K_INIT_RETRY_LONG 4 /* Slot time */ #define AR5K_INIT_SLOT_TIME_TURBO 6 @@ -1057,7 +1052,9 @@ struct ath5k_hw { #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version - u32 ah_limit_tx_retries; + u8 ah_retry_long; + u8 ah_retry_short; + u8 ah_coverage_class; bool ah_ack_bitrate_high; u8 ah_bwmode; @@ -1067,7 +1064,6 @@ struct ath5k_hw { u8 ah_ant_mode; u8 ah_tx_ant; u8 ah_def_ant; - bool ah_software_retry; struct ath5k_capabilities ah_capabilities; @@ -1250,6 +1246,8 @@ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); +void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, + unsigned int queue); u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index cdac5cff0177..c71fdbb4c439 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -118,8 +118,8 @@ int ath5k_hw_init(struct ath5k_softc *sc) ah->ah_bwmode = AR5K_BWMODE_DEFAULT; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; ah->ah_imr = 0; - ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; - ah->ah_software_retry = false; + ah->ah_retry_short = AR5K_INIT_RETRY_SHORT; + ah->ah_retry_long = AR5K_INIT_RETRY_LONG; ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; ah->ah_noise_floor = -95; /* until first NF calibration is run */ sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 09ae4ef0fd51..dbc45e085434 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -61,6 +61,9 @@ #include "debug.h" #include "ani.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + int ath5k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -242,73 +245,68 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re \********************/ /* - * Convert IEEE channel number to MHz frequency. - */ -static inline short -ath5k_ieee2mhz(short chan) -{ - if (chan <= 14 || chan >= 27) - return ieee80211chan2mhz(chan); - else - return 2212 + chan * 20; -} - -/* * Returns true for the channel numbers used without all_channels modparam. */ -static bool ath5k_is_standard_channel(short chan) +static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) { - return ((chan <= 14) || - /* UNII 1,2 */ - ((chan & 3) == 0 && chan >= 36 && chan <= 64) || + if (band == IEEE80211_BAND_2GHZ && chan <= 14) + return true; + + return /* UNII 1,2 */ + (((chan & 3) == 0 && chan >= 36 && chan <= 64) || /* midband */ ((chan & 3) == 0 && chan >= 100 && chan <= 140) || /* UNII-3 */ - ((chan & 3) == 1 && chan >= 149 && chan <= 165)); + ((chan & 3) == 1 && chan >= 149 && chan <= 165) || + /* 802.11j 5.030-5.080 GHz (20MHz) */ + (chan == 8 || chan == 12 || chan == 16) || + /* 802.11j 4.9GHz (20MHz) */ + (chan == 184 || chan == 188 || chan == 192 || chan == 196)); } static unsigned int -ath5k_copy_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max) +ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, + unsigned int mode, unsigned int max) { - unsigned int i, count, size, chfreq, freq, ch; - - if (!test_bit(mode, ah->ah_modes)) - return 0; + unsigned int count, size, chfreq, freq, ch; + enum ieee80211_band band; switch (mode) { case AR5K_MODE_11A: /* 1..220, but 2GHz frequencies are filtered by check_channel */ - size = 220 ; + size = 220; chfreq = CHANNEL_5GHZ; + band = IEEE80211_BAND_5GHZ; break; case AR5K_MODE_11B: case AR5K_MODE_11G: size = 26; chfreq = CHANNEL_2GHZ; + band = IEEE80211_BAND_2GHZ; break; default: ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); return 0; } - for (i = 0, count = 0; i < size && max > 0; i++) { - ch = i + 1 ; - freq = ath5k_ieee2mhz(ch); + count = 0; + for (ch = 1; ch <= size && count < max; ch++) { + freq = ieee80211_channel_to_frequency(ch, band); + + if (freq == 0) /* mapping failed - not a standard channel */ + continue; /* Check if channel is supported by the chipset */ if (!ath5k_channel_ok(ah, freq, chfreq)) continue; - if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) + if (!modparam_all_channels && + !ath5k_is_standard_channel(ch, band)) continue; /* Write channel info and increment counter */ channels[count].center_freq = freq; - channels[count].band = (chfreq == CHANNEL_2GHZ) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + channels[count].band = band; switch (mode) { case AR5K_MODE_11A: case AR5K_MODE_11G: @@ -319,7 +317,6 @@ ath5k_copy_channels(struct ath5k_hw *ah, } count++; - max--; } return count; @@ -364,7 +361,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw) sband->n_bitrates = 12; sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, + sband->n_channels = ath5k_setup_channels(ah, sband->channels, AR5K_MODE_11G, max_c); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; @@ -390,7 +387,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw) } sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, + sband->n_channels = ath5k_setup_channels(ah, sband->channels, AR5K_MODE_11B, max_c); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; @@ -410,7 +407,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw) sband->n_bitrates = 8; sband->channels = &sc->channels[count_c]; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, + sband->n_channels = ath5k_setup_channels(ah, sband->channels, AR5K_MODE_11A, max_c); hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; @@ -445,18 +442,6 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) return ath5k_reset(sc, chan, true); } -static void -ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) -{ - sc->curmode = mode; - - if (mode == AR5K_MODE_11A) { - sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; - } else { - sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; - } -} - struct ath_vif_iter_data { const u8 *hw_macaddr; u8 mask[ETH_ALEN]; @@ -569,7 +554,7 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) "hw_rix out of bounds: %x\n", hw_rix)) return 0; - rix = sc->rate_idx[sc->curband->band][hw_rix]; + rix = sc->rate_idx[sc->curchan->band][hw_rix]; if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) rix = 0; @@ -1379,7 +1364,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, rxs->flag |= RX_FLAG_TSFT; rxs->freq = sc->curchan->center_freq; - rxs->band = sc->curband->band; + rxs->band = sc->curchan->band; rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi; @@ -1394,10 +1379,10 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, rxs->flag |= ath5k_rx_decrypted(sc, skb, rs); if (rxs->rate_idx >= 0 && rs->rs_rate == - sc->curband->bitrates[rxs->rate_idx].hw_value_short) + sc->sbands[sc->curchan->band].bitrates[rxs->rate_idx].hw_value_short) rxs->flag |= RX_FLAG_SHORTPRE; - ath5k_debug_dump_skb(sc, skb, "RX ", 0); + trace_ath5k_rx(sc, skb); ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi); @@ -1542,7 +1527,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, unsigned long flags; int padsize; - ath5k_debug_dump_skb(sc, skb, "TX ", 1); + trace_ath5k_tx(sc, skb, txq); /* * The hardware expects the header padded to 4 byte boundaries. @@ -1591,7 +1576,7 @@ drop_packet: static void ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, - struct ath5k_tx_status *ts) + struct ath5k_txq *txq, struct ath5k_tx_status *ts) { struct ieee80211_tx_info *info; int i; @@ -1643,6 +1628,7 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, else sc->stats.antenna_tx[0]++; /* invalid */ + trace_ath5k_tx_complete(sc, skb, txq, ts); ieee80211_tx_status(sc->hw, skb); } @@ -1679,7 +1665,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE); - ath5k_tx_frame_completed(sc, skb, &ts); + ath5k_tx_frame_completed(sc, skb, txq, &ts); } /* @@ -1821,8 +1807,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } - ath5k_debug_dump_skb(sc, skb, "BC ", 1); - ath5k_txbuf_free_skb(sc, avf->bbuf); avf->bbuf->skb = skb; ret = ath5k_beacon_setup(sc, avf->bbuf); @@ -1917,6 +1901,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->opmode == NL80211_IFTYPE_MESH_POINT) ath5k_beacon_update(sc->hw, vif); + trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]); + ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", @@ -2417,7 +2403,8 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops) /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { hw->max_rates = 4; - hw->max_rate_tries = 11; + hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, + AR5K_INIT_RETRY_LONG); } hw->vif_data_size = sizeof(struct ath5k_vif); @@ -2554,7 +2541,6 @@ ath5k_init_hw(struct ath5k_softc *sc) * and then setup of the interrupt mask. */ sc->curchan = sc->hw->conf.channel; - sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; @@ -2681,10 +2667,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, * so we should also free any remaining * tx buffers */ ath5k_drain_tx_buffs(sc); - if (chan) { + if (chan) sc->curchan = chan; - sc->curband = &sc->sbands[chan->band]; - } ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL, skip_pcu); if (ret) { @@ -2782,12 +2766,6 @@ ath5k_init(struct ieee80211_hw *hw) goto err; } - /* NB: setup here so ath5k_rate_update is happy */ - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - ath5k_setcurmode(sc, AR5K_MODE_11A); - else - ath5k_setcurmode(sc, AR5K_MODE_11B); - /* * Allocate tx+rx descriptors and populate the lists. */ diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 6d511476e4d2..8f919dca95f1 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -183,8 +183,6 @@ struct ath5k_softc { enum nl80211_iftype opmode; struct ath5k_hw *ah; /* Atheros HW */ - struct ieee80211_supported_band *curband; - #ifdef CONFIG_ATH5K_DEBUG struct ath5k_dbg_info debug; /* debug info */ #endif /* CONFIG_ATH5K_DEBUG */ @@ -202,7 +200,6 @@ struct ath5k_softc { #define ATH_STAT_STARTED 4 /* opened & irqs enabled */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ - unsigned int curmode; /* current phy mode */ struct ieee80211_channel *curchan; /* current h/w channel */ u16 nvifs; diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index 31cad80e9b01..f77e8a703c5c 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -32,23 +32,24 @@ */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) { + struct ath5k_capabilities *caps = &ah->ah_capabilities; u16 ee_header; /* Capabilities stored in the EEPROM */ - ee_header = ah->ah_capabilities.cap_eeprom.ee_header; + ee_header = caps->cap_eeprom.ee_header; if (ah->ah_version == AR5K_AR5210) { /* * Set radio capabilities * (The AR5110 only supports the middle 5GHz band) */ - ah->ah_capabilities.cap_range.range_5ghz_min = 5120; - ah->ah_capabilities.cap_range.range_5ghz_max = 5430; - ah->ah_capabilities.cap_range.range_2ghz_min = 0; - ah->ah_capabilities.cap_range.range_2ghz_max = 0; + caps->cap_range.range_5ghz_min = 5120; + caps->cap_range.range_5ghz_max = 5430; + caps->cap_range.range_2ghz_min = 0; + caps->cap_range.range_2ghz_max = 0; /* Set supported modes */ - __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A, caps->cap_mode); } else { /* * XXX The tranceiver supports frequencies from 4920 to 6100GHz @@ -56,9 +57,8 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) * XXX current ieee80211 implementation because the IEEE * XXX channel mapping does not support negative channel * XXX numbers (2312MHz is channel -19). Of course, this - * XXX doesn't matter because these channels are out of range - * XXX but some regulation domains like MKK (Japan) will - * XXX support frequencies somewhere around 4.8GHz. + * XXX doesn't matter because these channels are out of the + * XXX legal range. */ /* @@ -66,13 +66,14 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) */ if (AR5K_EEPROM_HDR_11A(ee_header)) { - /* 4920 */ - ah->ah_capabilities.cap_range.range_5ghz_min = 5005; - ah->ah_capabilities.cap_range.range_5ghz_max = 6100; + if (ath_is_49ghz_allowed(caps->cap_eeprom.ee_regdomain)) + caps->cap_range.range_5ghz_min = 4920; + else + caps->cap_range.range_5ghz_min = 5005; + caps->cap_range.range_5ghz_max = 6100; /* Set supported modes */ - __set_bit(AR5K_MODE_11A, - ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A, caps->cap_mode); } /* Enable 802.11b if a 2GHz capable radio (2111/5112) is @@ -81,32 +82,29 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) (AR5K_EEPROM_HDR_11G(ee_header) && ah->ah_version != AR5K_AR5211)) { /* 2312 */ - ah->ah_capabilities.cap_range.range_2ghz_min = 2412; - ah->ah_capabilities.cap_range.range_2ghz_max = 2732; + caps->cap_range.range_2ghz_min = 2412; + caps->cap_range.range_2ghz_max = 2732; if (AR5K_EEPROM_HDR_11B(ee_header)) - __set_bit(AR5K_MODE_11B, - ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11B, caps->cap_mode); if (AR5K_EEPROM_HDR_11G(ee_header) && ah->ah_version != AR5K_AR5211) - __set_bit(AR5K_MODE_11G, - ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11G, caps->cap_mode); } } /* Set number of supported TX queues */ if (ah->ah_version == AR5K_AR5210) - ah->ah_capabilities.cap_queues.q_tx_num = - AR5K_NUM_TX_QUEUES_NOQCU; + caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; else - ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; /* newer hardware has PHY error counters */ if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) - ah->ah_capabilities.cap_has_phyerr_counters = true; + caps->cap_has_phyerr_counters = true; else - ah->ah_capabilities.cap_has_phyerr_counters = false; + caps->cap_has_phyerr_counters = false; return 0; } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index d2f84d76bb07..0230f30e9e9a 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -308,8 +308,6 @@ static const struct { { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" }, { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" }, { ATH5K_DEBUG_LED, "led", "LED management" }, - { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, - { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, { ATH5K_DEBUG_DMA, "dma", "dma start/stop" }, { ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" }, @@ -1036,24 +1034,6 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) } void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx) -{ - char buf[16]; - - if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || - (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) - return; - - snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); - - print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, - min(200U, skb->len)); - - printk(KERN_DEBUG "\n"); -} - -void ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_desc *ds = bf->desc; diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 3e34428d5126..b0355aef68d3 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -116,8 +116,6 @@ enum ath5k_debug_level { ATH5K_DEBUG_CALIBRATE = 0x00000020, ATH5K_DEBUG_TXPOWER = 0x00000040, ATH5K_DEBUG_LED = 0x00000080, - ATH5K_DEBUG_DUMP_RX = 0x00000100, - ATH5K_DEBUG_DUMP_TX = 0x00000200, ATH5K_DEBUG_DUMPBANDS = 0x00000400, ATH5K_DEBUG_DMA = 0x00000800, ATH5K_DEBUG_ANI = 0x00002000, @@ -152,10 +150,6 @@ void ath5k_debug_dump_bands(struct ath5k_softc *sc); void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx); - -void ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); #else /* no debugging */ @@ -182,10 +176,6 @@ static inline void ath5k_debug_dump_bands(struct ath5k_softc *sc) {} static inline void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx) {} - -static inline void ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {} #endif /* ifdef CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 80e625608bac..b6561f785c6e 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -72,7 +72,6 @@ static int ath5k_eeprom_init_header(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int ret; u16 val; u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; @@ -192,7 +191,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 o = *offset; u16 val; - int ret, i = 0; + int i = 0; AR5K_EEPROM_READ(o++, val); ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; @@ -252,7 +251,6 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 o = *offset; u16 val; - int ret; ee->ee_n_piers[mode] = 0; AR5K_EEPROM_READ(o++, val); @@ -515,7 +513,6 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, int o = *offset; int i = 0; u8 freq1, freq2; - int ret; u16 val; ee->ee_n_piers[mode] = 0; @@ -551,7 +548,7 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; - int i, ret; + int i; u16 val; u8 mask; @@ -970,7 +967,6 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) u32 offset; u8 i, c; u16 val; - int ret; u8 pd_gains = 0; /* Count how many curves we have and @@ -1228,7 +1224,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) struct ath5k_chan_pcal_info *chinfo; u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; u32 offset; - int idx, i, ret; + int idx, i; u16 val; u8 pd_gains = 0; @@ -1419,7 +1415,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) u8 *rate_target_pwr_num; u32 offset; u16 val; - int ret, i; + int i; offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; @@ -1593,7 +1589,7 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) struct ath5k_edge_power *rep; unsigned int fmask, pmask; unsigned int ctl_mode; - int ret, i, j; + int i, j; u32 offset; u16 val; @@ -1733,16 +1729,12 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) u8 mac_d[ETH_ALEN] = {}; u32 total, offset; u16 data; - int octet, ret; + int octet; - ret = ath5k_hw_nvram_read(ah, 0x20, &data); - if (ret) - return ret; + AR5K_EEPROM_READ(0x20, data); for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - ret = ath5k_hw_nvram_read(ah, offset, &data); - if (ret) - return ret; + AR5K_EEPROM_READ(offset, data); total += data; mac_d[octet + 1] = data & 0xff; diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 7c09e150dbdc..6511c27d938e 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -241,9 +241,8 @@ enum ath5k_eeprom_freq_bands{ #define AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz 6250 #define AR5K_EEPROM_READ(_o, _v) do { \ - ret = ath5k_hw_nvram_read(ah, (_o), &(_v)); \ - if (ret) \ - return ret; \ + if (!ath5k_hw_nvram_read(ah, (_o), &(_v))) \ + return -EIO; \ } while (0) #define AR5K_EEPROM_READ_HDR(_o, _v) \ @@ -269,29 +268,6 @@ enum ath5k_ctl_mode { AR5K_CTL_MODE_M = 15, }; -/* Default CTL ids for the 3 main reg domains. - * Atheros only uses these by default but vendors - * can have up to 32 different CTLs for different - * scenarios. Note that theese values are ORed with - * the mode id (above) so we can have up to 24 CTL - * datasets out of these 3 main regdomains. That leaves - * 8 ids that can be used by vendors and since 0x20 is - * missing from HAL sources i guess this is the set of - * custom CTLs vendors can use. */ -#define AR5K_CTL_FCC 0x10 -#define AR5K_CTL_CUSTOM 0x20 -#define AR5K_CTL_ETSI 0x30 -#define AR5K_CTL_MKK 0x40 - -/* Indicates a CTL with only mode set and - * no reg domain mapping, such CTLs are used - * for world roaming domains or simply when - * a reg domain is not set */ -#define AR5K_CTL_NO_REGDOMAIN 0xf0 - -/* Indicates an empty (invalid) CTL */ -#define AR5K_CTL_NO_CTL 0xff - /* Per channel calibration data, used for power table setup */ struct ath5k_chan_pcal_info_rf5111 { /* Power levels in half dbm units diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index d76d68c99f72..36a51995a7bc 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -226,6 +226,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) struct ath5k_hw *ah = sc->ah; struct ieee80211_conf *conf = &hw->conf; int ret = 0; + int i; mutex_lock(&sc->lock); @@ -243,6 +244,14 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); } + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + ah->ah_retry_long = conf->long_frame_max_tx_count; + ah->ah_retry_short = conf->short_frame_max_tx_count; + + for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) + ath5k_hw_set_tx_retry_limits(ah, i); + } + /* TODO: * 1) Move this on config_interface and handle each case * separately eg. when we have only one STA vif, use diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 7f8c5b0e9d2a..66598a0d1df0 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -69,7 +69,8 @@ static void ath5k_pci_read_cachesize(struct ath_common *common, int *csz) /* * Read from eeprom */ -bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) +static bool +ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) { struct ath5k_hw *ah = (struct ath5k_hw *) common->ah; u32 status, timeout; @@ -90,15 +91,15 @@ bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); if (status & AR5K_EEPROM_STAT_RDDONE) { if (status & AR5K_EEPROM_STAT_RDERR) - return -EIO; + return false; *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & 0xffff); - return 0; + return true; } udelay(15); } - return -ETIMEDOUT; + return false; } int ath5k_hw_read_srev(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 2c9c9e793d4e..3343fb9e4940 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -228,24 +228,9 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, /* * Set tx retry limits on DCU */ -static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, - unsigned int queue) +void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, + unsigned int queue) { - u32 retry_lg, retry_sh; - - /* - * Calculate and set retry limits - */ - if (ah->ah_software_retry) { - /* XXX Need to test this */ - retry_lg = ah->ah_limit_tx_retries; - retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? - AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; - } else { - retry_lg = AR5K_INIT_LG_RETRY; - retry_sh = AR5K_INIT_SH_RETRY; - } - /* Single data queue on AR5210 */ if (ah->ah_version == AR5K_AR5210) { struct ath5k_txq_info *tq = &ah->ah_txq[queue]; @@ -255,25 +240,26 @@ static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) - | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_NODCU_RETRY_LMT_SLG_RETRY) - | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_NODCU_RETRY_LMT_SSH_RETRY) - | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) - | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), + | AR5K_REG_SM(ah->ah_retry_long, + AR5K_NODCU_RETRY_LMT_SLG_RETRY) + | AR5K_REG_SM(ah->ah_retry_short, + AR5K_NODCU_RETRY_LMT_SSH_RETRY) + | AR5K_REG_SM(ah->ah_retry_long, + AR5K_NODCU_RETRY_LMT_LG_RETRY) + | AR5K_REG_SM(ah->ah_retry_short, + AR5K_NODCU_RETRY_LMT_SH_RETRY), AR5K_NODCU_RETRY_LMT); /* DCU on AR5211+ */ } else { ath5k_hw_reg_write(ah, - AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_DCU_RETRY_LMT_SLG_RETRY) | - AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_DCU_RETRY_LMT_SSH_RETRY) | - AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | - AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), + AR5K_REG_SM(ah->ah_retry_long, + AR5K_DCU_RETRY_LMT_RTS) + | AR5K_REG_SM(ah->ah_retry_long, + AR5K_DCU_RETRY_LMT_STA_RTS) + | AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short), + AR5K_DCU_RETRY_LMT_STA_DATA), AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); } - return; } /** diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 7ad05d401ab5..e1c9abd8c879 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -686,16 +686,15 @@ /* * DCU retry limit registers + * all these fields don't allow zero values */ #define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ -#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ -#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 -#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ -#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 -#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ -#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 -#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ -#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_DCU_RETRY_LMT_RTS 0x0000000f /* RTS failure limit. Transmission fails if no CTS is received for this number of times */ +#define AR5K_DCU_RETRY_LMT_RTS_S 0 +#define AR5K_DCU_RETRY_LMT_STA_RTS 0x00003f00 /* STA RTS failure limit. If exceeded CW reset */ +#define AR5K_DCU_RETRY_LMT_STA_RTS_S 8 +#define AR5K_DCU_RETRY_LMT_STA_DATA 0x000fc000 /* STA data failure limit. If exceeded CW reset. */ +#define AR5K_DCU_RETRY_LMT_STA_DATA_S 14 #define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) /* @@ -1064,7 +1063,7 @@ /* * EEPROM command register */ -#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ +#define AR5K_EEPROM_CMD 0x6008 /* Register Address */ #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ @@ -1084,7 +1083,7 @@ /* * EEPROM config register */ -#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ +#define AR5K_EEPROM_CFG 0x6010 /* Register Address */ #define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ #define AR5K_EEPROM_CFG_SIZE_AUTO 0 #define AR5K_EEPROM_CFG_SIZE_4KBIT 1 @@ -1126,7 +1125,7 @@ * Second station id register (Upper 16 bits of MAC address + PCU settings) */ #define AR5K_STA_ID1 0x8004 /* Register Address */ -#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC address */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h new file mode 100644 index 000000000000..2de68adb6240 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/trace.h @@ -0,0 +1,107 @@ +#if !defined(__TRACE_ATH5K_H) || defined(TRACE_HEADER_MULTI_READ) +#define __TRACE_ATH5K_H + +#include <linux/tracepoint.h> +#include "base.h" + +#ifndef CONFIG_ATH5K_TRACER +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +struct sk_buff; + +#define PRIV_ENTRY __field(struct ath5k_softc *, priv) +#define PRIV_ASSIGN __entry->priv = priv + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ath5k + +TRACE_EVENT(ath5k_rx, + TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb), + TP_ARGS(priv, skb), + TP_STRUCT__entry( + PRIV_ENTRY + __field(unsigned long, skbaddr) + __dynamic_array(u8, frame, skb->len) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->skbaddr = (unsigned long) skb; + memcpy(__get_dynamic_array(frame), skb->data, skb->len); + ), + TP_printk( + "[%p] RX skb=%lx", __entry->priv, __entry->skbaddr + ) +); + +TRACE_EVENT(ath5k_tx, + TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb, + struct ath5k_txq *q), + + TP_ARGS(priv, skb, q), + + TP_STRUCT__entry( + PRIV_ENTRY + __field(unsigned long, skbaddr) + __field(u8, qnum) + __dynamic_array(u8, frame, skb->len) + ), + + TP_fast_assign( + PRIV_ASSIGN; + __entry->skbaddr = (unsigned long) skb; + __entry->qnum = (u8) q->qnum; + memcpy(__get_dynamic_array(frame), skb->data, skb->len); + ), + + TP_printk( + "[%p] TX skb=%lx q=%d", __entry->priv, __entry->skbaddr, + __entry->qnum + ) +); + +TRACE_EVENT(ath5k_tx_complete, + TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb, + struct ath5k_txq *q, struct ath5k_tx_status *ts), + + TP_ARGS(priv, skb, q, ts), + + TP_STRUCT__entry( + PRIV_ENTRY + __field(unsigned long, skbaddr) + __field(u8, qnum) + __field(u8, ts_status) + __field(s8, ts_rssi) + __field(u8, ts_antenna) + ), + + TP_fast_assign( + PRIV_ASSIGN; + __entry->skbaddr = (unsigned long) skb; + __entry->qnum = (u8) q->qnum; + __entry->ts_status = ts->ts_status; + __entry->ts_rssi = ts->ts_rssi; + __entry->ts_antenna = ts->ts_antenna; + ), + + TP_printk( + "[%p] TX end skb=%lx q=%d stat=%x rssi=%d ant=%x", + __entry->priv, __entry->skbaddr, __entry->qnum, + __entry->ts_status, __entry->ts_rssi, __entry->ts_antenna + ) +); + +#endif /* __TRACE_ATH5K_H */ + +#ifdef CONFIG_ATH5K_TRACER + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/net/wireless/ath/ath5k +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include <trace/define_trace.h> + +#endif diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index aca01621c205..4d66ca8042eb 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -4,7 +4,6 @@ ath9k-y += beacon.o \ main.o \ recv.o \ xmit.o \ - virtual.o \ ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_PCI) += pci.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 25a6e4417cdb..993672105963 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -54,7 +54,6 @@ static struct ath_bus_ops ath_ahb_bus_ops = { static int ath_ahb_probe(struct platform_device *pdev) { void __iomem *mem; - struct ath_wiphy *aphy; struct ath_softc *sc; struct ieee80211_hw *hw; struct resource *res; @@ -92,8 +91,7 @@ static int ath_ahb_probe(struct platform_device *pdev) irq = res->start; - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + - sizeof(struct ath_softc), &ath9k_ops); + hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); ret = -ENOMEM; @@ -103,11 +101,7 @@ static int ath_ahb_probe(struct platform_device *pdev) SET_IEEE80211_DEV(hw, &pdev->dev); platform_set_drvdata(pdev, hw); - aphy = hw->priv; - sc = (struct ath_softc *) (aphy + 1); - aphy->sc = sc; - aphy->hw = hw; - sc->pri_wiphy = aphy; + sc = hw->priv; sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; @@ -151,8 +145,7 @@ static int ath_ahb_remove(struct platform_device *pdev) struct ieee80211_hw *hw = platform_get_drvdata(pdev); if (hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; void __iomem *mem = sc->mem; ath9k_deinit_device(sc); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 5e300bd3d264..76388c6d6692 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -805,7 +805,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); - if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9271(ah)) { + if (!ar9285_hw_cl_cal(ah, chan)) + return false; + } else if (AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_hw_clc(ah, chan)) return false; } else { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 4819747fa4c3..4a9271802991 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3673,7 +3673,7 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) return; reg_pmu_set = (5 << 1) | (7 << 4) | (1 << 8) | - (7 << 14) | (6 << 17) | (1 << 20) | + (2 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | (1 << 28); REG_WRITE(ah, AR_PHY_PMU1, reg_pmu_set); @@ -3959,19 +3959,19 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) { #define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) /* make sure forced gain is not set */ - REG_WRITE(ah, 0xa458, 0); + REG_WRITE(ah, AR_PHY_TX_FORCED_GAIN, 0); /* Write the OFDM power per rate set */ /* 6 (LSB), 9, 12, 18 (MSB) */ - REG_WRITE(ah, 0xa3c0, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(0), POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0)); /* 24 (LSB), 36, 48, 54 (MSB) */ - REG_WRITE(ah, 0xa3c4, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(1), POW_SM(pPwrArray[ALL_TARGET_LEGACY_54], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_48], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_36], 8) | @@ -3980,14 +3980,14 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Write the CCK power per rate set */ /* 1L (LSB), reserved, 2L, 2S (MSB) */ - REG_WRITE(ah, 0xa3c8, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(2), POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | /* POW_SM(txPowerTimes2, 8) | this is reserved for AR9003 */ POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)); /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */ - REG_WRITE(ah, 0xa3cc, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(3), POW_SM(pPwrArray[ALL_TARGET_LEGACY_11S], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_11L], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_5S], 8) | @@ -3997,7 +3997,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Write the HT20 power per rate set */ /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ - REG_WRITE(ah, 0xa3d0, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(4), POW_SM(pPwrArray[ALL_TARGET_HT20_5], 24) | POW_SM(pPwrArray[ALL_TARGET_HT20_4], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_1_3_9_11_17_19], 8) | @@ -4005,7 +4005,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 6 (LSB), 7, 12, 13 (MSB) */ - REG_WRITE(ah, 0xa3d4, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(5), POW_SM(pPwrArray[ALL_TARGET_HT20_13], 24) | POW_SM(pPwrArray[ALL_TARGET_HT20_12], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_7], 8) | @@ -4013,7 +4013,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 14 (LSB), 15, 20, 21 */ - REG_WRITE(ah, 0xa3e4, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(9), POW_SM(pPwrArray[ALL_TARGET_HT20_21], 24) | POW_SM(pPwrArray[ALL_TARGET_HT20_20], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_15], 8) | @@ -4023,7 +4023,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Mixed HT20 and HT40 rates */ /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */ - REG_WRITE(ah, 0xa3e8, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(10), POW_SM(pPwrArray[ALL_TARGET_HT40_23], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_22], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_23], 8) | @@ -4035,7 +4035,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) * correct PAR difference between HT40 and HT20/LEGACY * 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ - REG_WRITE(ah, 0xa3d8, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(6), POW_SM(pPwrArray[ALL_TARGET_HT40_5], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_4], 16) | POW_SM(pPwrArray[ALL_TARGET_HT40_1_3_9_11_17_19], 8) | @@ -4043,7 +4043,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 6 (LSB), 7, 12, 13 (MSB) */ - REG_WRITE(ah, 0xa3dc, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(7), POW_SM(pPwrArray[ALL_TARGET_HT40_13], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_12], 16) | POW_SM(pPwrArray[ALL_TARGET_HT40_7], 8) | @@ -4051,7 +4051,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 14 (LSB), 15, 20, 21 */ - REG_WRITE(ah, 0xa3ec, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(11), POW_SM(pPwrArray[ALL_TARGET_HT40_21], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_20], 16) | POW_SM(pPwrArray[ALL_TARGET_HT40_15], 8) | diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 4ceddbbdfcee..038a0cbfc6e7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -615,7 +615,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, */ if (rxsp->status11 & AR_CRCErr) rxs->rs_status |= ATH9K_RXERR_CRC; - if (rxsp->status11 & AR_PHYErr) { + else if (rxsp->status11 & AR_PHYErr) { phyerr = MS(rxsp->status11, AR_PHYErrCode); /* * If we reach a point here where AR_PostDelimCRCErr is @@ -638,11 +638,11 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_phyerr = phyerr; } - } - if (rxsp->status11 & AR_DecryptCRCErr) + } else if (rxsp->status11 & AR_DecryptCRCErr) rxs->rs_status |= ATH9K_RXERR_DECRYPT; - if (rxsp->status11 & AR_MichaelErr) + else if (rxsp->status11 & AR_MichaelErr) rxs->rs_status |= ATH9K_RXERR_MIC; + if (rxsp->status11 & AR_KeyMiss) rxs->rs_status |= ATH9K_RXERR_DECRYPT; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 59bab6bd8a74..8bdda2cf9dd7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -486,6 +486,8 @@ #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) +#define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) + #define AR_PHY_PWRTX_MAX (AR_SM_BASE + 0x1f0) #define AR_PHY_POWER_TX_SUB (AR_SM_BASE + 0x1f4) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3681caf54282..bd85e311c51b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -95,9 +95,9 @@ struct ath_config { * @BUF_XRETRY: To denote excessive retries of the buffer */ enum buffer_type { - BUF_AMPDU = BIT(2), - BUF_AGGR = BIT(3), - BUF_XRETRY = BIT(5), + BUF_AMPDU = BIT(0), + BUF_AGGR = BIT(1), + BUF_XRETRY = BIT(2), }; #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) @@ -137,7 +137,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ WME_AC_VO) -#define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ /* number of delimiters for encryption padding */ @@ -184,7 +183,8 @@ enum ATH_AGGR_STATUS { #define ATH_TXFIFO_DEPTH 8 struct ath_txq { - u32 axq_qnum; + int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ + u32 axq_qnum; /* ath9k hardware queue number */ u32 *axq_link; struct list_head axq_q; spinlock_t axq_lock; @@ -233,7 +233,6 @@ struct ath_buf { bool bf_stale; u16 bf_flags; struct ath_buf_state bf_state; - struct ath_wiphy *aphy; }; struct ath_atx_tid { @@ -254,7 +253,10 @@ struct ath_atx_tid { }; struct ath_node { - struct ath_common *common; +#ifdef CONFIG_ATH9K_DEBUGFS + struct list_head list; /* for sc->nodes */ + struct ieee80211_sta *sta; /* station struct we're part of */ +#endif struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; @@ -277,6 +279,11 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 +/** + * @txq_map: Index is mac80211 queue number. This is + * not necessarily the same as the hardware queue number + * (axq_qnum). + */ struct ath_tx { u16 seq_no; u32 txqsetup; @@ -303,6 +310,8 @@ struct ath_rx { struct ath_descdma rxdma; struct ath_buf *rx_bufptr; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; + + struct sk_buff *frag; }; int ath_startrecv(struct ath_softc *sc); @@ -342,7 +351,6 @@ struct ath_vif { __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ enum nl80211_iftype av_opmode; struct ath_buf *av_bcbuf; - struct ath_tx_control av_btxctl; u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ }; @@ -381,7 +389,6 @@ struct ath_beacon { u32 ast_be_xmit; u64 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; - struct ath_wiphy *bslot_aphy[ATH_BCBUF]; int slottime; int slotupdate; struct ath9k_tx_queue_info beacon_qi; @@ -392,7 +399,7 @@ struct ath_beacon { void ath_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); -int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); +int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); int ath_beaconq_config(struct ath_softc *sc); @@ -529,7 +536,6 @@ struct ath_ant_comb { #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 -#define IEEE80211_WEP_NKID 4 /* number of key ids */ #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_RATE_DUMMY_MARKER 0 @@ -557,27 +563,28 @@ struct ath_ant_comb { #define PS_WAIT_FOR_TX_ACK BIT(3) #define PS_BEACON_SYNC BIT(4) -struct ath_wiphy; struct ath_rate_table; +struct ath9k_vif_iter_data { + const u8 *hw_macaddr; /* phy's hardware address, set + * before starting iteration for + * valid bssid mask. + */ + u8 mask[ETH_ALEN]; /* bssid mask */ + int naps; /* number of AP vifs */ + int nmeshes; /* number of mesh vifs */ + int nstations; /* number of station vifs */ + int nwds; /* number of nwd vifs */ + int nadhocs; /* number of adhoc vifs */ + int nothers; /* number of vifs not specified above. */ +}; + struct ath_softc { struct ieee80211_hw *hw; struct device *dev; - spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ - struct ath_wiphy *pri_wiphy; - struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may - * have NULL entries */ - int num_sec_wiphy; /* number of sec_wiphy pointers in the array */ int chan_idx; int chan_is_ht; - struct ath_wiphy *next_wiphy; - struct work_struct chan_work; - int wiphy_select_failures; - unsigned long wiphy_select_first_fail; - 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]; @@ -599,10 +606,10 @@ struct ath_softc { u32 sc_flags; /* SC_OP_* */ u16 ps_flags; /* PS_* */ u16 curtxpow; - u8 nbcnvifs; - u16 nvifs; bool ps_enabled; bool ps_idle; + short nbcnvifs; + short nvifs; unsigned long ps_usecount; struct ath_config config; @@ -621,13 +628,20 @@ struct ath_softc { int led_on_cnt; int led_off_cnt; + struct ath9k_hw_cal_data caldata; + int last_rssi; + int beacon_interval; #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; + spinlock_t nodes_lock; + struct list_head nodes; /* basically, stations */ + unsigned int tx_complete_poll_work_seen; #endif struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; + struct delayed_work hw_pll_work; struct ath_btcoex btcoex; struct ath_descdma txsdma; @@ -637,23 +651,6 @@ struct ath_softc { struct pm_qos_request_list pm_qos_req; }; -struct ath_wiphy { - struct ath_softc *sc; /* shared for all virtual wiphys */ - struct ieee80211_hw *hw; - struct ath9k_hw_cal_data caldata; - enum ath_wiphy_state { - ATH_WIPHY_INACTIVE, - ATH_WIPHY_ACTIVE, - ATH_WIPHY_PAUSING, - ATH_WIPHY_PAUSED, - ATH_WIPHY_SCAN, - } state; - bool idle; - int chan_idx; - int chan_is_ht; - int last_rssi; -}; - void ath9k_tasklet(unsigned long data); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_cabq_update(struct ath_softc *); @@ -675,14 +672,13 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *ichan); int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan); void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); +bool ath9k_uses_beacons(int type); #ifdef CONFIG_PCI int ath_pci_init(void); @@ -706,26 +702,12 @@ void ath9k_ps_restore(struct ath_softc *sc); u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int ath9k_wiphy_add(struct ath_softc *sc); -int ath9k_wiphy_del(struct ath_wiphy *aphy); -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype); -int ath9k_wiphy_pause(struct ath_wiphy *aphy); -int ath9k_wiphy_unpause(struct ath_wiphy *aphy); -int ath9k_wiphy_select(struct ath_wiphy *aphy); -void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int); -void ath9k_wiphy_chan_work(struct work_struct *work); -bool ath9k_wiphy_started(struct ath_softc *sc); -void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, - struct ath_wiphy *selected); -bool ath9k_wiphy_scanning(struct ath_softc *sc); -void ath9k_wiphy_work(struct work_struct *work); -bool ath9k_all_wiphys_idle(struct ath_softc *sc); -void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle); - -void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); -bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); void ath_start_rfkill_poll(struct ath_softc *sc); extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); +void ath9k_calculate_iter_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ath9k_vif_iter_data *iter_data); + #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 385ba03134ba..87ba44c06692 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -112,8 +112,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; @@ -132,8 +131,7 @@ static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_buf *bf; struct ath_vif *avp; @@ -142,9 +140,6 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_tx_info *info; int cabq_depth; - if (aphy->state != ATH_WIPHY_ACTIVE) - return NULL; - avp = (void *)vif->drv_priv; cabq = sc->beacon.cabq; @@ -225,9 +220,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, return bf; } -int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) +int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp; struct ath_buf *bf; @@ -244,9 +238,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || - sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC || - sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { + if (ath9k_uses_beacons(vif->type)) { int slot; /* * Assign the vif to a beacon xmit slot. As @@ -263,7 +255,6 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) } BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); sc->beacon.bslot[avp->av_bslot] = vif; - sc->beacon.bslot_aphy[avp->av_bslot] = aphy; sc->nbcnvifs++; } } @@ -281,10 +272,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) /* NB: the beacon data buffer must be 32-bit aligned. */ skb = ieee80211_beacon_get(sc->hw, vif); - if (skb == NULL) { - ath_dbg(common, ATH_DBG_BEACON, "cannot get skb\n"); + if (skb == NULL) return -ENOMEM; - } tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; sc->beacon.bc_tstamp = le64_to_cpu(tstamp); @@ -336,7 +325,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) if (avp->av_bslot != -1) { sc->beacon.bslot[avp->av_bslot] = NULL; - sc->beacon.bslot_aphy[avp->av_bslot] = NULL; sc->nbcnvifs--; } @@ -362,7 +350,6 @@ void ath_beacon_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; - struct ath_wiphy *aphy; int slot; u32 bfaddr, bc = 0, tsftu; u64 tsf; @@ -420,7 +407,6 @@ void ath_beacon_tasklet(unsigned long data) */ slot = ATH_BCBUF - slot - 1; vif = sc->beacon.bslot[slot]; - aphy = sc->beacon.bslot_aphy[slot]; ath_dbg(common, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", @@ -428,7 +414,7 @@ void ath_beacon_tasklet(unsigned long data) bfaddr = 0; if (vif) { - bf = ath_beacon_generate(aphy->hw, vif); + bf = ath_beacon_generate(sc->hw, vif); if (bf != NULL) { bfaddr = bf->bf_daddr; bc = 1; @@ -720,10 +706,10 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) iftype = sc->sc_ah->opmode; } - cur_conf->listen_interval = 1; - cur_conf->dtim_count = 1; - cur_conf->bmiss_timeout = - ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; /* * It looks like mac80211 may end up using beacon interval of zero in diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index b68a1acbddd0..b4a92a4313f6 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -382,9 +382,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, s16 default_nf; int i, j; - if (!ah->caldata) - return; - + ah->caldata->channel = chan->channel; + ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT; h = ah->caldata->nfCalHist; default_nf = ath9k_hw_get_default_nf(ah, chan); for (i = 0; i < NUM_NF_READINGS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index a126bddebb0a..4c7020b3a5a0 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -23,8 +23,6 @@ /* Common header for Atheros 802.11n base driver cores */ -#define IEEE80211_WEP_NKID 4 - #define WME_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 3586c43077a7..9cdc41b0ec44 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -381,41 +381,21 @@ static const struct file_operations fops_interrupt = { .llseek = default_llseek, }; -static const char * ath_wiphy_state_str(enum ath_wiphy_state state) -{ - switch (state) { - case ATH_WIPHY_INACTIVE: - return "INACTIVE"; - case ATH_WIPHY_ACTIVE: - return "ACTIVE"; - case ATH_WIPHY_PAUSING: - return "PAUSING"; - case ATH_WIPHY_PAUSED: - return "PAUSED"; - case ATH_WIPHY_SCAN: - return "SCAN"; - } - return "?"; -} - static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_wiphy *aphy = sc->pri_wiphy; - struct ieee80211_channel *chan = aphy->hw->conf.channel; + struct ieee80211_channel *chan = sc->hw->conf.channel; char buf[512]; unsigned int len = 0; - int i; u8 addr[ETH_ALEN]; u32 tmp; len += snprintf(buf + len, sizeof(buf) - len, - "primary: %s (%s chan=%d ht=%d)\n", - wiphy_name(sc->pri_wiphy->hw->wiphy), - ath_wiphy_state_str(sc->pri_wiphy->state), + "%s (chan=%d ht=%d)\n", + wiphy_name(sc->hw->wiphy), ieee80211_frequency_to_channel(chan->center_freq), - aphy->chan_is_ht); + conf_is_ht(&sc->hw->conf)); put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); @@ -457,156 +437,82 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, else len += snprintf(buf + len, sizeof(buf) - len, "\n"); - /* Put variable-length stuff down here, and check for overflows. */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i]; - if (aphy_tmp == NULL) - continue; - chan = aphy_tmp->hw->conf.channel; - len += snprintf(buf + len, sizeof(buf) - len, - "secondary: %s (%s chan=%d ht=%d)\n", - wiphy_name(aphy_tmp->hw->wiphy), - ath_wiphy_state_str(aphy_tmp->state), - ieee80211_frequency_to_channel(chan->center_freq), - aphy_tmp->chan_is_ht); - } if (len > sizeof(buf)) len = sizeof(buf); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) -{ - int i; - if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) - return sc->pri_wiphy; - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) - return aphy; - } - return NULL; -} - -static int del_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_del(aphy); -} - -static int pause_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_pause(aphy); -} - -static int unpause_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_unpause(aphy); -} - -static int select_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_select(aphy); -} - -static int schedule_wiphy(struct ath_softc *sc, const char *msec) -{ - ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); - return 0; -} - -static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[50]; - size_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (strncmp(buf, "add", 3) == 0) { - int res = ath9k_wiphy_add(sc); - if (res < 0) - return res; - } else if (strncmp(buf, "del=", 4) == 0) { - int res = del_wiphy(sc, buf + 4); - if (res < 0) - return res; - } else if (strncmp(buf, "pause=", 6) == 0) { - int res = pause_wiphy(sc, buf + 6); - if (res < 0) - return res; - } else if (strncmp(buf, "unpause=", 8) == 0) { - int res = unpause_wiphy(sc, buf + 8); - if (res < 0) - return res; - } else if (strncmp(buf, "select=", 7) == 0) { - int res = select_wiphy(sc, buf + 7); - if (res < 0) - return res; - } else if (strncmp(buf, "schedule=", 9) == 0) { - int res = schedule_wiphy(sc, buf + 9); - if (res < 0) - return res; - } else - return -EOPNOTSUPP; - - return count; -} - static const struct file_operations fops_wiphy = { .read = read_file_wiphy, - .write = write_file_wiphy, .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; +#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum #define PR(str, elem) \ do { \ len += snprintf(buf + len, size - len, \ "%s%13u%11u%10u%10u\n", str, \ - sc->debug.stats.txstats[WME_AC_BE].elem, \ - sc->debug.stats.txstats[WME_AC_BK].elem, \ - sc->debug.stats.txstats[WME_AC_VI].elem, \ - sc->debug.stats.txstats[WME_AC_VO].elem); \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \ + if (len >= size) \ + goto done; \ } while(0) +#define PRX(str, elem) \ +do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + (unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \ + (unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \ + (unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \ + (unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \ + if (len >= size) \ + goto done; \ +} while(0) + +#define PRQLE(str, elem) \ +do { \ + len += snprintf(buf + len, size - len, \ + "%s%13i%11i%10i%10i\n", str, \ + list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \ + list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \ + list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \ + list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \ + if (len >= size) \ + goto done; \ +} while (0) + static ssize_t read_file_xmit(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 2048; + unsigned int len = 0, size = 8000; + int i; ssize_t retval = 0; + char tmp[32]; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); + len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x" + " poll-work-seen: %u\n" + "%30s %10s%10s%10s\n\n", + ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup, + sc->tx_complete_poll_work_seen, + "BE", "BK", "VI", "VO"); PR("MPDUs Queued: ", queued); PR("MPDUs Completed: ", completed); PR("Aggregates: ", a_aggr); - PR("AMPDUs Queued: ", a_queued); + PR("AMPDUs Queued HW:", a_queued_hw); + PR("AMPDUs Queued SW:", a_queued_sw); PR("AMPDUs Completed:", a_completed); PR("AMPDUs Retried: ", a_retries); PR("AMPDUs XRetried: ", a_xretries); @@ -618,6 +524,223 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("DELIM Underrun: ", delim_underrun); PR("TX-Pkts-All: ", tx_pkts_all); PR("TX-Bytes-All: ", tx_bytes_all); + PR("hw-put-tx-buf: ", puttxbuf); + PR("hw-tx-start: ", txstart); + PR("hw-tx-proc-desc: ", txprocdesc); + len += snprintf(buf + len, size - len, + "%s%11p%11p%10p%10p\n", "txq-memory-address:", + &(sc->tx.txq_map[WME_AC_BE]), + &(sc->tx.txq_map[WME_AC_BK]), + &(sc->tx.txq_map[WME_AC_VI]), + &(sc->tx.txq_map[WME_AC_VO])); + if (len >= size) + goto done; + + PRX("axq-qnum: ", axq_qnum); + PRX("axq-depth: ", axq_depth); + PRX("axq-ampdu_depth: ", axq_ampdu_depth); + PRX("axq-stopped ", stopped); + PRX("tx-in-progress ", axq_tx_inprogress); + PRX("pending-frames ", pending_frames); + PRX("txq_headidx: ", txq_headidx); + PRX("txq_tailidx: ", txq_headidx); + + PRQLE("axq_q empty: ", axq_q); + PRQLE("axq_acq empty: ", axq_acq); + PRQLE("txq_fifo_pending: ", txq_fifo_pending); + for (i = 0; i < ATH_TXFIFO_DEPTH; i++) { + snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); + PRQLE(tmp, txq_fifo[i]); + } + + /* Print out more detailed queue-info */ + for (i = 0; i <= WME_AC_BK; i++) { + struct ath_txq *txq = &(sc->tx.txq[i]); + struct ath_atx_ac *ac; + struct ath_atx_tid *tid; + if (len >= size) + goto done; + spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->axq_acq)) { + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, + list); + len += snprintf(buf + len, size - len, + "txq[%i] first-ac: %p sched: %i\n", + i, ac, ac->sched); + if (list_empty(&ac->tid_q) || (len >= size)) + goto done_for; + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, + list); + len += snprintf(buf + len, size - len, + " first-tid: %p sched: %i paused: %i\n", + tid, tid->sched, tid->paused); + } + done_for: + spin_unlock_bh(&txq->axq_lock); + } + +done: + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t read_file_stations(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char *buf; + unsigned int len = 0, size = 64000; + struct ath_node *an = NULL; + ssize_t retval = 0; + int q; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "Stations:\n" + " tid: addr sched paused buf_q-empty an ac\n" + " ac: addr sched tid_q-empty txq\n"); + + spin_lock(&sc->nodes_lock); + list_for_each_entry(an, &sc->nodes, list) { + len += snprintf(buf + len, size - len, + "%pM\n", an->sta->addr); + if (len >= size) + goto done; + + for (q = 0; q < WME_NUM_TID; q++) { + struct ath_atx_tid *tid = &(an->tid[q]); + len += snprintf(buf + len, size - len, + " tid: %p %s %s %i %p %p\n", + tid, tid->sched ? "sched" : "idle", + tid->paused ? "paused" : "running", + list_empty(&tid->buf_q), + tid->an, tid->ac); + if (len >= size) + goto done; + } + + for (q = 0; q < WME_NUM_AC; q++) { + struct ath_atx_ac *ac = &(an->ac[q]); + len += snprintf(buf + len, size - len, + " ac: %p %s %i %p\n", + ac, ac->sched ? "sched" : "idle", + list_empty(&ac->tid_q), ac->txq); + if (len >= size) + goto done; + } + } + +done: + spin_unlock(&sc->nodes_lock); + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t read_file_misc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_hw *hw = sc->hw; + char *buf; + unsigned int len = 0, size = 8000; + ssize_t retval = 0; + const char *tmp; + unsigned int reg; + struct ath9k_vif_iter_data iter_data; + + ath9k_calculate_iter_data(hw, NULL, &iter_data); + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_ADHOC: + tmp = "ADHOC"; + break; + case NL80211_IFTYPE_MESH_POINT: + tmp = "MESH"; + break; + case NL80211_IFTYPE_AP: + tmp = "AP"; + break; + case NL80211_IFTYPE_STATION: + tmp = "STATION"; + break; + default: + tmp = "???"; + break; + } + + len += snprintf(buf + len, size - len, + "curbssid: %pM\n" + "OP-Mode: %s(%i)\n" + "Beacon-Timer-Register: 0x%x\n", + common->curbssid, + tmp, (int)(sc->sc_ah->opmode), + REG_READ(ah, AR_BEACON_PERIOD)); + + reg = REG_READ(ah, AR_TIMER_MODE); + len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (", + reg); + if (reg & AR_TBTT_TIMER_EN) + len += snprintf(buf + len, size - len, "TBTT "); + if (reg & AR_DBA_TIMER_EN) + len += snprintf(buf + len, size - len, "DBA "); + if (reg & AR_SWBA_TIMER_EN) + len += snprintf(buf + len, size - len, "SWBA "); + if (reg & AR_HCF_TIMER_EN) + len += snprintf(buf + len, size - len, "HCF "); + if (reg & AR_TIM_TIMER_EN) + len += snprintf(buf + len, size - len, "TIM "); + if (reg & AR_DTIM_TIMER_EN) + len += snprintf(buf + len, size - len, "DTIM "); + len += snprintf(buf + len, size - len, ")\n"); + + reg = sc->sc_ah->imask; + len += snprintf(buf + len, size - len, "imask: 0x%x (", reg); + if (reg & ATH9K_INT_SWBA) + len += snprintf(buf + len, size - len, "SWBA "); + if (reg & ATH9K_INT_BMISS) + len += snprintf(buf + len, size - len, "BMISS "); + if (reg & ATH9K_INT_CST) + len += snprintf(buf + len, size - len, "CST "); + if (reg & ATH9K_INT_RX) + len += snprintf(buf + len, size - len, "RX "); + if (reg & ATH9K_INT_RXHP) + len += snprintf(buf + len, size - len, "RXHP "); + if (reg & ATH9K_INT_RXLP) + len += snprintf(buf + len, size - len, "RXLP "); + if (reg & ATH9K_INT_BB_WATCHDOG) + len += snprintf(buf + len, size - len, "BB_WATCHDOG "); + /* there are other IRQs if one wanted to add them. */ + len += snprintf(buf + len, size - len, ")\n"); + + len += snprintf(buf + len, size - len, + "VIF Counts: AP: %i STA: %i MESH: %i WDS: %i" + " ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n", + iter_data.naps, iter_data.nstations, iter_data.nmeshes, + iter_data.nwds, iter_data.nadhocs, iter_data.nothers, + sc->nvifs, sc->nbcnvifs); + + len += snprintf(buf + len, size - len, + "Calculated-BSSID-Mask: %pM\n", + iter_data.mask); if (len > size) len = size; @@ -629,9 +752,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, } void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts) + struct ath_tx_status *ts, struct ath_txq *txq) { - int qnum = skb_get_queue_mapping(bf->bf_mpdu); + int qnum = txq->axq_qnum; TX_STAT_INC(qnum, tx_pkts_all); sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; @@ -666,6 +789,20 @@ static const struct file_operations fops_xmit = { .llseek = default_llseek, }; +static const struct file_operations fops_stations = { + .read = read_file_stations, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_misc = { + .read = read_file_misc, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t read_file_recv(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -903,6 +1040,14 @@ int ath9k_init_debug(struct ath_hw *ah) sc, &fops_xmit)) goto err; + if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_stations)) + goto err; + + if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_misc)) + goto err; + if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_recv)) goto err; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 1e5078bd0344..59338de0ce19 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -89,7 +89,8 @@ struct ath_interrupt_stats { * @queued: Total MPDUs (non-aggr) queued * @completed: Total MPDUs (non-aggr) completed * @a_aggr: Total no. of aggregates queued - * @a_queued: Total AMPDUs queued + * @a_queued_hw: Total AMPDUs queued to hardware + * @a_queued_sw: Total AMPDUs queued to software queues * @a_completed: Total AMPDUs completed * @a_retries: No. of AMPDUs retried (SW) * @a_xretries: No. of AMPDUs dropped due to xretries @@ -102,6 +103,9 @@ struct ath_interrupt_stats { * @desc_cfg_err: Descriptor configuration errors * @data_urn: TX data underrun errors * @delim_urn: TX delimiter underrun errors + * @puttxbuf: Number of times hardware was given txbuf to write. + * @txstart: Number of times hardware was told to start tx. + * @txprocdesc: Number of times tx descriptor was processed */ struct ath_tx_stats { u32 tx_pkts_all; @@ -109,7 +113,8 @@ struct ath_tx_stats { u32 queued; u32 completed; u32 a_aggr; - u32 a_queued; + u32 a_queued_hw; + u32 a_queued_sw; u32 a_completed; u32 a_retries; u32 a_xretries; @@ -119,6 +124,9 @@ struct ath_tx_stats { u32 desc_cfg_err; u32 data_underrun; u32 delim_underrun; + u32 puttxbuf; + u32 txstart; + u32 txprocdesc; }; /** @@ -167,7 +175,7 @@ int ath9k_init_debug(struct ath_hw *ah); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts); + struct ath_tx_status *ts, struct ath_txq *txq); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); #else @@ -184,7 +192,8 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc, static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts) + struct ath_tx_status *ts, + struct ath_txq *txq) { } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index d05163159572..8c18bed3a558 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -89,6 +89,38 @@ bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, return false; } +void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, + int eep_start_loc, int size) +{ + int i = 0, j, addr; + u32 addrdata[8]; + u32 data[8]; + + for (addr = 0; addr < size; addr++) { + addrdata[i] = AR5416_EEPROM_OFFSET + + ((addr + eep_start_loc) << AR5416_EEPROM_S); + i++; + if (i == 8) { + REG_READ_MULTI(ah, addrdata, data, i); + + for (j = 0; j < i; j++) { + *eep_data = data[j]; + eep_data++; + } + i = 0; + } + } + + if (i != 0) { + REG_READ_MULTI(ah, addrdata, data, i); + + for (j = 0; j < i; j++) { + *eep_data = data[j]; + eep_data++; + } + } +} + bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) { return common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 58e2ddc927a9..bd82447f5b78 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -665,6 +665,8 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, u16 *indexL, u16 *indexR); bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data); +void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, + int eep_start_loc, int size); void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index fbdff7e47952..bc77a308c901 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -27,19 +27,13 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); } -static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) -{ #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + +static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.map4k; - int addr, eep_start_loc = 0; - - eep_start_loc = 64; - - if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } + int addr, eep_start_loc = 64; for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { @@ -51,9 +45,34 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) } return true; -#undef SIZE_EEPROM_4K } +static bool __ath9k_hw_usb_4k_fill_eeprom(struct ath_hw *ah) +{ + u16 *eep_data = (u16 *)&ah->eeprom.map4k; + + ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, 64, SIZE_EEPROM_4K); + + return true; +} + +static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_use_flash(ah)) { + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + if (common->bus_ops->ath_bus_type == ATH_USB) + return __ath9k_hw_usb_4k_fill_eeprom(ah); + else + return __ath9k_hw_4k_fill_eeprom(ah); +} + +#undef SIZE_EEPROM_4K + static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) { #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 9b6bc8a953bc..8cd8333cc086 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -17,7 +17,7 @@ #include "hw.h" #include "ar9002_phy.h" -#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16)) +#define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16)) static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah) { @@ -29,25 +29,15 @@ static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah) return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; } -static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) +static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data; - int addr, eep_start_loc; + int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; - if (common->bus_ops->ath_bus_type == ATH_USB) - eep_start_loc = AR9287_HTC_EEP_START_LOC; - else - eep_start_loc = AR9287_EEP_START_LOC; - - if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < NUM_EEP_WORDS; addr++) { + for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_dbg(common, ATH_DBG_EEPROM, @@ -60,6 +50,31 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) return true; } +static bool __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah) +{ + u16 *eep_data = (u16 *)&ah->eeprom.map9287; + + ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, + AR9287_HTC_EEP_START_LOC, + SIZE_EEPROM_AR9287); + return true; +} + +static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_use_flash(ah)) { + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + if (common->bus_ops->ath_bus_type == ATH_USB) + return __ath9k_hw_usb_ar9287_fill_eeprom(ah); + else + return __ath9k_hw_ar9287_fill_eeprom(ah); +} + static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) { u32 sum = 0, el, integer; @@ -86,7 +101,7 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) need_swap = true; eepdata = (u16 *)(&ah->eeprom); - for (addr = 0; addr < NUM_EEP_WORDS; addr++) { + for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { temp = swab16(*eepdata); *eepdata = temp; eepdata++; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 749a93608664..fccd87df7300 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -86,9 +86,10 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); } -static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) -{ #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + +static bool __ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.def; int addr, ar5416_eep_start_loc = 0x100; @@ -103,9 +104,34 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) eep_data++; } return true; -#undef SIZE_EEPROM_DEF } +static bool __ath9k_hw_usb_def_fill_eeprom(struct ath_hw *ah) +{ + u16 *eep_data = (u16 *)&ah->eeprom.def; + + ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, + 0x100, SIZE_EEPROM_DEF); + return true; +} + +static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_use_flash(ah)) { + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + if (common->bus_ops->ath_bus_type == ATH_USB) + return __ath9k_hw_usb_def_fill_eeprom(ah); + else + return __ath9k_hw_def_fill_eeprom(ah); +} + +#undef SIZE_EEPROM_DEF + static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = @@ -221,9 +247,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } /* Enable fixup for AR_AN_TOP2 if necessary */ - if (AR_SREV_9280_20_OR_LATER(ah) && - (eep->baseEepHeader.version & 0xff) > 0x0a && - eep->baseEepHeader.pwdclkind == 0) + if ((ah->hw_version.devid == AR9280_DEVID_PCI) && + ((eep->baseEepHeader.version & 0xff) > 0x0a) && + (eep->baseEepHeader.pwdclkind == 0)) ah->need_an_top2_fixup = 1; if ((common->bus_ops->ath_bus_type == ATH_USB) && diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 133764069246..fb4f17a5183d 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -201,8 +201,7 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; bool blocked = !!ath_is_rfkill_set(sc); wiphy_rfkill_set_hw_state(hw->wiphy, blocked); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 780ac5eac501..63549868e686 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -366,7 +366,7 @@ struct ath9k_htc_priv { u16 seq_no; u32 bmiss_cnt; - struct ath9k_hw_cal_data caldata[ATH9K_NUM_CHANNELS]; + struct ath9k_hw_cal_data caldata; spinlock_t beacon_lock; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 0352f0994caa..a7bc26d1bd66 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -294,6 +294,34 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) return be32_to_cpu(val); } +static void ath9k_multi_regread(void *hw_priv, u32 *addr, + u32 *val, u16 count) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + __be32 tmpaddr[8]; + __be32 tmpval[8]; + int i, ret; + + for (i = 0; i < count; i++) { + tmpaddr[i] = cpu_to_be32(addr[i]); + } + + ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, + (u8 *)tmpaddr , sizeof(u32) * count, + (u8 *)tmpval, sizeof(u32) * count, + 100); + if (unlikely(ret)) { + ath_dbg(common, ATH_DBG_WMI, + "Multiple REGISTER READ FAILED (count: %d)\n", count); + } + + for (i = 0; i < count; i++) { + val[i] = be32_to_cpu(tmpval[i]); + } +} + static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -404,6 +432,7 @@ static void ath9k_regwrite_flush(void *hw_priv) static const struct ath_ops ath9k_common_ops = { .read = ath9k_regread, + .multi_read = ath9k_multi_regread, .write = ath9k_regwrite, .enable_write_buffer = ath9k_enable_regwrite_buffer, .write_flush = ath9k_regwrite_flush, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6bb59958f71e..a702089f18d0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -121,7 +121,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = priv->hw->conf.channel; - struct ath9k_hw_cal_data *caldata; + struct ath9k_hw_cal_data *caldata = NULL; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; @@ -139,7 +139,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); - caldata = &priv->caldata[channel->hw_value]; + caldata = &priv->caldata; ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); if (ret) { ath_err(common, @@ -202,7 +202,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), fastcc); - caldata = &priv->caldata[channel->hw_value]; + if (!fastcc) + caldata = &priv->caldata; ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, @@ -1557,7 +1558,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + u16 tid, u16 *ssn, u8 buf_size) { struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_sta *ista; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9f01e50d5cda..f9cf81551817 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -495,6 +495,17 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (ah->hw_version.devid == AR5416_AR9100_DEVID) ah->hw_version.macVersion = AR_SREV_VERSION_9100; + ath9k_hw_read_revisions(ah); + + /* + * Read back AR_WA into a permanent copy and set bits 14 and 17. + * We need to do this to avoid RMW of this register. We cannot + * read the reg when chip is asleep. + */ + ah->WARegVal = REG_READ(ah, AR_WA); + ah->WARegVal |= (AR_WA_D3_L1_DISABLE | + AR_WA_ASPM_TIMER_BASED_DISABLE); + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { ath_err(common, "Couldn't reset chip\n"); return -EIO; @@ -563,14 +574,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_mode_regs(ah); - /* - * Read back AR_WA into a permanent copy and set bits 14 and 17. - * We need to do this to avoid RMW of this register. We cannot - * read the reg when chip is asleep. - */ - ah->WARegVal = REG_READ(ah, AR_WA); - ah->WARegVal |= (AR_WA_D3_L1_DISABLE | - AR_WA_ASPM_TIMER_BASED_DISABLE); if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, 0, 0); @@ -668,14 +671,51 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REGWRITE_BUFFER_FLUSH(ah); } +unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) +{ + REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); + udelay(100); + REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); + + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) + udelay(100); + + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; +} +EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); + +#define DPLL2_KD_VAL 0x3D +#define DPLL2_KI_VAL 0x06 +#define DPLL3_PHASE_SHIFT_VAL 0x1 + static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { u32 pll; - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah)) { + REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); + REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01); + + REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, + AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + + REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); + udelay(100); + REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KD, DPLL2_KD_VAL); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KI, DPLL2_KI_VAL); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, + AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); + udelay(110); + } + pll = ath9k_hw_compute_pll_control(ah, chan); REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); @@ -1082,8 +1122,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) return false; } - ath9k_hw_read_revisions(ah); - return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); } @@ -1348,8 +1386,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); - ath9k_hw_set_operating_mode(ah, ah->opmode); - ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); @@ -1367,6 +1403,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); + ath9k_hw_set_operating_mode(ah, ah->opmode); + r = ath9k_hw_rf_set_freq(ah, chan); if (r) return r; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ea9fde670646..ef79f4c876ca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -70,6 +70,9 @@ #define REG_READ(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +#define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ + ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) + #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ @@ -926,6 +929,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); void ath9k_hw_init_global_settings(struct ath_hw *ah); +unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 087a6a95edd5..e5c1eead98a2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -254,8 +254,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); return ath_reg_notifier_apply(wiphy, request, reg); @@ -442,9 +441,10 @@ static int ath9k_init_queues(struct ath_softc *sc) sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - for (i = 0; i < WME_NUM_AC; i++) + for (i = 0; i < WME_NUM_AC; i++) { sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); - + sc->tx.txq_map[i]->mac80211_qnum = i; + } return 0; } @@ -516,10 +516,8 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->beacon.slottime = ATH9K_SLOT_TIME_9; - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; @@ -537,6 +535,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (!ah) return -ENOMEM; + ah->hw = sc->hw; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; @@ -554,10 +553,13 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, common->btcoex_enabled = ath9k_btcoex_enable == 1; spin_lock_init(&common->cc_lock); - spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); +#ifdef CONFIG_ATH9K_DEBUGFS + spin_lock_init(&sc->nodes_lock); + INIT_LIST_HEAD(&sc->nodes); +#endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, (unsigned long)sc); @@ -699,7 +701,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; - struct ath_wiphy *aphy = hw->priv; struct ath_common *common; struct ath_hw *ah; int error = 0; @@ -754,10 +755,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); - INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(500); - aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); ath_start_rfkill_poll(sc); @@ -812,7 +810,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc) void ath9k_deinit_device(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; - int i = 0; ath9k_ps_wakeup(sc); @@ -821,21 +818,11 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - sc->sec_wiphy[i] = NULL; - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - } - ieee80211_unregister_hw(hw); pm_qos_remove_request(&sc->pm_qos_req); ath_rx_cleanup(sc); ath_tx_cleanup(sc); ath9k_deinit_softc(sc); - kfree(sc->sec_wiphy); } void ath_descdma_cleanup(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 180170d3ce25..c75d40fb86f1 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -690,17 +690,23 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { + /* + * Treat these errors as mutually exclusive to avoid spurious + * extra error reports from the hardware. If a CRC error is + * reported, then decryption and MIC errors are irrelevant, + * the frame is going to be dropped either way + */ if (ads.ds_rxstatus8 & AR_CRCErr) rs->rs_status |= ATH9K_RXERR_CRC; - if (ads.ds_rxstatus8 & AR_PHYErr) { + else if (ads.ds_rxstatus8 & AR_PHYErr) { rs->rs_status |= ATH9K_RXERR_PHY; phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); rs->rs_phyerr = phyerr; - } - if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; - if (ads.ds_rxstatus8 & AR_MichaelErr) + else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; + if (ads.ds_rxstatus8 & AR_KeyMiss) rs->rs_status |= ATH9K_RXERR_DECRYPT; } diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7512f97e8f49..04d58ae923bb 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -639,6 +639,8 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PHYERR = 0x00000100, ATH9K_RX_FILTER_MYBEACON = 0x00000200, ATH9K_RX_FILTER_COMP_BAR = 0x00000400, + ATH9K_RX_FILTER_COMP_BA = 0x00000800, + ATH9K_RX_FILTER_UNCOMP_BA_BAR = 0x00001000, ATH9K_RX_FILTER_PSPOLL = 0x00004000, ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 568f7be2ec75..20c70ba45753 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -73,7 +73,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, chan_idx = curchan->hw_value; channel = &sc->sc_ah->channels[chan_idx]; - ath9k_update_ichannel(sc, hw, channel); + ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type); return channel; } @@ -215,7 +215,6 @@ static void ath_update_survey_stats(struct ath_softc *sc) int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { - struct ath_wiphy *aphy = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; @@ -231,6 +230,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->hw_pll_work); ath9k_ps_wakeup(sc); @@ -251,6 +251,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!ath_stoprecv(sc)) stopped = false; + if (!ath9k_hw_check_alive(ah)) + stopped = false; + /* XXX: do not flush receive queue here. We don't want * to flush data frames already in queue because of * changing channel. */ @@ -259,7 +262,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, fastcc = false; if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) - caldata = &aphy->caldata; + caldata = &sc->caldata; ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n", @@ -288,10 +291,13 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); ath_start_ani(common); } ps_restore: + ieee80211_wake_queues(hw); + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); @@ -545,6 +551,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) struct ath_hw *ah = sc->sc_ah; an = (struct ath_node *)sta->drv_priv; +#ifdef CONFIG_ATH9K_DEBUGFS + spin_lock(&sc->nodes_lock); + list_add(&an->list, &sc->nodes); + spin_unlock(&sc->nodes_lock); + an->sta = sta; +#endif if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM) sc->sc_flags |= SC_OP_ENABLE_APM; @@ -560,6 +572,13 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; +#ifdef CONFIG_ATH9K_DEBUGFS + spin_lock(&sc->nodes_lock); + list_del(&an->list); + spin_unlock(&sc->nodes_lock); + an->sta = NULL; +#endif + if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_node_cleanup(sc, an); } @@ -600,7 +619,15 @@ void ath9k_tasklet(unsigned long data) ath9k_ps_wakeup(sc); spin_lock(&sc->sc_pcu_lock); - if (!ath9k_hw_check_alive(ah)) + /* + * Only run the baseband hang check if beacons stop working in AP or + * IBSS mode, because it has a high false positive rate. For station + * mode it should not be necessary, since the upper layers will detect + * this through a beacon miss automatically and the following channel + * change will trigger a hardware reset anyway + */ + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && + !ath9k_hw_check_alive(ah)) ieee80211_queue_work(sc->hw, &sc->hw_check_work); if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) @@ -779,54 +806,11 @@ chip_reset: #undef SCHED_INTR } -static u32 ath_get_extchanmode(struct ath_softc *sc, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - u32 chanmode = 0; - - switch (chan->band) { - case IEEE80211_BAND_2GHZ: - switch(channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_G_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_G_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_G_HT40MINUS; - break; - } - break; - case IEEE80211_BAND_5GHZ: - switch(channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_A_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_A_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_A_HT40MINUS; - break; - } - break; - default: - break; - } - - return chanmode; -} - static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { - struct ath_wiphy *aphy = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -850,7 +834,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_beacon_config(sc, vif); /* Reset rssi stats */ - aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_flags |= SC_OP_ANI_RUN; @@ -1017,38 +1001,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } -/* XXX: Remove me once we don't depend on ath9k_channel for all - * this redundant data */ -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *ichan) -{ - struct ieee80211_channel *chan = hw->conf.channel; - struct ieee80211_conf *conf = &hw->conf; - - ichan->channel = chan->center_freq; - ichan->chan = chan; - - if (chan->band == IEEE80211_BAND_2GHZ) { - ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; - } else { - ichan->chanmode = CHANNEL_A; - ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; - } - - if (conf_is_ht(conf)) - ichan->chanmode = ath_get_extchanmode(sc, chan, - conf->channel_type); -} - /**********************/ /* mac80211 callbacks */ /**********************/ static int ath9k_start(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *curchan = hw->conf.channel; @@ -1061,29 +1020,7 @@ static int ath9k_start(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); - if (ath9k_wiphy_started(sc)) { - if (sc->chan_idx == curchan->hw_value) { - /* - * Already on the operational channel, the new wiphy - * can be marked active. - */ - aphy->state = ATH_WIPHY_ACTIVE; - ieee80211_wake_queues(hw); - } else { - /* - * Another wiphy is on another channel, start the new - * wiphy in paused state. - */ - aphy->state = ATH_WIPHY_PAUSED; - ieee80211_stop_queues(hw); - } - mutex_unlock(&sc->mutex); - return 0; - } - aphy->state = ATH_WIPHY_ACTIVE; - /* setup initial channel */ - sc->chan_idx = curchan->hw_value; init_channel = ath_get_curchannel(sc, hw); @@ -1187,19 +1124,11 @@ mutex_unlock: static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { - ath_dbg(common, ATH_DBG_XMIT, - "ath9k: %s: TX in unexpected wiphy state %d\n", - wiphy_name(hw->wiphy), aphy->state); - goto exit; - } - if (sc->ps_enabled) { /* * mac80211 does not set PM field for normal data frames, so we @@ -1258,44 +1187,26 @@ exit: static void ath9k_stop(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - int i; mutex_lock(&sc->mutex); - aphy->state = ATH_WIPHY_INACTIVE; - if (led_blink) cancel_delayed_work_sync(&sc->ath_led_blink_work); cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->hw_pll_work); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i]) - break; - } - - if (i == sc->num_sec_wiphy) { - cancel_delayed_work_sync(&sc->wiphy_work); - cancel_work_sync(&sc->chan_work); - } - if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } - if (ath9k_wiphy_started(sc)) { - mutex_unlock(&sc->mutex); - return; /* another wiphy still in use */ - } - /* Ensure HW is awake when we try to shut it down. */ ath9k_ps_wakeup(sc); @@ -1321,6 +1232,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) } else sc->rx.rxlink = NULL; + if (sc->rx.frag) { + dev_kfree_skb_any(sc->rx.frag); + sc->rx.frag = NULL; + } + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); @@ -1336,7 +1252,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_ps_restore(sc); sc->ps_idle = true; - ath9k_set_wiphy_idle(aphy, true); ath_radio_disable(sc, hw); sc->sc_flags |= SC_OP_INVALID; @@ -1348,112 +1263,238 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n"); } -static int ath9k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +bool ath9k_uses_beacons(int type) +{ + switch (type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + return true; + default: + return false; + } +} + +static void ath9k_reclaim_beacon(struct ath_softc *sc, + struct ieee80211_vif *vif) { - 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(ah); struct ath_vif *avp = (void *)vif->drv_priv; - enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; - int ret = 0; - mutex_lock(&sc->mutex); + /* Disable SWBA interrupt */ + sc->sc_ah->imask &= ~ATH9K_INT_SWBA; + ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + tasklet_kill(&sc->bcon_tasklet); + ath9k_ps_restore(sc); + + ath_beacon_return(sc, avp); + sc->sc_flags &= ~SC_OP_BEACONS; + + if (sc->nbcnvifs > 0) { + /* Re-enable beaconing */ + sc->sc_ah->imask |= ATH9K_INT_SWBA; + ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); + ath9k_ps_restore(sc); + } +} + +static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath9k_vif_iter_data *iter_data = data; + int i; + + if (iter_data->hw_macaddr) + for (i = 0; i < ETH_ALEN; i++) + iter_data->mask[i] &= + ~(iter_data->hw_macaddr[i] ^ mac[i]); switch (vif->type) { - case NL80211_IFTYPE_STATION: - ic_opmode = NL80211_IFTYPE_STATION; + case NL80211_IFTYPE_AP: + iter_data->naps++; break; - case NL80211_IFTYPE_WDS: - ic_opmode = NL80211_IFTYPE_WDS; + case NL80211_IFTYPE_STATION: + iter_data->nstations++; break; case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: + iter_data->nadhocs++; + break; case NL80211_IFTYPE_MESH_POINT: - if (sc->nbcnvifs >= ATH_BCBUF) { - ret = -ENOBUFS; - goto out; - } - ic_opmode = vif->type; + iter_data->nmeshes++; + break; + case NL80211_IFTYPE_WDS: + iter_data->nwds++; break; default: - ath_err(common, "Interface type %d not yet supported\n", - vif->type); - ret = -EOPNOTSUPP; - goto out; + iter_data->nothers++; + break; } +} - ath_dbg(common, ATH_DBG_CONFIG, - "Attach a VIF of type: %d\n", ic_opmode); +/* Called with sc->mutex held. */ +void ath9k_calculate_iter_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ath9k_vif_iter_data *iter_data) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); - /* Set the VIF opmode */ - avp->av_opmode = ic_opmode; - avp->av_bslot = -1; + /* + * Use the hardware MAC address as reference, the hardware uses it + * together with the BSSID mask when matching addresses. + */ + memset(iter_data, 0, sizeof(*iter_data)); + iter_data->hw_macaddr = common->macaddr; + memset(&iter_data->mask, 0xff, ETH_ALEN); - sc->nvifs++; + if (vif) + ath9k_vif_iter(iter_data, vif->addr, vif); + + /* Get list of all active MAC addresses */ + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, + iter_data); +} + +/* Called with sc->mutex held. */ +static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_vif_iter_data iter_data; - ath9k_set_bssid_mask(hw, vif); + ath9k_calculate_iter_data(hw, vif, &iter_data); - if (sc->nvifs > 1) - goto out; /* skip global settings for secondary vif */ + /* Set BSSID mask. */ + memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); + ath_hw_setbssidmask(common); - if (ic_opmode == NL80211_IFTYPE_AP) { + /* Set op-mode & TSF */ + if (iter_data.naps > 0) { ath9k_hw_set_tsfadjust(ah, 1); sc->sc_flags |= SC_OP_TSF_RESET; - } + ah->opmode = NL80211_IFTYPE_AP; + } else { + ath9k_hw_set_tsfadjust(ah, 0); + sc->sc_flags &= ~SC_OP_TSF_RESET; - /* Set the device opmode */ - ah->opmode = ic_opmode; + if (iter_data.nwds + iter_data.nmeshes) + ah->opmode = NL80211_IFTYPE_AP; + else if (iter_data.nadhocs) + ah->opmode = NL80211_IFTYPE_ADHOC; + else + ah->opmode = NL80211_IFTYPE_STATION; + } /* * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. */ - if ((vif->type == NL80211_IFTYPE_STATION) || - (vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) { if (ah->config.enable_ani) ah->imask |= ATH9K_INT_MIB; ah->imask |= ATH9K_INT_TSFOOR; + } else { + ah->imask &= ~ATH9K_INT_MIB; + ah->imask &= ~ATH9K_INT_TSFOOR; } ath9k_hw_set_interrupts(ah, ah->imask); - if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC) { + /* Set up ANI */ + if ((iter_data.naps + iter_data.nadhocs) > 0) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); + } else { + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); } +} -out: - mutex_unlock(&sc->mutex); - return ret; +/* Called with sc->mutex held, vif counts set up properly. */ +static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + + ath9k_calculate_summary_state(hw, vif); + + if (ath9k_uses_beacons(vif->type)) { + int error; + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + /* This may fail because upper levels do not have beacons + * properly configured yet. That's OK, we assume it + * will be properly configured and then we will be notified + * in the info_changed method and set up beacons properly + * there. + */ + error = ath_beacon_alloc(sc, vif); + if (error) + ath9k_reclaim_beacon(sc, vif); + else + ath_beacon_config(sc, vif); + } } -static void ath9k_reclaim_beacon(struct ath_softc *sc, - struct ieee80211_vif *vif) + +static int ath9k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; + int ret = 0; - /* Disable SWBA interrupt */ - sc->sc_ah->imask &= ~ATH9K_INT_SWBA; - ath9k_ps_wakeup(sc); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - tasklet_kill(&sc->bcon_tasklet); - ath9k_ps_restore(sc); + mutex_lock(&sc->mutex); - ath_beacon_return(sc, avp); - sc->sc_flags &= ~SC_OP_BEACONS; + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + break; + default: + ath_err(common, "Interface type %d not yet supported\n", + vif->type); + ret = -EOPNOTSUPP; + goto out; + } - if (sc->nbcnvifs > 0) { - /* Re-enable beaconing */ - sc->sc_ah->imask |= ATH9K_INT_SWBA; - ath9k_ps_wakeup(sc); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); - ath9k_ps_restore(sc); + if (ath9k_uses_beacons(vif->type)) { + if (sc->nbcnvifs >= ATH_BCBUF) { + ath_err(common, "Not enough beacon buffers when adding" + " new interface of type: %i\n", + vif->type); + ret = -ENOBUFS; + goto out; + } + } + + if ((vif->type == NL80211_IFTYPE_ADHOC) && + sc->nvifs > 0) { + ath_err(common, "Cannot create ADHOC interface when other" + " interfaces already exist.\n"); + ret = -EINVAL; + goto out; } + + ath_dbg(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d\n", vif->type); + + /* Set the VIF opmode */ + avp->av_opmode = vif->type; + avp->av_bslot = -1; + + sc->nvifs++; + + ath9k_do_vif_add_setup(hw, vif); +out: + mutex_unlock(&sc->mutex); + return ret; } static int ath9k_change_interface(struct ieee80211_hw *hw, @@ -1461,40 +1502,40 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, enum nl80211_iftype new_type, bool p2p) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); - switch (new_type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: + /* See if new interface type is valid. */ + if ((new_type == NL80211_IFTYPE_ADHOC) && + (sc->nvifs > 1)) { + ath_err(common, "When using ADHOC, it must be the only" + " interface.\n"); + ret = -EINVAL; + goto out; + } + + if (ath9k_uses_beacons(new_type) && + !ath9k_uses_beacons(vif->type)) { if (sc->nbcnvifs >= ATH_BCBUF) { ath_err(common, "No beacon slot available\n"); ret = -ENOBUFS; goto out; } - break; - case NL80211_IFTYPE_STATION: - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); - if ((vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_ADHOC)) - ath9k_reclaim_beacon(sc, vif); - break; - default: - ath_err(common, "Interface type %d not yet supported\n", - vif->type); - ret = -ENOTSUPP; - goto out; } + + /* Clean up old vif stuff */ + if (ath9k_uses_beacons(vif->type)) + ath9k_reclaim_beacon(sc, vif); + + /* Add new settings */ vif->type = new_type; vif->p2p = p2p; + ath9k_do_vif_add_setup(hw, vif); out: mutex_unlock(&sc->mutex); return ret; @@ -1503,25 +1544,20 @@ out: static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); mutex_lock(&sc->mutex); - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); + sc->nvifs--; /* Reclaim beacon resources */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || - (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) + if (ath9k_uses_beacons(vif->type)) ath9k_reclaim_beacon(sc, vif); - sc->nvifs--; + ath9k_calculate_summary_state(hw, NULL); mutex_unlock(&sc->mutex); } @@ -1562,12 +1598,11 @@ static void ath9k_disable_ps(struct ath_softc *sc) static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; - bool disable_radio; + bool disable_radio = false; mutex_lock(&sc->mutex); @@ -1578,29 +1613,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) * the end. */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { - bool enable_radio; - bool all_wiphys_idle; - bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); - - spin_lock_bh(&sc->wiphy_lock); - all_wiphys_idle = ath9k_all_wiphys_idle(sc); - ath9k_set_wiphy_idle(aphy, idle); - - enable_radio = (!idle && all_wiphys_idle); - - /* - * After we unlock here its possible another wiphy - * can be re-renabled so to account for that we will - * only disable the radio toward the end of this routine - * if by then all wiphys are still idle. - */ - spin_unlock_bh(&sc->wiphy_lock); - - if (enable_radio) { - sc->ps_idle = false; + sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); + if (!sc->ps_idle) { ath_radio_enable(sc, hw); ath_dbg(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); + } else { + disable_radio = true; } } @@ -1641,29 +1660,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (ah->curchan) old_pos = ah->curchan - &ah->channels[0]; - aphy->chan_idx = pos; - aphy->chan_is_ht = conf_is_ht(conf); if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) sc->sc_flags |= SC_OP_OFFCHANNEL; else sc->sc_flags &= ~SC_OP_OFFCHANNEL; - if (aphy->state == ATH_WIPHY_SCAN || - aphy->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_all_forced(sc, aphy); - else { - /* - * Do not change operational channel based on a paused - * wiphy changes. - */ - goto skip_chan_change; - } - ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); - /* XXX: remove me eventualy */ - ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]); + ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], + curchan, conf->channel_type); /* update survey stats for the old channel before switching */ spin_lock_irqsave(&common->cc_lock, flags); @@ -1705,7 +1711,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_survey_nf(sc, old_pos); } -skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) { sc->config.txpowlimit = 2 * conf->power_level; ath9k_ps_wakeup(sc); @@ -1713,13 +1718,8 @@ skip_chan_change: ath9k_ps_restore(sc); } - spin_lock_bh(&sc->wiphy_lock); - disable_radio = ath9k_all_wiphys_idle(sc); - spin_unlock_bh(&sc->wiphy_lock); - if (disable_radio) { ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); - sc->ps_idle = true; ath_radio_disable(sc, hw); } @@ -1744,8 +1744,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; u32 rfilt; changed_flags &= SUPPORTED_FILTERS; @@ -1765,8 +1764,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; ath_node_attach(sc, sta); @@ -1777,8 +1775,7 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; ath_node_detach(sc, sta); @@ -1788,8 +1785,7 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_txq *txq; struct ath9k_tx_queue_info qi; @@ -1833,8 +1829,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; @@ -1878,8 +1873,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; @@ -1909,7 +1903,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON) || ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - error = ath_beacon_alloc(aphy, vif); + error = ath_beacon_alloc(sc, vif); if (!error) ath_beacon_config(sc, vif); } @@ -1946,7 +1940,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP) { sc->sc_flags |= SC_OP_TSF_RESET; ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - error = ath_beacon_alloc(aphy, vif); + error = ath_beacon_alloc(sc, vif); if (!error) ath_beacon_config(sc, vif); } else { @@ -1984,9 +1978,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, static u64 ath9k_get_tsf(struct ieee80211_hw *hw) { + struct ath_softc *sc = hw->priv; u64 tsf; - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); @@ -1999,8 +1992,7 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw) static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); @@ -2011,8 +2003,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) static void ath9k_reset_tsf(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; mutex_lock(&sc->mutex); @@ -2027,10 +2018,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + u16 tid, u16 *ssn, u8 buf_size) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; int ret = 0; local_bh_disable(); @@ -2075,8 +2065,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -2110,47 +2099,9 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } -static void ath9k_sw_scan_start(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - if (ath9k_wiphy_scanning(sc)) { - /* - * There is a race here in mac80211 but fixing it requires - * we revisit how we handle the scan complete callback. - * After mac80211 fixes we will not have configured hardware - * to the home channel nor would we have configured the RX - * filter yet. - */ - mutex_unlock(&sc->mutex); - return; - } - - aphy->state = ATH_WIPHY_SCAN; - ath9k_wiphy_pause_all_forced(sc, aphy); - mutex_unlock(&sc->mutex); -} - -/* - * XXX: this requires a revisit after the driver - * scan_complete gets moved to another place/removed in mac80211. - */ -static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - aphy->state = ATH_WIPHY_ACTIVE; - mutex_unlock(&sc->mutex); -} - static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; mutex_lock(&sc->mutex); @@ -2178,8 +2129,6 @@ struct ieee80211_ops ath9k_ops = { .reset_tsf = ath9k_reset_tsf, .ampdu_action = ath9k_ampdu_action, .get_survey = ath9k_get_survey, - .sw_scan_start = ath9k_sw_scan_start, - .sw_scan_complete = ath9k_sw_scan_complete, .rfkill_poll = ath9k_rfkill_poll_state, .set_coverage_class = ath9k_set_coverage_class, }; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 78ef1f13386f..e83128c50f7b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -126,7 +126,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *mem; - struct ath_wiphy *aphy; struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; @@ -198,8 +197,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_iomap; } - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + - sizeof(struct ath_softc), &ath9k_ops); + hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (!hw) { dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); ret = -ENOMEM; @@ -209,11 +207,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); - aphy = hw->priv; - sc = (struct ath_softc *) (aphy + 1); - aphy->sc = sc; - aphy->hw = hw; - sc->pri_wiphy = aphy; + sc = hw->priv; sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; @@ -260,8 +254,7 @@ err_dma: static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; void __iomem *mem = sc->mem; if (!is_ath9k_unloaded) @@ -281,8 +274,7 @@ static int ath_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); @@ -293,8 +285,7 @@ static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; u32 val; /* @@ -320,7 +311,6 @@ static int ath_pci_resume(struct device *device) ath9k_ps_restore(sc); sc->ps_idle = true; - ath9k_set_wiphy_idle(aphy, true); ath_radio_disable(sc, hw); return 0; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e45147820eae..960d717ca7c2 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1560,8 +1560,7 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ath_wiphy *aphy = hw->priv; - return aphy->sc; + return hw->priv; } static void ath_rate_free(void *priv) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b2497b8601e5..daf171d2f610 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -34,27 +34,6 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP); } -static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, - struct ieee80211_hdr *hdr) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - int i; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr) - == 0) { - hw = aphy->hw; - break; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return hw; -} - /* * Setup and link descriptors. * @@ -230,11 +209,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) int error = 0, i; u32 size; - - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN + - ah->caps.rx_status_len, - min(common->cachelsz, (u16)64)); - ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - ah->caps.rx_status_len); @@ -321,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); + common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + + sc->sc_ah->caps.rx_status_len; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { return ath_rx_edma_init(sc, nbufs); } else { - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(common->cachelsz, (u16)64)); - ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", common->cachelsz, common->rx_bufsize); @@ -463,8 +437,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (conf_is_ht(&sc->hw->conf)) rfilt |= ATH9K_RX_FILTER_COMP_BAR; - if (sc->sec_wiphy || (sc->nvifs > 1) || - (sc->rx.rxfilter & FIF_OTHER_BSS)) { + if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* The following may also be needed for other older chips */ if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160) rfilt |= ATH9K_RX_FILTER_PROM; @@ -588,8 +561,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) return; mgmt = (struct ieee80211_mgmt *)skb->data; - if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) + if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) { + /* TODO: This doesn't work well if you have stations + * associated to two different APs because curbssid + * is just the last AP that any of the stations associated + * with. + */ return; /* not from our current AP */ + } sc->ps_flags &= ~PS_WAIT_FOR_BEACON; @@ -662,37 +641,6 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) } } -static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, - struct ath_softc *sc, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *)skb->data; - - /* Send the frame to mac80211 */ - if (is_multicast_ether_addr(hdr->addr1)) { - int i; - /* - * Deliver broadcast/multicast frames to all suitable - * virtual wiphys. - */ - /* TODO: filter based on channel configuration */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - struct sk_buff *nskb; - if (aphy == NULL) - continue; - nskb = skb_copy(skb, GFP_ATOMIC); - if (!nskb) - continue; - ieee80211_rx(aphy->hw, nskb); - } - ieee80211_rx(sc->hw, skb); - } else - /* Deliver unicast frames based on receiver address */ - ieee80211_rx(hw, skb); -} - static bool ath_edma_get_buffers(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { @@ -862,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) return false; - /* - * rs_more indicates chained descriptors which can be used - * to link buffers together for a sort of scatter-gather - * operation. - * reject the frame, we don't support scatter-gather yet and - * the frame is probably corrupt anyway - */ + /* Only use error bits from the last fragment */ if (rx_stats->rs_more) - return false; + return true; /* * The rx_stats->rs_status will not be set until the end of the @@ -974,7 +916,7 @@ static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hdr *hdr, struct ath_rx_status *rx_stats) { - struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; __le16 fc; @@ -984,13 +926,19 @@ static void ath9k_process_rssi(struct ath_common *common, fc = hdr->frame_control; if (!ieee80211_is_beacon(fc) || - compare_ether_addr(hdr->addr3, common->curbssid)) + compare_ether_addr(hdr->addr3, common->curbssid)) { + /* TODO: This doesn't work well if you have stations + * associated to two different APs because curbssid + * is just the last AP that any of the stations associated + * with. + */ return; + } if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) - ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi); + ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); - last_rssi = aphy->last_rssi; + last_rssi = sc->last_rssi; if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) rx_stats->rs_rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); @@ -1022,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) return -EINVAL; + /* Only use status info from the last fragment */ + if (rx_stats->rs_more) + return 0; + ath9k_process_rssi(common, hw, hdr, rx_stats); if (ath9k_process_rate(common, hw, rx_stats, rx_status)) @@ -1623,7 +1575,7 @@ div_comb_done: int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; - struct sk_buff *skb = NULL, *requeue_skb; + struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -1632,7 +1584,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * virtual wiphy so to account for that we iterate over the active * wiphys and find the appropriate wiphy and therefore hw. */ - struct ieee80211_hw *hw = NULL; + struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; int retval; bool decrypt_error = false; @@ -1674,10 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (!skb) continue; - hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len); - rxs = IEEE80211_SKB_RXCB(skb); + /* + * Take frame header from the first fragment and RX status from + * the last one. + */ + if (sc->rx.frag) + hdr_skb = sc->rx.frag; + else + hdr_skb = skb; - hw = ath_get_virt_hw(sc, hdr); + hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); + rxs = IEEE80211_SKB_RXCB(hdr_skb); ath_debug_stat_rx(sc, &rs); @@ -1686,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * chain it back at the queue without processing it. */ if (flush) - goto requeue; + goto requeue_drop_frag; retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, rxs, &decrypt_error); if (retval) - goto requeue; + goto requeue_drop_frag; rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; if (rs.rs_tstamp > tsf_lower && @@ -1711,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ if (!requeue_skb) - goto requeue; + goto requeue_drop_frag; /* Unmap the frame */ dma_unmap_single(sc->dev, bf->bf_buf_addr, @@ -1722,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (ah->caps.rx_status_len) skb_pull(skb, ah->caps.rx_status_len); - ath9k_rx_skb_postprocess(common, skb, &rs, - rxs, decrypt_error); + if (!rs.rs_more) + ath9k_rx_skb_postprocess(common, hdr_skb, &rs, + rxs, decrypt_error); /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; @@ -1736,10 +1696,42 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) bf->bf_mpdu = NULL; bf->bf_buf_addr = 0; ath_err(common, "dma_mapping_error() on RX\n"); - ath_rx_send_to_mac80211(hw, sc, skb); + ieee80211_rx(hw, skb); break; } + if (rs.rs_more) { + /* + * rs_more indicates chained descriptors which can be + * used to link buffers together for a sort of + * scatter-gather operation. + */ + if (sc->rx.frag) { + /* too many fragments - cannot handle frame */ + dev_kfree_skb_any(sc->rx.frag); + dev_kfree_skb_any(skb); + skb = NULL; + } + sc->rx.frag = skb; + goto requeue; + } + + if (sc->rx.frag) { + int space = skb->len - skb_tailroom(hdr_skb); + + sc->rx.frag = NULL; + + if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { + dev_kfree_skb(skb); + goto requeue_drop_frag; + } + + skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len), + skb->len); + dev_kfree_skb_any(skb); + skb = hdr_skb; + } + /* * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. @@ -1763,8 +1755,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) ath_ant_comb_scan(sc, &rs); - ath_rx_send_to_mac80211(hw, sc, skb); + ieee80211_rx(hw, skb); +requeue_drop_frag: + if (sc->rx.frag) { + dev_kfree_skb_any(sc->rx.frag); + sc->rx.frag = NULL; + } requeue: if (edma) { list_add_tail(&bf->list, &sc->rx.rxbuf); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 4df5659c6c16..b262e98709de 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1083,6 +1083,17 @@ enum { #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_MPSD 0x00800000 +#define AR_CH0_BB_DPLL2 0x16184 +#define AR_CH0_BB_DPLL3 0x16188 +#define AR_CH0_DDR_DPLL2 0x16244 +#define AR_CH0_DDR_DPLL3 0x16248 +#define AR_CH0_DPLL2_KD 0x03F80000 +#define AR_CH0_DPLL2_KD_S 19 +#define AR_CH0_DPLL2_KI 0x3C000000 +#define AR_CH0_DPLL2_KI_S 26 +#define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000 +#define AR_CH0_DPLL3_PHASE_SHIFT_S 23 +#define AR_PHY_CCA_NOM_VAL_2GHZ -118 #define AR_RTC_9300_PLL_DIV 0x000003ff #define AR_RTC_9300_PLL_DIV_S 0 @@ -1129,6 +1140,12 @@ enum { #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 +#define PLL3 0x16188 +#define PLL3_DO_MEAS_MASK 0x40000000 +#define PLL4 0x1618c +#define PLL4_MEAS_DONE 0x8 +#define SQSUM_DVC_MASK 0x007ffff8 + #define AR_RTC_RESET \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) #define AR_RTC_RESET_EN (0x00000001) diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c deleted file mode 100644 index 2dc7095e56d1..000000000000 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> - -#include "ath9k.h" - -struct ath9k_vif_iter_data { - const u8 *hw_macaddr; - u8 mask[ETH_ALEN]; -}; - -static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath9k_vif_iter_data *iter_data = data; - int i; - - for (i = 0; i < ETH_ALEN; i++) - iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); -} - -void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath9k_vif_iter_data iter_data; - int i; - - /* - * Use the hardware MAC address as reference, the hardware uses it - * together with the BSSID mask when matching addresses. - */ - iter_data.hw_macaddr = common->macaddr; - memset(&iter_data.mask, 0xff, ETH_ALEN); - - if (vif) - ath9k_vif_iter(&iter_data, vif->addr, vif); - - /* Get list of all active MAC addresses */ - spin_lock_bh(&sc->wiphy_lock); - ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, - &iter_data); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] == NULL) - continue; - ieee80211_iterate_active_interfaces_atomic( - sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); - } - spin_unlock_bh(&sc->wiphy_lock); - - memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); - ath_hw_setbssidmask(common); -} - -int ath9k_wiphy_add(struct ath_softc *sc) -{ - int i, error; - struct ath_wiphy *aphy; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_hw *hw; - u8 addr[ETH_ALEN]; - - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); - if (hw == NULL) - return -ENOMEM; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] == NULL) - break; - } - - if (i == sc->num_sec_wiphy) { - /* No empty slot available; increase array length */ - struct ath_wiphy **n; - n = krealloc(sc->sec_wiphy, - (sc->num_sec_wiphy + 1) * - sizeof(struct ath_wiphy *), - GFP_ATOMIC); - if (n == NULL) { - spin_unlock_bh(&sc->wiphy_lock); - ieee80211_free_hw(hw); - return -ENOMEM; - } - n[i] = NULL; - sc->sec_wiphy = n; - sc->num_sec_wiphy++; - } - - SET_IEEE80211_DEV(hw, sc->dev); - - aphy = hw->priv; - aphy->sc = sc; - aphy->hw = hw; - sc->sec_wiphy[i] = aphy; - aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; - spin_unlock_bh(&sc->wiphy_lock); - - memcpy(addr, common->macaddr, ETH_ALEN); - addr[0] |= 0x02; /* Locally managed address */ - /* - * XOR virtual wiphy index into the least significant bits to generate - * a different MAC address for each virtual wiphy. - */ - addr[5] ^= i & 0xff; - addr[4] ^= (i & 0xff00) >> 8; - addr[3] ^= (i & 0xff0000) >> 16; - - SET_IEEE80211_PERM_ADDR(hw, addr); - - ath9k_set_hw_capab(sc, hw); - - error = ieee80211_register_hw(hw); - - if (error == 0) { - /* Make sure wiphy scheduler is started (if enabled) */ - ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); - } - - return error; -} - -int ath9k_wiphy_del(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - int i; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (aphy == sc->sec_wiphy[i]) { - sc->sec_wiphy[i] = NULL; - spin_unlock_bh(&sc->wiphy_lock); - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - return 0; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return -ENOENT; -} - -static int ath9k_send_nullfunc(struct ath_wiphy *aphy, - struct ieee80211_vif *vif, const u8 *bssid, - int ps) -{ - struct ath_softc *sc = aphy->sc; - struct ath_tx_control txctl; - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - __le16 fc; - struct ieee80211_tx_info *info; - - skb = dev_alloc_skb(24); - if (skb == NULL) - return -ENOMEM; - hdr = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(hdr, 0, 24); - fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - if (ps) - fc |= cpu_to_le16(IEEE80211_FCTL_PM); - hdr->frame_control = fc; - memcpy(hdr->addr1, bssid, ETH_ALEN); - memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN); - memcpy(hdr->addr3, bssid, ETH_ALEN); - - info = IEEE80211_SKB_CB(skb); - memset(info, 0, sizeof(*info)); - info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS; - info->control.vif = vif; - info->control.rates[0].idx = 0; - info->control.rates[0].count = 4; - info->control.rates[1].idx = -1; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.txq = sc->tx.txq_map[WME_AC_VO]; - txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE; - - if (ath_tx_start(aphy->hw, skb, &txctl) != 0) - goto exit; - - return 0; -exit: - dev_kfree_skb_any(skb); - return -1; -} - -static bool __ath9k_wiphy_pausing(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING) - return true; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING) - return true; - } - return false; -} - -static bool ath9k_wiphy_pausing(struct ath_softc *sc) -{ - bool ret; - spin_lock_bh(&sc->wiphy_lock); - ret = __ath9k_wiphy_pausing(sc); - spin_unlock_bh(&sc->wiphy_lock); - return ret; -} - -static bool __ath9k_wiphy_scanning(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) - return true; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) - return true; - } - return false; -} - -bool ath9k_wiphy_scanning(struct ath_softc *sc) -{ - bool ret; - spin_lock_bh(&sc->wiphy_lock); - ret = __ath9k_wiphy_scanning(sc); - spin_unlock_bh(&sc->wiphy_lock); - return ret; -} - -static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); - -/* caller must hold wiphy_lock */ -static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy) -{ - if (aphy == NULL) - return; - if (aphy->chan_idx != aphy->sc->chan_idx) - return; /* wiphy not on the selected channel */ - __ath9k_wiphy_unpause(aphy); -} - -static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - __ath9k_wiphy_unpause_ch(sc->pri_wiphy); - for (i = 0; i < sc->num_sec_wiphy; i++) - __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]); - spin_unlock_bh(&sc->wiphy_lock); -} - -void ath9k_wiphy_chan_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_wiphy *aphy = sc->next_wiphy; - - if (aphy == NULL) - return; - - /* - * All pending interfaces paused; ready to change - * channels. - */ - - /* Change channels */ - mutex_lock(&sc->mutex); - /* XXX: remove me eventually */ - ath9k_update_ichannel(sc, aphy->hw, - &sc->sc_ah->channels[sc->chan_idx]); - - /* sync hw configuration for hw code */ - common->hw = aphy->hw; - - if (ath_set_channel(sc, aphy->hw, - &sc->sc_ah->channels[sc->chan_idx]) < 0) { - printk(KERN_DEBUG "ath9k: Failed to set channel for new " - "virtual wiphy\n"); - mutex_unlock(&sc->mutex); - return; - } - mutex_unlock(&sc->mutex); - - ath9k_wiphy_unpause_channel(sc); -} - -/* - * ath9k version of ieee80211_tx_status() for TX frames that are generated - * internally in the driver. - */ -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype) -{ - struct ath_wiphy *aphy = hw->priv; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - if (ftype == ATH9K_IFT_PAUSE && aphy->state == ATH_WIPHY_PAUSING) { - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) { - printk(KERN_DEBUG "ath9k: %s: no ACK for pause " - "frame\n", wiphy_name(hw->wiphy)); - /* - * The AP did not reply; ignore this to allow us to - * continue. - */ - } - aphy->state = ATH_WIPHY_PAUSED; - if (!ath9k_wiphy_pausing(aphy->sc)) { - /* - * Drop from tasklet to work to allow mutex for channel - * change. - */ - ieee80211_queue_work(aphy->sc->hw, - &aphy->sc->chan_work); - } - } - - dev_kfree_skb(skb); -} - -static void ath9k_mark_paused(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - aphy->state = ATH_WIPHY_PAUSED; - if (!__ath9k_wiphy_pausing(sc)) - ieee80211_queue_work(sc->hw, &sc->chan_work); -} - -static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = data; - struct ath_vif *avp = (void *) vif->drv_priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) { - ath9k_mark_paused(aphy); - break; - } - /* TODO: could avoid this if already in PS mode */ - if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) { - printk(KERN_DEBUG "%s: failed to send PS nullfunc\n", - __func__); - ath9k_mark_paused(aphy); - } - break; - case NL80211_IFTYPE_AP: - /* Beacon transmission is paused by aphy->state change */ - ath9k_mark_paused(aphy); - break; - default: - break; - } -} - -/* caller must hold wiphy_lock */ -static int __ath9k_wiphy_pause(struct ath_wiphy *aphy) -{ - ieee80211_stop_queues(aphy->hw); - aphy->state = ATH_WIPHY_PAUSING; - /* - * TODO: handle PAUSING->PAUSED for the case where there are multiple - * active vifs (now we do it on the first vif getting ready; should be - * on the last) - */ - ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter, - aphy); - return 0; -} - -int ath9k_wiphy_pause(struct ath_wiphy *aphy) -{ - int ret; - spin_lock_bh(&aphy->sc->wiphy_lock); - ret = __ath9k_wiphy_pause(aphy); - spin_unlock_bh(&aphy->sc->wiphy_lock); - return ret; -} - -static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = data; - struct ath_vif *avp = (void *) vif->drv_priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) - break; - ath9k_send_nullfunc(aphy, vif, avp->bssid, 0); - break; - case NL80211_IFTYPE_AP: - /* Beacon transmission is re-enabled by aphy->state change */ - break; - default: - break; - } -} - -/* caller must hold wiphy_lock */ -static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy) -{ - ieee80211_iterate_active_interfaces_atomic(aphy->hw, - ath9k_unpause_iter, aphy); - aphy->state = ATH_WIPHY_ACTIVE; - ieee80211_wake_queues(aphy->hw); - return 0; -} - -int ath9k_wiphy_unpause(struct ath_wiphy *aphy) -{ - int ret; - spin_lock_bh(&aphy->sc->wiphy_lock); - ret = __ath9k_wiphy_unpause(aphy); - spin_unlock_bh(&aphy->sc->wiphy_lock); - return ret; -} - -static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) - sc->pri_wiphy->state = ATH_WIPHY_PAUSED; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) - sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED; - } -} - -/* caller must hold wiphy_lock */ -static void __ath9k_wiphy_pause_all(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) - __ath9k_wiphy_pause(sc->pri_wiphy); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) - __ath9k_wiphy_pause(sc->sec_wiphy[i]); - } -} - -int ath9k_wiphy_select(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - bool now; - - spin_lock_bh(&sc->wiphy_lock); - if (__ath9k_wiphy_scanning(sc)) { - /* - * For now, we are using mac80211 sw scan and it expects to - * have full control over channel changes, so avoid wiphy - * scheduling during a scan. This could be optimized if the - * scanning control were moved into the driver. - */ - spin_unlock_bh(&sc->wiphy_lock); - return -EBUSY; - } - if (__ath9k_wiphy_pausing(sc)) { - if (sc->wiphy_select_failures == 0) - sc->wiphy_select_first_fail = jiffies; - sc->wiphy_select_failures++; - if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) - { - printk(KERN_DEBUG "ath9k: Previous wiphy select timed " - "out; disable/enable hw to recover\n"); - __ath9k_wiphy_mark_all_paused(sc); - /* - * TODO: this workaround to fix hardware is unlikely to - * be specific to virtual wiphy changes. It can happen - * on normal channel change, too, and as such, this - * should really be made more generic. For example, - * tricker radio disable/enable on GTT interrupt burst - * (say, 10 GTT interrupts received without any TX - * frame being completed) - */ - spin_unlock_bh(&sc->wiphy_lock); - ath_radio_disable(sc, aphy->hw); - ath_radio_enable(sc, aphy->hw); - /* Only the primary wiphy hw is used for queuing work */ - ieee80211_queue_work(aphy->sc->hw, - &aphy->sc->chan_work); - return -EBUSY; /* previous select still in progress */ - } - spin_unlock_bh(&sc->wiphy_lock); - return -EBUSY; /* previous select still in progress */ - } - sc->wiphy_select_failures = 0; - - /* Store the new channel */ - sc->chan_idx = aphy->chan_idx; - sc->chan_is_ht = aphy->chan_is_ht; - sc->next_wiphy = aphy; - - __ath9k_wiphy_pause_all(sc); - now = !__ath9k_wiphy_pausing(aphy->sc); - spin_unlock_bh(&sc->wiphy_lock); - - if (now) { - /* Ready to request channel change immediately */ - ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); - } - - /* - * wiphys will be unpaused in ath9k_tx_status() once channel has been - * changed if any wiphy needs time to become paused. - */ - - return 0; -} - -bool ath9k_wiphy_started(struct ath_softc *sc) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { - spin_unlock_bh(&sc->wiphy_lock); - return true; - } - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { - spin_unlock_bh(&sc->wiphy_lock); - return true; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return false; -} - -static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, - struct ath_wiphy *selected) -{ - if (selected->state == ATH_WIPHY_SCAN) { - if (aphy == selected) - return; - /* - * Pause all other wiphys for the duration of the scan even if - * they are on the current channel now. - */ - } else if (aphy->chan_idx == selected->chan_idx) - return; - aphy->state = ATH_WIPHY_PAUSED; - ieee80211_stop_queues(aphy->hw); -} - -void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, - struct ath_wiphy *selected) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_chan(sc->pri_wiphy, selected); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected); - } - spin_unlock_bh(&sc->wiphy_lock); -} - -void ath9k_wiphy_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - wiphy_work.work); - struct ath_wiphy *aphy = NULL; - bool first = true; - - spin_lock_bh(&sc->wiphy_lock); - - if (sc->wiphy_scheduler_int == 0) { - /* wiphy scheduler is disabled */ - spin_unlock_bh(&sc->wiphy_lock); - return; - } - -try_again: - sc->wiphy_scheduler_index++; - while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { - aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; - if (aphy && aphy->state != ATH_WIPHY_INACTIVE) - break; - - sc->wiphy_scheduler_index++; - aphy = NULL; - } - if (aphy == NULL) { - sc->wiphy_scheduler_index = 0; - if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { - if (first) { - first = false; - goto try_again; - } - /* No wiphy is ready to be scheduled */ - } else - aphy = sc->pri_wiphy; - } - - spin_unlock_bh(&sc->wiphy_lock); - - if (aphy && - aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && - ath9k_wiphy_select(aphy)) { - printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " - "change\n"); - } - - ieee80211_queue_delayed_work(sc->hw, - &sc->wiphy_work, - sc->wiphy_scheduler_int); -} - -void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) -{ - cancel_delayed_work_sync(&sc->wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); - if (sc->wiphy_scheduler_int) - ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work, - sc->wiphy_scheduler_int); -} - -/* caller must hold wiphy_lock */ -bool ath9k_all_wiphys_idle(struct ath_softc *sc) -{ - unsigned int i; - if (!sc->pri_wiphy->idle) - return false; - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (!aphy) - continue; - if (!aphy->idle) - return false; - } - return true; -} - -/* caller must hold wiphy_lock */ -void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) -{ - struct ath_softc *sc = aphy->sc; - - aphy->idle = idle; - ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, - "Marking %s as %sidle\n", - wiphy_name(aphy->hw->wiphy), idle ? "" : "not-"); -} -/* Only bother starting a queue on an active virtual wiphy */ -bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - unsigned int i; - bool txq_started = false; - - spin_lock_bh(&sc->wiphy_lock); - - /* Start the primary wiphy */ - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) { - ieee80211_wake_queue(hw, skb_queue); - txq_started = true; - goto unlock; - } - - /* Now start the secondary wiphy queues */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (!aphy) - continue; - if (aphy->state != ATH_WIPHY_ACTIVE) - continue; - - hw = aphy->hw; - ieee80211_wake_queue(hw, skb_queue); - txq_started = true; - break; - } - -unlock: - spin_unlock_bh(&sc->wiphy_lock); - return txq_started; -} - -/* Go ahead and propagate information to all virtual wiphys, it won't hurt */ -void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - unsigned int i; - - spin_lock_bh(&sc->wiphy_lock); - - /* Stop the primary wiphy */ - ieee80211_stop_queue(hw, skb_queue); - - /* Now stop the secondary wiphy queues */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (!aphy) - continue; - hw = aphy->hw; - ieee80211_stop_queue(hw, skb_queue); - } - spin_unlock_bh(&sc->wiphy_lock); -} diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 33a37edbaf79..68a1c7612e9b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -19,7 +19,6 @@ #define BITS_PER_BYTE 8 #define OFDM_PLCP_BITS 22 -#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f) #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) #define L_STF 8 #define L_LTF 8 @@ -32,7 +31,6 @@ #define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) #define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) -#define OFDM_SIFS_TIME 16 static u16 bits_per_symbol[][2] = { /* 20MHz 40MHz */ @@ -57,8 +55,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len); -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, - int nframes, int nbad, int txok, bool update_rc); +static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts, int nframes, int nbad, + int txok, bool update_rc); static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, int seqno); @@ -169,7 +168,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ath_tx_update_baw(sc, tid, fi->seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } else { - ath_tx_send_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txq, NULL, &bf_head); } spin_lock_bh(&txq->axq_lock); } @@ -297,7 +296,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) ATH_TXBUF_RESET(tbf); - tbf->aphy = bf->aphy; tbf->bf_mpdu = bf->bf_mpdu; tbf->bf_buf_addr = bf->bf_buf_addr; memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); @@ -345,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_sta *sta; - struct ieee80211_hw *hw; + struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct ath_atx_tid *tid = NULL; @@ -364,7 +362,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, hdr = (struct ieee80211_hdr *)skb->data; tx_info = IEEE80211_SKB_CB(skb); - hw = bf->aphy->hw; memcpy(rates, tx_info->control.rates, sizeof(rates)); @@ -383,7 +380,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, 1, 1, 0, false); + ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -429,7 +426,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); while (bf) { - txfail = txpending = 0; + txfail = txpending = sendbar = 0; bf_next = bf->bf_next; skb = bf->bf_mpdu; @@ -489,10 +486,10 @@ 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)); - ath_tx_rc_status(bf, ts, nframes, nbad, txok, true); + ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true); rc_update = false; } else { - ath_tx_rc_status(bf, ts, nframes, nbad, txok, false); + ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false); } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, @@ -516,7 +513,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ts, nframes, + ath_tx_rc_status(sc, bf, ts, nframes, nbad, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, @@ -566,8 +563,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); - if (needreset) + if (needreset) { + spin_unlock_bh(&sc->sc_pcu_lock); ath_reset(sc, false); + spin_lock_bh(&sc->sc_pcu_lock); + } } static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -856,7 +856,10 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, txtid->state |= AGGR_ADDBA_PROGRESS; txtid->paused = true; - *ssn = txtid->seq_start; + *ssn = txtid->seq_start = txtid->seq_next; + + memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); + txtid->baw_head = txtid->baw_tail = 0; return 0; } @@ -942,7 +945,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) [WME_AC_VI] = ATH_TXQ_AC_VI, [WME_AC_VO] = ATH_TXQ_AC_VO, }; - int qnum, i; + int axq_qnum, i; memset(&qi, 0, sizeof(qi)); qi.tqi_subtype = subtype_txq_to_hwq[subtype]; @@ -976,24 +979,25 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; } - qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); - if (qnum == -1) { + axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); + if (axq_qnum == -1) { /* * NB: don't print a message, this happens * normally on parts with too few tx queues */ return NULL; } - if (qnum >= ARRAY_SIZE(sc->tx.txq)) { + if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) { ath_err(common, "qnum %u out of range, max %zu!\n", - qnum, ARRAY_SIZE(sc->tx.txq)); - ath9k_hw_releasetxqueue(ah, qnum); + axq_qnum, ARRAY_SIZE(sc->tx.txq)); + ath9k_hw_releasetxqueue(ah, axq_qnum); return NULL; } - if (!ATH_TXQ_SETUP(sc, qnum)) { - struct ath_txq *txq = &sc->tx.txq[qnum]; + if (!ATH_TXQ_SETUP(sc, axq_qnum)) { + struct ath_txq *txq = &sc->tx.txq[axq_qnum]; - txq->axq_qnum = qnum; + txq->axq_qnum = axq_qnum; + txq->mac80211_qnum = -1; txq->axq_link = NULL; INIT_LIST_HEAD(&txq->axq_q); INIT_LIST_HEAD(&txq->axq_acq); @@ -1001,14 +1005,14 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_depth = 0; txq->axq_ampdu_depth = 0; txq->axq_tx_inprogress = false; - sc->tx.txqsetup |= 1<<qnum; + sc->tx.txqsetup |= 1<<axq_qnum; txq->txq_headidx = txq->txq_tailidx = 0; for (i = 0; i < ATH_TXFIFO_DEPTH; i++) INIT_LIST_HEAD(&txq->txq_fifo[i]); INIT_LIST_HEAD(&txq->txq_fifo_pending); } - return &sc->tx.txq[qnum]; + return &sc->tx.txq[axq_qnum]; } int ath_txq_update(struct ath_softc *sc, int qnum, @@ -1205,8 +1209,17 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) ath_err(common, "Failed to stop TX DMA!\n"); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) - ath_draintxq(sc, &sc->tx.txq[i], retry_tx); + if (!ATH_TXQ_SETUP(sc, i)) + continue; + + /* + * The caller will resume queues with ieee80211_wake_queues. + * Mark the queue as not stopped to prevent ath_tx_complete + * from waking the queue too early. + */ + txq = &sc->tx.txq[i]; + txq->stopped = false; + ath_draintxq(sc, txq, retry_tx); } return !npend; @@ -1218,46 +1231,59 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) sc->tx.txqsetup &= ~(1<<txq->axq_qnum); } +/* For each axq_acq entry, for each tid, try to schedule packets + * for transmit until ampdu_depth has reached min Q depth. + */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { - struct ath_atx_ac *ac; - struct ath_atx_tid *tid; + struct ath_atx_ac *ac, *ac_tmp, *last_ac; + struct ath_atx_tid *tid, *last_tid; - if (list_empty(&txq->axq_acq)) + if (list_empty(&txq->axq_acq) || + txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) return; ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); - list_del(&ac->list); - ac->sched = false; + last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); - do { - if (list_empty(&ac->tid_q)) - return; + list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { + last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); + list_del(&ac->list); + ac->sched = false; - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); - list_del(&tid->list); - tid->sched = false; + while (!list_empty(&ac->tid_q)) { + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, + list); + list_del(&tid->list); + tid->sched = false; - if (tid->paused) - continue; + if (tid->paused) + continue; - ath_tx_sched_aggr(sc, txq, tid); + ath_tx_sched_aggr(sc, txq, tid); - /* - * add tid to round-robin queue if more frames - * are pending for the tid - */ - if (!list_empty(&tid->buf_q)) - ath_tx_queue_tid(txq, tid); + /* + * add tid to round-robin queue if more frames + * are pending for the tid + */ + if (!list_empty(&tid->buf_q)) + ath_tx_queue_tid(txq, tid); - break; - } while (!list_empty(&ac->tid_q)); + if (tid == last_tid || + txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + break; + } - if (!list_empty(&ac->tid_q)) { - if (!ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + if (!list_empty(&ac->tid_q)) { + if (!ac->sched) { + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); + } } + + if (ac == last_ac || + txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + return; } } @@ -1301,6 +1327,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]); list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]); INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); + TX_STAT_INC(txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); @@ -1308,6 +1335,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, list_splice_tail_init(head, &txq->axq_q); if (txq->axq_link == NULL) { + TX_STAT_INC(txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), @@ -1321,6 +1349,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc, &txq->axq_link); + TX_STAT_INC(txq->axq_qnum, txstart); ath9k_hw_txstart(ah, txq->axq_qnum); } txq->axq_depth++; @@ -1335,7 +1364,6 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head bf_head; bf->bf_state.bf_type |= BUF_AMPDU; - TX_STAT_INC(txctl->txq->axq_qnum, a_queued); /* * Do not queue to h/w when any of the following conditions is true: @@ -1351,6 +1379,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * Add this frame to software queue for scheduling later * for aggregation. */ + TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); list_add_tail(&bf->list, &tid->buf_q); ath_tx_queue_tid(txctl->txq, tid); return; @@ -1364,6 +1393,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ath_tx_addto_baw(sc, tid, fi->seqno); /* Queue to h/w without aggregation */ + TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw); bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf, fi->framelen); ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); @@ -1416,8 +1446,7 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, int framelen) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; @@ -1635,8 +1664,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_txq *txq, struct sk_buff *skb) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); @@ -1652,7 +1680,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ATH_TXBUF_RESET(bf); - bf->aphy = aphy; bf->bf_flags = setup_tx_flags(skb); bf->bf_mpdu = skb; @@ -1738,8 +1765,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = info->control.sta; - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; struct ath_buf *bf; int padpos, padsize; @@ -1791,7 +1817,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, spin_lock_bh(&txq->axq_lock); if (txq == sc->tx.txq_map[q] && ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { - ath_mac80211_stop_queue(sc, q); + ieee80211_stop_queue(sc->hw, q); txq->stopped = 1; } spin_unlock_bh(&txq->axq_lock); @@ -1806,8 +1832,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_wiphy *aphy, int tx_flags, int ftype, - struct ath_txq *txq) + int tx_flags, int ftype, struct ath_txq *txq) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1817,9 +1842,6 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); - if (aphy) - hw = aphy->hw; - if (tx_flags & ATH_TX_BAR) tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; @@ -1849,19 +1871,20 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, PS_WAIT_FOR_TX_ACK)); } - if (unlikely(ftype)) - ath9k_tx_status(hw, skb, ftype); - else { - q = skb_get_queue_mapping(skb); - if (txq == sc->tx.txq_map[q]) { - spin_lock_bh(&txq->axq_lock); - if (WARN_ON(--txq->pending_frames < 0)) - txq->pending_frames = 0; - spin_unlock_bh(&txq->axq_lock); - } + q = skb_get_queue_mapping(skb); + if (txq == sc->tx.txq_map[q]) { + spin_lock_bh(&txq->axq_lock); + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; - ieee80211_tx_status(hw, skb); + if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { + ieee80211_wake_queue(sc->hw, q); + txq->stopped = 0; + } + spin_unlock_bh(&txq->axq_lock); } + + ieee80211_tx_status(hw, skb); } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, @@ -1891,8 +1914,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, else complete(&sc->paprd_complete); } else { - ath_debug_stat_tx(sc, bf, ts); - ath_tx_complete(sc, skb, bf->aphy, tx_flags, + ath_debug_stat_tx(sc, bf, ts, txq); + ath_tx_complete(sc, skb, tx_flags, bf->bf_state.bfs_ftype, txq); } /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't @@ -1908,14 +1931,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, - int nframes, int nbad, int txok, bool update_rc) +static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts, int nframes, int nbad, + int txok, bool update_rc) { struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = bf->aphy->hw; - struct ath_softc *sc = bf->aphy->sc; + struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; u8 i, tx_rateindex; @@ -1966,19 +1989,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; } -static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum) -{ - struct ath_txq *txq; - - txq = sc->tx.txq_map[qnum]; - spin_lock_bh(&txq->axq_lock); - if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { - if (ath_mac80211_start_queue(sc, qnum)) - txq->stopped = 0; - } - spin_unlock_bh(&txq->axq_lock); -} - static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hw *ah = sc->sc_ah; @@ -1989,7 +1999,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_tx_status ts; int txok; int status; - int qnum; ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), @@ -1999,6 +2008,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_lock_bh(&txq->axq_lock); if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; + if (sc->sc_flags & SC_OP_TXAGGR) + ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); break; } @@ -2033,6 +2044,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&txq->axq_lock); break; } + TX_STAT_INC(txq->axq_qnum, txprocdesc); /* * Remove ath_buf's of the same transmit unit from txq, @@ -2065,27 +2077,45 @@ 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, 1, txok ? 0 : 1, txok, true); + ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true); } - qnum = skb_get_queue_mapping(bf->bf_mpdu); - if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok, true); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); - if (txq == sc->tx.txq_map[qnum]) - ath_wake_mac80211_queue(sc, qnum); - spin_lock_bh(&txq->axq_lock); + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } } +static void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + static int count; + + if (AR_SREV_9485(sc->sc_ah)) { + if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { + count++; + + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_reset(sc, true); + count = 0; + } + } else + count = 0; + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } +} + static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, @@ -2093,6 +2123,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) struct ath_txq *txq; int i; bool needreset = false; +#ifdef CONFIG_ATH9K_DEBUGFS + sc->tx_complete_poll_work_seen++; +#endif for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) { @@ -2106,6 +2139,33 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } else { txq->axq_tx_inprogress = true; } + } else { + /* If the queue has pending buffers, then it + * should be doing tx work (and have axq_depth). + * Shouldn't get to this state I think..but + * we do. + */ + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && + (txq->pending_frames > 0 || + !list_empty(&txq->axq_acq) || + txq->stopped)) { + ath_err(ath9k_hw_common(sc->sc_ah), + "txq: %p axq_qnum: %u," + " mac80211_qnum: %i" + " axq_link: %p" + " pending frames: %i" + " axq_acq empty: %i" + " stopped: %i" + " axq_depth: 0 Attempting to" + " restart tx logic.\n", + txq, txq->axq_qnum, + txq->mac80211_qnum, + txq->axq_link, + txq->pending_frames, + list_empty(&txq->axq_acq), + txq->stopped); + ath_txq_schedule(sc, txq); + } } spin_unlock_bh(&txq->axq_lock); } @@ -2145,7 +2205,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) struct list_head bf_head; int status; int txok; - int qnum; for (;;) { status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs); @@ -2188,11 +2247,9 @@ 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, 1, txok ? 0 : 1, txok, true); + ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true); } - qnum = skb_get_queue_mapping(bf->bf_mpdu); - if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok, true); @@ -2200,10 +2257,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_tx_complete_buf(sc, bf, txq, &bf_head, &txs, txok, 0); - if (txq == sc->tx.txq_map[qnum]) - ath_wake_mac80211_queue(sc, qnum); - spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->txq_fifo_pending)) { INIT_LIST_HEAD(&bf_head); bf = list_first_entry(&txq->txq_fifo_pending, @@ -2280,6 +2335,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { error = ath_tx_edma_init(sc); diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index d07ff7f2fd92..420d437f9580 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -283,6 +283,7 @@ struct ar9170 { unsigned int mem_blocks; unsigned int mem_block_size; unsigned int rx_size; + unsigned int tx_seq_table; } fw; /* reset / stuck frames/queue detection */ diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 546b4e4ec5ea..9517ede9e2df 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -150,6 +150,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) const struct carl9170fw_otus_desc *otus_desc; const struct carl9170fw_chk_desc *chk_desc; const struct carl9170fw_last_desc *last_desc; + const struct carl9170fw_txsq_desc *txsq_desc; last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC, sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER); @@ -264,6 +265,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) FIF_PROMISC_IN_BSS; } + if (SUPP(CARL9170FW_WOL)) + device_set_wakeup_enable(&ar->udev->dev, true); + ar->fw.vif_num = otus_desc->vif_num; ar->fw.cmd_bufs = otus_desc->cmd_bufs; ar->fw.address = le32_to_cpu(otus_desc->fw_address); @@ -296,6 +300,17 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) } } + txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC, + sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER); + + if (txsq_desc) { + ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr); + if (!valid_cpu_addr(ar->fw.tx_seq_table)) + return -EINVAL; + } else { + ar->fw.tx_seq_table = 0; + } + #undef SUPPORTED return 0; } diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index 3680dfc70f46..30449d21b762 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -167,6 +167,7 @@ struct carl9170_rx_filter_cmd { #define CARL9170_RX_FILTER_CTL_BACKR 0x20 #define CARL9170_RX_FILTER_MGMT 0x40 #define CARL9170_RX_FILTER_DATA 0x80 +#define CARL9170_RX_FILTER_EVERYTHING (~0) struct carl9170_bcn_ctrl_cmd { __le32 vif_id; diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 71f3821f6058..921066822dd5 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h @@ -69,6 +69,9 @@ enum carl9170fw_feature_list { /* Firmware RX filter | CARL9170_CMD_RX_FILTER */ CARL9170FW_RX_FILTER, + /* Wake up on WLAN */ + CARL9170FW_WOL, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; @@ -78,6 +81,7 @@ enum carl9170fw_feature_list { #define FIX_MAGIC "FIX\0" #define DBG_MAGIC "DBG\0" #define CHK_MAGIC "CHK\0" +#define TXSQ_MAGIC "TXSQ" #define LAST_MAGIC "LAST" #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31) @@ -88,8 +92,10 @@ enum carl9170fw_feature_list { #define CARL9170FW_GET_MONTH(m) ((((m) / 31) % 12) + 1) #define CARL9170FW_GET_YEAR(y) ((y) / 372 + 10) +#define CARL9170FW_MAGIC_SIZE 4 + struct carl9170fw_desc_head { - u8 magic[4]; + u8 magic[CARL9170FW_MAGIC_SIZE]; __le16 length; u8 min_ver; u8 cur_ver; @@ -170,6 +176,16 @@ struct carl9170fw_chk_desc { #define CARL9170FW_CHK_DESC_SIZE \ (sizeof(struct carl9170fw_chk_desc)) +#define CARL9170FW_TXSQ_DESC_MIN_VER 1 +#define CARL9170FW_TXSQ_DESC_CUR_VER 1 +struct carl9170fw_txsq_desc { + struct carl9170fw_desc_head head; + + __le32 seq_table_addr; +} __packed; +#define CARL9170FW_TXSQ_DESC_SIZE \ + (sizeof(struct carl9170fw_txsq_desc)) + #define CARL9170FW_LAST_DESC_MIN_VER 1 #define CARL9170FW_LAST_DESC_CUR_VER 2 struct carl9170fw_last_desc { @@ -189,8 +205,8 @@ struct carl9170fw_last_desc { } static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head, - u8 magic[4], __le16 length, - u8 min_ver, u8 cur_ver) + u8 magic[CARL9170FW_MAGIC_SIZE], + __le16 length, u8 min_ver, u8 cur_ver) { head->magic[0] = magic[0]; head->magic[1] = magic[1]; @@ -204,7 +220,7 @@ static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head, #define carl9170fw_for_each_hdr(desc, fw_desc) \ for (desc = fw_desc; \ - memcmp(desc->magic, LAST_MAGIC, 4) && \ + memcmp(desc->magic, LAST_MAGIC, CARL9170FW_MAGIC_SIZE) && \ le16_to_cpu(desc->length) >= CARL9170FW_DESC_HEAD_SIZE && \ le16_to_cpu(desc->length) < CARL9170FW_DESC_MAX_LENGTH; \ desc = (void *)((unsigned long)desc + le16_to_cpu(desc->length))) @@ -218,8 +234,8 @@ static inline bool carl9170fw_supports(__le32 list, u8 feature) } static inline bool carl9170fw_desc_cmp(const struct carl9170fw_desc_head *head, - const u8 descid[4], u16 min_len, - u8 compatible_revision) + const u8 descid[CARL9170FW_MAGIC_SIZE], + u16 min_len, u8 compatible_revision) { if (descid[0] == head->magic[0] && descid[1] == head->magic[1] && descid[2] == head->magic[2] && descid[3] == head->magic[3] && diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index e85df6edfed3..4e30762dd903 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -463,6 +463,8 @@ #define AR9170_PWR_REG_CHIP_REVISION (AR9170_PWR_REG_BASE + 0x010) #define AR9170_PWR_REG_PLL_ADDAC (AR9170_PWR_REG_BASE + 0x014) +#define AR9170_PWR_PLL_ADDAC_DIV_S 2 +#define AR9170_PWR_PLL_ADDAC_DIV 0xffc #define AR9170_PWR_REG_WATCH_DOG_MAGIC (AR9170_PWR_REG_BASE + 0x020) /* Faraday USB Controller */ @@ -471,6 +473,9 @@ #define AR9170_USB_REG_MAIN_CTRL (AR9170_USB_REG_BASE + 0x000) #define AR9170_USB_MAIN_CTRL_REMOTE_WAKEUP BIT(0) #define AR9170_USB_MAIN_CTRL_ENABLE_GLOBAL_INT BIT(2) +#define AR9170_USB_MAIN_CTRL_GO_TO_SUSPEND BIT(3) +#define AR9170_USB_MAIN_CTRL_RESET BIT(4) +#define AR9170_USB_MAIN_CTRL_CHIP_ENABLE BIT(5) #define AR9170_USB_MAIN_CTRL_HIGHSPEED BIT(6) #define AR9170_USB_REG_DEVICE_ADDRESS (AR9170_USB_REG_BASE + 0x001) @@ -499,6 +504,13 @@ #define AR9170_USB_REG_INTR_GROUP (AR9170_USB_REG_BASE + 0x020) #define AR9170_USB_REG_INTR_SOURCE_0 (AR9170_USB_REG_BASE + 0x021) +#define AR9170_USB_INTR_SRC0_SETUP BIT(0) +#define AR9170_USB_INTR_SRC0_IN BIT(1) +#define AR9170_USB_INTR_SRC0_OUT BIT(2) +#define AR9170_USB_INTR_SRC0_FAIL BIT(3) /* ??? */ +#define AR9170_USB_INTR_SRC0_END BIT(4) /* ??? */ +#define AR9170_USB_INTR_SRC0_ABORT BIT(7) + #define AR9170_USB_REG_INTR_SOURCE_1 (AR9170_USB_REG_BASE + 0x022) #define AR9170_USB_REG_INTR_SOURCE_2 (AR9170_USB_REG_BASE + 0x023) #define AR9170_USB_REG_INTR_SOURCE_3 (AR9170_USB_REG_BASE + 0x024) @@ -506,6 +518,15 @@ #define AR9170_USB_REG_INTR_SOURCE_5 (AR9170_USB_REG_BASE + 0x026) #define AR9170_USB_REG_INTR_SOURCE_6 (AR9170_USB_REG_BASE + 0x027) #define AR9170_USB_REG_INTR_SOURCE_7 (AR9170_USB_REG_BASE + 0x028) +#define AR9170_USB_INTR_SRC7_USB_RESET BIT(1) +#define AR9170_USB_INTR_SRC7_USB_SUSPEND BIT(2) +#define AR9170_USB_INTR_SRC7_USB_RESUME BIT(3) +#define AR9170_USB_INTR_SRC7_ISO_SEQ_ERR BIT(4) +#define AR9170_USB_INTR_SRC7_ISO_SEQ_ABORT BIT(5) +#define AR9170_USB_INTR_SRC7_TX0BYTE BIT(6) +#define AR9170_USB_INTR_SRC7_RX0BYTE BIT(7) + +#define AR9170_USB_REG_IDLE_COUNT (AR9170_USB_REG_BASE + 0x02f) #define AR9170_USB_REG_EP_MAP (AR9170_USB_REG_BASE + 0x030) #define AR9170_USB_REG_EP1_MAP (AR9170_USB_REG_BASE + 0x030) @@ -581,6 +602,10 @@ #define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) #define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) + +#define AR9170_USB_REG_WAKE_UP (AR9170_USB_REG_BASE + 0x120) +#define AR9170_USB_WAKE_UP_WAKE BIT(0) + #define AR9170_USB_REG_CBUS_CTRL (AR9170_USB_REG_BASE + 0x1f0) #define AR9170_USB_CBUS_CTRL_BUFFER_END (BIT(1)) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 870df8c42622..ede3d7e5a048 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -662,6 +662,13 @@ init: goto unlock; } + if (ar->fw.tx_seq_table) { + err = carl9170_write_reg(ar, ar->fw.tx_seq_table + vif_id * 4, + 0); + if (err) + goto unlock; + } + unlock: if (err && (vif_id >= 0)) { vif_priv->active = false; @@ -1279,7 +1286,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + u16 tid, u16 *ssn, u8 buf_size) { struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 6cc58e052d10..6f41e21d3a1c 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -862,6 +862,9 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) if (unlikely(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)) txc->s.misc |= CARL9170_TX_SUPER_MISC_CAB; + if (unlikely(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) + txc->s.misc |= CARL9170_TX_SUPER_MISC_ASSIGN_SEQ; + if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) txc->s.misc |= CARL9170_TX_SUPER_MISC_FILL_IN_TSF; diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index ee0f84f2a2f6..15095c035169 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H -#define CARL9170FW_VERSION_YEAR 10 -#define CARL9170FW_VERSION_MONTH 10 -#define CARL9170FW_VERSION_DAY 29 -#define CARL9170FW_VERSION_GIT "1.9.0" +#define CARL9170FW_VERSION_YEAR 11 +#define CARL9170FW_VERSION_MONTH 1 +#define CARL9170FW_VERSION_DAY 22 +#define CARL9170FW_VERSION_GIT "1.9.2" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/drivers/net/wireless/ath/carl9170/wlan.h b/drivers/net/wireless/ath/carl9170/wlan.h index 24d63b583b6b..9e1324b67e08 100644 --- a/drivers/net/wireless/ath/carl9170/wlan.h +++ b/drivers/net/wireless/ath/carl9170/wlan.h @@ -251,7 +251,7 @@ struct carl9170_tx_superdesc { u8 ampdu_commit_factor:1; u8 ampdu_unused_bit:1; u8 queue:2; - u8 reserved:1; + u8 assign_seq:1; u8 vif_id:3; u8 fill_in_tsf:1; u8 cab:1; @@ -299,6 +299,7 @@ struct _ar9170_tx_hwdesc { #define CARL9170_TX_SUPER_MISC_QUEUE 0x3 #define CARL9170_TX_SUPER_MISC_QUEUE_S 0 +#define CARL9170_TX_SUPER_MISC_ASSIGN_SEQ 0x4 #define CARL9170_TX_SUPER_MISC_VIF_ID 0x38 #define CARL9170_TX_SUPER_MISC_VIF_ID_S 3 #define CARL9170_TX_SUPER_MISC_FILL_IN_TSF 0x40 @@ -413,6 +414,23 @@ enum ar9170_txq { __AR9170_NUM_TXQ, }; +/* + * This is an workaround for several undocumented bugs. + * Don't mess with the QoS/AC <-> HW Queue map, if you don't + * know what you are doing. + * + * Known problems [hardware]: + * * The MAC does not aggregate frames on anything other + * than the first HW queue. + * * when an AMPDU is placed [in the first hw queue] and + * additional frames are already queued on a different + * hw queue, the MAC will ALWAYS freeze. + * + * In a nutshell: The hardware can either do QoS or + * Aggregation but not both at the same time. As a + * result, this makes the device pretty much useless + * for any serious 802.11n setup. + */ static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 }; #define AR9170_TXQ_DEPTH 32 diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 2b14775e6bc6..f828f294ba89 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -158,6 +158,13 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) } } +bool ath_is_49ghz_allowed(u16 regdomain) +{ + /* possibly more */ + return regdomain == MKK9_MKKC; +} +EXPORT_SYMBOL(ath_is_49ghz_allowed); + /* Frequency is one where radar detection is required */ static bool ath_is_radar_freq(u16 center_freq) { diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 345dd9721b41..172f63f671cf 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -250,6 +250,7 @@ enum CountryCode { }; bool ath_is_world_regd(struct ath_regulatory *reg); +bool ath_is_49ghz_allowed(u16 redomain); int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, int (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)); |