diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 322 |
1 files changed, 216 insertions, 106 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index d366dadcf86..4b18434ba69 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -40,6 +40,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -54,10 +56,12 @@ #include <linux/etherdevice.h> #include <linux/nl80211.h> +#include <net/cfg80211.h> #include <net/ieee80211_radiotap.h> #include <asm/unaligned.h> +#include <net/mac80211.h> #include "base.h" #include "reg.h" #include "debug.h" @@ -72,15 +76,11 @@ bool ath5k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -static bool modparam_all_channels; -module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); -MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); - static bool modparam_fastchanswitch; module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); -static int ath5k_modparam_no_hw_rfkill_switch; +static bool ath5k_modparam_no_hw_rfkill_switch; module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch, bool, S_IRUGO); MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state"); @@ -166,28 +166,36 @@ static const struct ieee80211_rate ath5k_rates[] = { .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 60, .hw_value = ATH5K_RATE_CODE_6M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 90, .hw_value = ATH5K_RATE_CODE_9M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 120, .hw_value = ATH5K_RATE_CODE_12M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 180, .hw_value = ATH5K_RATE_CODE_18M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 240, .hw_value = ATH5K_RATE_CODE_24M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 360, .hw_value = ATH5K_RATE_CODE_36M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 480, .hw_value = ATH5K_RATE_CODE_48M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, { .bitrate = 540, .hw_value = ATH5K_RATE_CODE_54M, - .flags = 0 }, + .flags = IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ }, }; static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) @@ -242,13 +250,14 @@ static const struct ath_ops ath5k_common_ops = { * Driver Initialization * \***********************/ -static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +static void ath5k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath5k_hw *ah = hw->priv; struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); - return ath_reg_notifier_apply(wiphy, request, regulatory); + ath_reg_notifier_apply(wiphy, request, regulatory); } /********************\ @@ -256,8 +265,15 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re \********************/ /* - * Returns true for the channel numbers used without all_channels modparam. + * Returns true for the channel numbers used. */ +#ifdef CONFIG_ATH5K_TEST_CHANNELS +static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) +{ + return true; +} + +#else static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) { if (band == IEEE80211_BAND_2GHZ && chan <= 14) @@ -274,6 +290,7 @@ static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) /* 802.11j 4.9GHz (20MHz) */ (chan == 184 || chan == 188 || chan == 192 || chan == 196)); } +#endif static unsigned int ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, @@ -314,8 +331,7 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, if (!ath5k_channel_ok(ah, &channels[count])) continue; - if (!modparam_all_channels && - !ath5k_is_standard_channel(ch, band)) + if (!ath5k_is_standard_channel(ch, band)) continue; count++; @@ -428,11 +444,27 @@ ath5k_setup_bands(struct ieee80211_hw *hw) * Called with ah->lock. */ int -ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan) +ath5k_chan_set(struct ath5k_hw *ah, struct cfg80211_chan_def *chandef) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "channel set, resetting (%u -> %u MHz)\n", - ah->curchan->center_freq, chan->center_freq); + ah->curchan->center_freq, chandef->chan->center_freq); + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_20_NOHT: + ah->ah_bwmode = AR5K_BWMODE_DEFAULT; + break; + case NL80211_CHAN_WIDTH_5: + ah->ah_bwmode = AR5K_BWMODE_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + ah->ah_bwmode = AR5K_BWMODE_10MHZ; + break; + default: + WARN_ON(1); + return -EINVAL; + } /* * To switch channels clear any pending DMA operations; @@ -440,7 +472,7 @@ ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan) * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ - return ath5k_reset(ah, chan, true); + return ath5k_reset(ah, chandef->chan, true); } void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) @@ -460,7 +492,7 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) } if (iter_data->need_set_hw_addr && iter_data->hw_macaddr) - if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0) + if (ether_addr_equal(iter_data->hw_macaddr, mac)) iter_data->need_set_hw_addr = false; if (!iter_data->any_assoc) { @@ -506,8 +538,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, ath5k_vif_iter(&iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN); ah->opmode = iter_data.opmode; @@ -659,9 +692,46 @@ static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) return htype; } +static struct ieee80211_rate * +ath5k_get_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *info, + struct ath5k_buf *bf, int idx) +{ + /* + * convert a ieee80211_tx_rate RC-table entry to + * the respective ieee80211_rate struct + */ + if (bf->rates[idx].idx < 0) { + return NULL; + } + + return &hw->wiphy->bands[info->band]->bitrates[ bf->rates[idx].idx ]; +} + +static u16 +ath5k_get_rate_hw_value(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *info, + struct ath5k_buf *bf, int idx) +{ + struct ieee80211_rate *rate; + u16 hw_rate; + u8 rc_flags; + + rate = ath5k_get_rate(hw, info, bf, idx); + if (!rate) + return 0; + + rc_flags = bf->rates[idx].flags; + hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? + rate->hw_value_short : rate->hw_value; + + return hw_rate; +} + static int ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, - struct ath5k_txq *txq, int padsize) + struct ath5k_txq *txq, int padsize, + struct ieee80211_tx_control *control) { struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; @@ -681,7 +751,14 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len, DMA_TO_DEVICE); - rate = ieee80211_get_tx_rate(ah->hw, info); + if (dma_mapping_error(ah->dev, bf->skbaddr)) + return -ENOSPC; + + ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates, + ARRAY_SIZE(bf->rates)); + + rate = ath5k_get_rate(ah->hw, info, bf, 0); + if (!rate) { ret = -EINVAL; goto err_unmap; @@ -691,8 +768,8 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, flags |= AR5K_TXDESC_NOACK; rc_flags = info->control.rates[0].flags; - hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? - rate->hw_value_short : rate->hw_value; + + hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0); pktlen = skb->len; @@ -715,12 +792,13 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, duration = le16_to_cpu(ieee80211_ctstoself_duration(ah->hw, info->control.vif, pktlen, info)); } + ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), padsize, get_hw_packet_type(skb), - (ah->power_level * 2), + (ah->ah_txpower.txp_requested * 2), hw_rate, - info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, + bf->rates[0].count, keyidx, ah->ah_tx_ant, flags, cts_rate, duration); if (ret) goto err_unmap; @@ -729,13 +807,15 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, if (ah->ah_capabilities.cap_has_mrr_support) { memset(mrr_rate, 0, sizeof(mrr_rate)); memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i < 3; i++) { - rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); + + rate = ath5k_get_rate(ah->hw, info, bf, i); if (!rate) break; - mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.rates[i + 1].count; + mrr_rate[i] = ath5k_get_rate_hw_value(ah->hw, info, bf, i); + mrr_tries[i] = bf->rates[i].count; } ath5k_hw_setup_mrr_tx_desc(ah, ds, @@ -843,7 +923,7 @@ ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf) return; dma_unmap_single(ah->dev, bf->skbaddr, bf->skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(bf->skb); + ieee80211_free_txskb(ah->hw, bf->skb); bf->skb = NULL; bf->skbaddr = 0; bf->desc->ds_data = 0; @@ -1043,11 +1123,11 @@ ath5k_drain_tx_buffs(struct ath5k_hw *ah) ath5k_txbuf_free_skb(ah, bf); - spin_lock_bh(&ah->txbuflock); + spin_lock(&ah->txbuflock); list_move_tail(&bf->list, &ah->txbuf); ah->txbuf_len++; txq->txq_len--; - spin_unlock_bh(&ah->txbuflock); + spin_unlock(&ah->txbuflock); } txq->link = NULL; txq->txq_poll_mark = false; @@ -1161,14 +1241,11 @@ static void ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb, struct ieee80211_rx_status *rxs) { - struct ath_common *common = ath5k_hw_common(ah); u64 tsf, bc_tstamp; u32 hw_tu; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - if (ieee80211_is_beacon(mgmt->frame_control) && - le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { + if (le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS) { /* * Received an IBSS beacon with the same BSSID. Hardware *must* * have updated the local TSF. We have to work around various @@ -1224,23 +1301,6 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb, } } -static void -ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi) -{ - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - struct ath_common *common = ath5k_hw_common(ah); - - /* only beacons from our BSSID */ - if (!ieee80211_is_beacon(mgmt->frame_control) || - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) - return; - - ewma_add(&ah->ah_beacon_rssi_avg, rssi); - - /* in IBSS mode we should keep RSSI statistics per neighbour */ - /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ -} - /* * Compute padding position. skb must contain an IEEE 802.11 frame */ @@ -1313,6 +1373,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, struct ath5k_rx_status *rs) { struct ieee80211_rx_status *rxs; + struct ath_common *common = ath5k_hw_common(ah); ath5k_remove_padding(skb); @@ -1330,20 +1391,9 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, * 15bit only. that means TSF extension has to be done within * 32768usec (about 32ms). it might be necessary to move this to * the interrupt handler, like it is done in madwifi. - * - * Unfortunately we don't know when the hardware takes the rx - * timestamp (beginning of phy frame, data frame, end of rx?). - * The only thing we know is that it is hardware specific... - * On AR5213 it seems the rx timestamp is at the end of the - * frame, but I'm not sure. - * - * NOTE: mac80211 defines mactime at the beginning of the first - * data symbol. Since we don't have any time references it's - * impossible to comply to that. This affects IBSS merge only - * right now, so it's not too bad... */ rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp); - rxs->flag |= RX_FLAG_MACTIME_MPDU; + rxs->flag |= RX_FLAG_MACTIME_END; rxs->freq = ah->curchan->center_freq; rxs->band = ah->curchan->band; @@ -1359,6 +1409,16 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, rxs->rate_idx = ath5k_hw_to_driver_rix(ah, rs->rs_rate); rxs->flag |= ath5k_rx_decrypted(ah, skb, rs); + switch (ah->ah_bwmode) { + case AR5K_BWMODE_5MHZ: + rxs->flag |= RX_FLAG_5MHZ; + break; + case AR5K_BWMODE_10MHZ: + rxs->flag |= RX_FLAG_10MHZ; + break; + default: + break; + } if (rxs->rate_idx >= 0 && rs->rs_rate == ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short) @@ -1366,11 +1426,13 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, trace_ath5k_rx(ah, skb); - ath5k_update_beacon_rssi(ah, skb, rs->rs_rssi); + if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) { + ewma_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); - /* check beacons in IBSS mode */ - if (ah->opmode == NL80211_IFTYPE_ADHOC) - ath5k_check_ibss_tsf(ah, skb, rxs); + /* check beacons in IBSS mode */ + if (ah->opmode == NL80211_IFTYPE_ADHOC) + ath5k_check_ibss_tsf(ah, skb, rxs); + } ieee80211_rx(ah->hw, skb); } @@ -1519,7 +1581,7 @@ unlock: void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath5k_txq *txq) + struct ath5k_txq *txq, struct ieee80211_tx_control *control) { struct ath5k_hw *ah = hw->priv; struct ath5k_buf *bf; @@ -1559,7 +1621,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, bf->skb = skb; - if (ath5k_txbuf_setup(ah, bf, txq, padsize)) { + if (ath5k_txbuf_setup(ah, bf, txq, padsize, control)) { bf->skb = NULL; spin_lock_irqsave(&ah->txbuflock, flags); list_add_tail(&bf->list, &ah->txbuf); @@ -1570,21 +1632,26 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, return; drop_packet: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb, - struct ath5k_txq *txq, struct ath5k_tx_status *ts) + struct ath5k_txq *txq, struct ath5k_tx_status *ts, + struct ath5k_buf *bf) { struct ieee80211_tx_info *info; u8 tries[3]; int i; + int size = 0; ah->stats.tx_all_count++; ah->stats.tx_bytes_count += skb->len; info = IEEE80211_SKB_CB(skb); + size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates)); + memcpy(info->status.rates, bf->rates, size); + tries[0] = info->status.rates[0].count; tries[1] = info->status.rates[1].count; tries[2] = info->status.rates[2].count; @@ -1667,7 +1734,7 @@ ath5k_tx_processq(struct ath5k_hw *ah, struct ath5k_txq *txq) dma_unmap_single(ah->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE); - ath5k_tx_frame_completed(ah, skb, txq, &ts); + ath5k_tx_frame_completed(ah, skb, txq, &ts, bf); } /* @@ -1773,7 +1840,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf) ds->ds_data = bf->skbaddr; ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), padsize, - AR5K_PKT_TYPE_BEACON, (ah->power_level * 2), + AR5K_PKT_TYPE_BEACON, + (ah->ah_txpower.txp_requested * 2), ieee80211_get_tx_rate(ah->hw, info)->hw_value, 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); @@ -1798,7 +1866,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int ret; struct ath5k_hw *ah = hw->priv; - struct ath5k_vif *avf = (void *)vif->drv_priv; + struct ath5k_vif *avf; struct sk_buff *skb; if (WARN_ON(!vif)) { @@ -1813,6 +1881,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } + avf = (void *)vif->drv_priv; ath5k_txbuf_free_skb(ah, avf->bbuf); avf->bbuf->skb = skb; ret = ath5k_beacon_setup(ah, avf->bbuf); @@ -1867,7 +1936,8 @@ ath5k_beacon_send(struct ath5k_hw *ah) ah->bmisscount = 0; } - if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) || + if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + + ah->num_mesh_vifs > 1) || ah->opmode == NL80211_IFTYPE_MESH_POINT) { u64 tsf = ath5k_hw_get_tsf64(ah); u32 tsftu = TSF_TO_TU(tsf); @@ -1918,7 +1988,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) skb = ieee80211_get_buffered_bc(ah->hw, vif); while (skb) { - ath5k_tx_queue(ah->hw, skb, ah->cabq); + ath5k_tx_queue(ah->hw, skb, ah->cabq, NULL); if (ah->cabq->txq_len >= ah->cabq->txq_max) break; @@ -1952,7 +2022,8 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) u64 hw_tsf; intval = ah->bintval & AR5K_BEACON_PERIOD; - if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) { + if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + + ah->num_mesh_vifs > 1) { intval /= ATH_BCBUF; /* staggered multi-bss beacons */ if (intval < 15) ATH5K_WARN(ah, "intval %u is too low, min 15\n", @@ -2049,9 +2120,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) void ath5k_beacon_config(struct ath5k_hw *ah) { - unsigned long flags; - - spin_lock_irqsave(&ah->block, flags); + spin_lock_bh(&ah->block); ah->bmisscount = 0; ah->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); @@ -2078,7 +2147,7 @@ ath5k_beacon_config(struct ath5k_hw *ah) ath5k_hw_set_imr(ah, ah->imask); mmiowb(); - spin_unlock_irqrestore(&ah->block, flags); + spin_unlock_bh(&ah->block); } static void ath5k_tasklet_beacon(unsigned long data) @@ -2330,15 +2399,6 @@ ath5k_calibrate_work(struct work_struct *work) "got new rfgain, resetting\n"); ieee80211_queue_work(ah->hw, &ah->reset_work); } - - /* TODO: On full calibration we should stop TX here, - * so that it doesn't interfere (mostly due to gain_f - * calibration that messes with tx packets -see phy.c). - * - * NOTE: Stopping the queues from above is not enough - * to stop TX but saves us from disconecting (at least - * we don't lose packets). */ - ieee80211_stop_queues(ah->hw); } else ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT; @@ -2353,10 +2413,9 @@ ath5k_calibrate_work(struct work_struct *work) ah->curchan->center_freq)); /* Clear calibration flags */ - if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) { - ieee80211_wake_queues(ah->hw); + if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; - } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) + else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT; } @@ -2381,6 +2440,9 @@ ath5k_tx_complete_poll_work(struct work_struct *work) int i; bool needreset = false; + if (!test_bit(ATH_STAT_STARTED, ah->status)) + return; + mutex_lock(&ah->lock); for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) { @@ -2421,7 +2483,23 @@ ath5k_tx_complete_poll_work(struct work_struct *work) * Initialization routines * \*************************/ -int __devinit +static const struct ieee80211_iface_limit if_limits[] = { + { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, + { .max = 4, .types = +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) }, +}; + +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 2048, + .num_different_channels = 1, +}; + +int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = ah->hw; @@ -2434,7 +2512,9 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_REPORTS_TX_ACK_STATUS; + IEEE80211_HW_MFP_CAPABLE | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_SUPPORTS_RC_TABLE; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | @@ -2442,12 +2522,19 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); + hw->wiphy->iface_combinations = &if_comb; + hw->wiphy->n_iface_combinations = 1; + + /* SW support for IBSS_RSN is provided by mac80211 */ + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; + /* both antennas can be configured as RX or TX */ hw->wiphy->available_antennas_tx = 0x3; hw->wiphy->available_antennas_rx = 0x3; hw->extra_tx_headroom = 2; - hw->channel_change_time = 5000; /* * Mark the device as detached to avoid processing @@ -2628,7 +2715,7 @@ int ath5k_start(struct ieee80211_hw *hw) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - ah->curchan = ah->hw->conf.channel; + ah->curchan = ah->hw->conf.chandef.chan; ah->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL @@ -2665,6 +2752,7 @@ done: mmiowb(); mutex_unlock(&ah->lock); + set_bit(ATH_STAT_STARTED, ah->status); ieee80211_queue_delayed_work(ah->hw, &ah->tx_complete_work, msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT)); @@ -2726,6 +2814,7 @@ void ath5k_stop(struct ieee80211_hw *hw) ath5k_stop_tasklets(ah); + clear_bit(ATH_STAT_STARTED, ah->status); cancel_delayed_work_sync(&ah->tx_complete_work); if (!ath5k_modparam_no_hw_rfkill_switch) @@ -2840,7 +2929,7 @@ static void ath5k_reset_work(struct work_struct *work) mutex_unlock(&ah->lock); } -static int __devinit +static int ath5k_init(struct ieee80211_hw *hw) { @@ -3025,8 +3114,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah) iter_data.need_set_hw_addr = false; iter_data.found_active = true; - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); return iter_data.any_assoc; } @@ -3043,3 +3133,23 @@ ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable) ath5k_hw_set_rx_filter(ah, rfilt); ah->filter_flags = rfilt; } + +void _ath5k_printk(const struct ath5k_hw *ah, const char *level, + const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (ah && ah->hw) + printk("%s" pr_fmt("%s: %pV"), + level, wiphy_name(ah->hw->wiphy), &vaf); + else + printk("%s" pr_fmt("%pV"), level, &vaf); + + va_end(args); +} |
