aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c210
1 files changed, 121 insertions, 89 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index c8c658bfcf9d..6789c5dfcc76 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -227,9 +227,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
227static void ath5k_remove_interface(struct ieee80211_hw *hw, 227static void ath5k_remove_interface(struct ieee80211_hw *hw,
228 struct ieee80211_if_init_conf *conf); 228 struct ieee80211_if_init_conf *conf);
229static int ath5k_config(struct ieee80211_hw *hw, u32 changed); 229static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
230static int ath5k_config_interface(struct ieee80211_hw *hw,
231 struct ieee80211_vif *vif,
232 struct ieee80211_if_conf *conf);
233static void ath5k_configure_filter(struct ieee80211_hw *hw, 230static void ath5k_configure_filter(struct ieee80211_hw *hw,
234 unsigned int changed_flags, 231 unsigned int changed_flags,
235 unsigned int *new_flags, 232 unsigned int *new_flags,
@@ -259,7 +256,6 @@ static const struct ieee80211_ops ath5k_hw_ops = {
259 .add_interface = ath5k_add_interface, 256 .add_interface = ath5k_add_interface,
260 .remove_interface = ath5k_remove_interface, 257 .remove_interface = ath5k_remove_interface,
261 .config = ath5k_config, 258 .config = ath5k_config,
262 .config_interface = ath5k_config_interface,
263 .configure_filter = ath5k_configure_filter, 259 .configure_filter = ath5k_configure_filter,
264 .set_key = ath5k_set_key, 260 .set_key = ath5k_set_key,
265 .get_stats = ath5k_get_stats, 261 .get_stats = ath5k_get_stats,
@@ -520,6 +516,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
520 IEEE80211_HW_NOISE_DBM; 516 IEEE80211_HW_NOISE_DBM;
521 517
522 hw->wiphy->interface_modes = 518 hw->wiphy->interface_modes =
519 BIT(NL80211_IFTYPE_AP) |
523 BIT(NL80211_IFTYPE_STATION) | 520 BIT(NL80211_IFTYPE_STATION) |
524 BIT(NL80211_IFTYPE_ADHOC) | 521 BIT(NL80211_IFTYPE_ADHOC) |
525 BIT(NL80211_IFTYPE_MESH_POINT); 522 BIT(NL80211_IFTYPE_MESH_POINT);
@@ -1282,7 +1279,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
1282 ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, 1279 ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
1283 (sc->power_level * 2), 1280 (sc->power_level * 2),
1284 hw_rate, 1281 hw_rate,
1285 info->control.rates[0].count, keyidx, 0, flags, 1282 info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
1286 cts_rate, duration); 1283 cts_rate, duration);
1287 if (ret) 1284 if (ret)
1288 goto err_unmap; 1285 goto err_unmap;
@@ -1742,35 +1739,6 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
1742 } 1739 }
1743} 1740}
1744 1741
1745static void ath5k_tasklet_beacon(unsigned long data)
1746{
1747 struct ath5k_softc *sc = (struct ath5k_softc *) data;
1748
1749 /*
1750 * Software beacon alert--time to send a beacon.
1751 *
1752 * In IBSS mode we use this interrupt just to
1753 * keep track of the next TBTT (target beacon
1754 * transmission time) in order to detect wether
1755 * automatic TSF updates happened.
1756 */
1757 if (sc->opmode == NL80211_IFTYPE_ADHOC) {
1758 /* XXX: only if VEOL suppported */
1759 u64 tsf = ath5k_hw_get_tsf64(sc->ah);
1760 sc->nexttbtt += sc->bintval;
1761 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
1762 "SWBA nexttbtt: %x hw_tu: %x "
1763 "TSF: %llx\n",
1764 sc->nexttbtt,
1765 TSF_TO_TU(tsf),
1766 (unsigned long long) tsf);
1767 } else {
1768 spin_lock(&sc->block);
1769 ath5k_beacon_send(sc);
1770 spin_unlock(&sc->block);
1771 }
1772}
1773
1774static void 1742static void
1775ath5k_tasklet_rx(unsigned long data) 1743ath5k_tasklet_rx(unsigned long data)
1776{ 1744{
@@ -2041,7 +2009,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
2041 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 2009 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2042 struct ath5k_hw *ah = sc->ah; 2010 struct ath5k_hw *ah = sc->ah;
2043 struct ath5k_desc *ds; 2011 struct ath5k_desc *ds;
2044 int ret, antenna = 0; 2012 int ret = 0;
2013 u8 antenna;
2045 u32 flags; 2014 u32 flags;
2046 2015
2047 bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, 2016 bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
@@ -2055,23 +2024,35 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
2055 } 2024 }
2056 2025
2057 ds = bf->desc; 2026 ds = bf->desc;
2027 antenna = ah->ah_tx_ant;
2058 2028
2059 flags = AR5K_TXDESC_NOACK; 2029 flags = AR5K_TXDESC_NOACK;
2060 if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { 2030 if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) {
2061 ds->ds_link = bf->daddr; /* self-linked */ 2031 ds->ds_link = bf->daddr; /* self-linked */
2062 flags |= AR5K_TXDESC_VEOL; 2032 flags |= AR5K_TXDESC_VEOL;
2063 /* 2033 } else
2064 * Let hardware handle antenna switching if txantenna is not set
2065 */
2066 } else {
2067 ds->ds_link = 0; 2034 ds->ds_link = 0;
2068 /* 2035
2069 * Switch antenna every 4 beacons if txantenna is not set 2036 /*
2070 * XXX assumes two antennas 2037 * If we use multiple antennas on AP and use
2071 */ 2038 * the Sectored AP scenario, switch antenna every
2072 if (antenna == 0) 2039 * 4 beacons to make sure everybody hears our AP.
2073 antenna = sc->bsent & 4 ? 2 : 1; 2040 * When a client tries to associate, hw will keep
2074 } 2041 * track of the tx antenna to be used for this client
2042 * automaticaly, based on ACKed packets.
2043 *
2044 * Note: AP still listens and transmits RTS on the
2045 * default antenna which is supposed to be an omni.
2046 *
2047 * Note2: On sectored scenarios it's possible to have
2048 * multiple antennas (1omni -the default- and 14 sectors)
2049 * so if we choose to actually support this mode we need
2050 * to allow user to set how many antennas we have and tweak
2051 * the code below to send beacons on all of them.
2052 */
2053 if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP)
2054 antenna = sc->bsent & 4 ? 2 : 1;
2055
2075 2056
2076 /* FIXME: If we are in g mode and rate is a CCK rate 2057 /* FIXME: If we are in g mode and rate is a CCK rate
2077 * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta 2058 * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta
@@ -2124,7 +2105,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
2124 sc->bmisscount++; 2105 sc->bmisscount++;
2125 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, 2106 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
2126 "missed %u consecutive beacons\n", sc->bmisscount); 2107 "missed %u consecutive beacons\n", sc->bmisscount);
2127 if (sc->bmisscount > 3) { /* NB: 3 is a guess */ 2108 if (sc->bmisscount > 10) { /* NB: 10 is a guess */
2128 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, 2109 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
2129 "stuck beacon time (%u missed)\n", 2110 "stuck beacon time (%u missed)\n",
2130 sc->bmisscount); 2111 sc->bmisscount);
@@ -2145,10 +2126,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
2145 * are still pending on the queue. 2126 * are still pending on the queue.
2146 */ 2127 */
2147 if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { 2128 if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
2148 ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); 2129 ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq);
2149 /* NB: hw still stops DMA, so proceed */ 2130 /* NB: hw still stops DMA, so proceed */
2150 } 2131 }
2151 2132
2133 /* Note: Beacon buffer is updated on beacon_update when mac80211
2134 * calls config_interface */
2152 ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); 2135 ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
2153 ath5k_hw_start_tx_dma(ah, sc->bhalq); 2136 ath5k_hw_start_tx_dma(ah, sc->bhalq);
2154 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", 2137 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
@@ -2305,6 +2288,35 @@ ath5k_beacon_config(struct ath5k_softc *sc)
2305 ath5k_hw_set_imr(ah, sc->imask); 2288 ath5k_hw_set_imr(ah, sc->imask);
2306} 2289}
2307 2290
2291static void ath5k_tasklet_beacon(unsigned long data)
2292{
2293 struct ath5k_softc *sc = (struct ath5k_softc *) data;
2294
2295 /*
2296 * Software beacon alert--time to send a beacon.
2297 *
2298 * In IBSS mode we use this interrupt just to
2299 * keep track of the next TBTT (target beacon
2300 * transmission time) in order to detect wether
2301 * automatic TSF updates happened.
2302 */
2303 if (sc->opmode == NL80211_IFTYPE_ADHOC) {
2304 /* XXX: only if VEOL suppported */
2305 u64 tsf = ath5k_hw_get_tsf64(sc->ah);
2306 sc->nexttbtt += sc->bintval;
2307 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
2308 "SWBA nexttbtt: %x hw_tu: %x "
2309 "TSF: %llx\n",
2310 sc->nexttbtt,
2311 TSF_TO_TU(tsf),
2312 (unsigned long long) tsf);
2313 } else {
2314 spin_lock(&sc->block);
2315 ath5k_beacon_send(sc);
2316 spin_unlock(&sc->block);
2317 }
2318}
2319
2308 2320
2309/********************\ 2321/********************\
2310* Interrupt handling * 2322* Interrupt handling *
@@ -2509,7 +2521,7 @@ ath5k_intr(int irq, void *dev_id)
2509 ath5k_hw_update_mib_counters(ah, &sc->ll_stats); 2521 ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
2510 } 2522 }
2511 } 2523 }
2512 } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); 2524 } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
2513 2525
2514 if (unlikely(!counter)) 2526 if (unlikely(!counter))
2515 ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); 2527 ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
@@ -2751,56 +2763,47 @@ static int
2751ath5k_config(struct ieee80211_hw *hw, u32 changed) 2763ath5k_config(struct ieee80211_hw *hw, u32 changed)
2752{ 2764{
2753 struct ath5k_softc *sc = hw->priv; 2765 struct ath5k_softc *sc = hw->priv;
2766 struct ath5k_hw *ah = sc->ah;
2754 struct ieee80211_conf *conf = &hw->conf; 2767 struct ieee80211_conf *conf = &hw->conf;
2755 int ret; 2768 int ret = 0;
2756 2769
2757 mutex_lock(&sc->lock); 2770 mutex_lock(&sc->lock);
2758 2771
2759 sc->bintval = conf->beacon_int; 2772 sc->bintval = conf->beacon_int;
2760 sc->power_level = conf->power_level;
2761 2773
2762 ret = ath5k_chan_set(sc, conf->channel); 2774 ret = ath5k_chan_set(sc, conf->channel);
2775 if (ret < 0)
2776 return ret;
2763 2777
2764 mutex_unlock(&sc->lock); 2778 if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
2765 return ret; 2779 (sc->power_level != conf->power_level)) {
2766} 2780 sc->power_level = conf->power_level;
2767
2768static int
2769ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
2770 struct ieee80211_if_conf *conf)
2771{
2772 struct ath5k_softc *sc = hw->priv;
2773 struct ath5k_hw *ah = sc->ah;
2774 int ret = 0;
2775 2781
2776 mutex_lock(&sc->lock); 2782 /* Half dB steps */
2777 if (sc->vif != vif) { 2783 ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
2778 ret = -EIO;
2779 goto unlock;
2780 }
2781 if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
2782 /* Cache for later use during resets */
2783 memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN);
2784 /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
2785 * a clean way of letting us retrieve this yet. */
2786 ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
2787 mmiowb();
2788 }
2789 if (conf->changed & IEEE80211_IFCC_BEACON &&
2790 (vif->type == NL80211_IFTYPE_ADHOC ||
2791 vif->type == NL80211_IFTYPE_MESH_POINT ||
2792 vif->type == NL80211_IFTYPE_AP)) {
2793 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
2794 if (!beacon) {
2795 ret = -ENOMEM;
2796 goto unlock;
2797 }
2798 ath5k_beacon_update(sc, beacon);
2799 } 2784 }
2800 2785
2801unlock: 2786 /* TODO:
2787 * 1) Move this on config_interface and handle each case
2788 * separately eg. when we have only one STA vif, use
2789 * AR5K_ANTMODE_SINGLE_AP
2790 *
2791 * 2) Allow the user to change antenna mode eg. when only
2792 * one antenna is present
2793 *
2794 * 3) Allow the user to set default/tx antenna when possible
2795 *
2796 * 4) Default mode should handle 90% of the cases, together
2797 * with fixed a/b and single AP modes we should be able to
2798 * handle 99%. Sectored modes are extreme cases and i still
2799 * haven't found a usage for them. If we decide to support them,
2800 * then we must allow the user to set how many tx antennas we
2801 * have available
2802 */
2803 ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
2804
2802 mutex_unlock(&sc->lock); 2805 mutex_unlock(&sc->lock);
2803 return ret; 2806 return 0;
2804} 2807}
2805 2808
2806#define SUPPORTED_FIF_FLAGS \ 2809#define SUPPORTED_FIF_FLAGS \
@@ -3083,11 +3086,40 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
3083 u32 changes) 3086 u32 changes)
3084{ 3087{
3085 struct ath5k_softc *sc = hw->priv; 3088 struct ath5k_softc *sc = hw->priv;
3089 struct ath5k_hw *ah = sc->ah;
3090
3091 mutex_lock(&sc->lock);
3092 if (WARN_ON(sc->vif != vif))
3093 goto unlock;
3094
3095 if (changes & BSS_CHANGED_BSSID) {
3096 /* Cache for later use during resets */
3097 memcpy(ah->ah_bssid, bss_conf->bssid, ETH_ALEN);
3098 /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
3099 * a clean way of letting us retrieve this yet. */
3100 ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
3101 mmiowb();
3102 }
3103
3104 if (changes & BSS_CHANGED_BEACON_INT)
3105 sc->bintval = bss_conf->beacon_int;
3106
3086 if (changes & BSS_CHANGED_ASSOC) { 3107 if (changes & BSS_CHANGED_ASSOC) {
3087 mutex_lock(&sc->lock);
3088 sc->assoc = bss_conf->assoc; 3108 sc->assoc = bss_conf->assoc;
3089 if (sc->opmode == NL80211_IFTYPE_STATION) 3109 if (sc->opmode == NL80211_IFTYPE_STATION)
3090 set_beacon_filter(hw, sc->assoc); 3110 set_beacon_filter(hw, sc->assoc);
3091 mutex_unlock(&sc->lock);
3092 } 3111 }
3112
3113 if (changes & BSS_CHANGED_BEACON &&
3114 (vif->type == NL80211_IFTYPE_ADHOC ||
3115 vif->type == NL80211_IFTYPE_MESH_POINT ||
3116 vif->type == NL80211_IFTYPE_AP)) {
3117 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
3118
3119 if (beacon)
3120 ath5k_beacon_update(sc, beacon);
3121 }
3122
3123 unlock:
3124 mutex_unlock(&sc->lock);
3093} 3125}