aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorBruno Randolf <bruno@thinktube.com>2008-01-19 04:18:21 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:10:52 -0500
commit036cd1ec038f7e3a36740beaf2aa4a0d2e8ed2c1 (patch)
tree9a39d8523018a07d25ed672390d068402f52c65c /drivers/net
parent9804b98d57f9b3b02a8906b0b45f461ce0c08428 (diff)
ath5k: use SWBA to detect IBSS HW merges
use SWBA (software beacon alert) interrupts to keep track of the next beacon time und check if a HW merge (automatic TSF update) has happened on every received beacon with the same BSSID. this is necessary because the atheros hardware will silently update the local TSF in IBSS mode, but not its beacon timers. if the TSF is ahead of the beacon timers no beacons are sent until the timers wrap around (typically after about 1 minute). this solution is not very nice, since we have to look into every beacon, but there is apparently no other way to detect HW merges. drivers/net/wireless/ath5k/base.c: Changes-licensed-under: 3-Clause-BSD drivers/net/wireless/ath5k/base.h: Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bruno Randolf <bruno@thinktube.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath5k/base.c79
-rw-r--r--drivers/net/wireless/ath5k/base.h1
2 files changed, 67 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index c49061c51688..eb98284cba92 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1640,6 +1640,34 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
1640 return 0; 1640 return 0;
1641} 1641}
1642 1642
1643
1644static void
1645ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
1646{
1647 u32 hw_tu;
1648 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
1649
1650 if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) ==
1651 IEEE80211_FTYPE_MGMT &&
1652 (mgmt->frame_control & IEEE80211_FCTL_STYPE) ==
1653 IEEE80211_STYPE_BEACON &&
1654 mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
1655 memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
1656 /*
1657 * Received an IBSS beacon with the same BSSID. Hardware might
1658 * have updated the TSF, check if we need to update timers.
1659 */
1660 hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah));
1661 if (hw_tu >= sc->nexttbtt) {
1662 ath5k_beacon_update_timers(sc,
1663 mgmt->u.beacon.timestamp);
1664 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
1665 "detected HW merge from received beacon\n");
1666 }
1667 }
1668}
1669
1670
1643static void 1671static void
1644ath5k_tasklet_rx(unsigned long data) 1672ath5k_tasklet_rx(unsigned long data)
1645{ 1673{
@@ -1767,6 +1795,10 @@ accept:
1767 1795
1768 ath5k_debug_dump_skb(sc, skb, "RX ", 0); 1796 ath5k_debug_dump_skb(sc, skb, "RX ", 0);
1769 1797
1798 /* check beacons in IBSS mode */
1799 if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
1800 ath5k_check_ibss_hw_merge(sc, skb);
1801
1770 __ieee80211_rx(sc->hw, skb, &rxs); 1802 __ieee80211_rx(sc->hw, skb, &rxs);
1771 sc->led_rxrate = ds->ds_rxstat.rs_rate; 1803 sc->led_rxrate = ds->ds_rxstat.rs_rate;
1772 ath5k_led_event(sc, ATH_LED_RX); 1804 ath5k_led_event(sc, ATH_LED_RX);
@@ -2057,6 +2089,8 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
2057 } 2089 }
2058#undef FUDGE 2090#undef FUDGE
2059 2091
2092 sc->nexttbtt = nexttbtt;
2093
2060 intval |= AR5K_BEACON_ENA; 2094 intval |= AR5K_BEACON_ENA;
2061 ath5k_hw_init_beacon(ah, nexttbtt, intval); 2095 ath5k_hw_init_beacon(ah, nexttbtt, intval);
2062 2096
@@ -2084,16 +2118,19 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
2084} 2118}
2085 2119
2086 2120
2087/* 2121/**
2088 * Configure the beacon timers and interrupts based on the operating mode 2122 * ath5k_beacon_config - Configure the beacon queues and interrupts
2123 *
2124 * @sc: struct ath5k_softc pointer we are operating on
2089 * 2125 *
2090 * When operating in station mode we want to receive a BMISS interrupt when we 2126 * When operating in station mode we want to receive a BMISS interrupt when we
2091 * stop seeing beacons from the AP we've associated with so we can look for 2127 * stop seeing beacons from the AP we've associated with so we can look for
2092 * another AP to associate with. 2128 * another AP to associate with.
2093 * 2129 *
2094 * In IBSS mode we need to configure the beacon timers and use a self-linked tx 2130 * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
2095 * descriptor if possible. If the hardware cannot deal with that we enable SWBA 2131 * interrupts to detect HW merges only.
2096 * interrupts to send the beacons from the interrupt handler. 2132 *
2133 * AP mode is missing.
2097 */ 2134 */
2098static void 2135static void
2099ath5k_beacon_config(struct ath5k_softc *sc) 2136ath5k_beacon_config(struct ath5k_softc *sc)
@@ -2107,17 +2144,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
2107 sc->imask |= AR5K_INT_BMISS; 2144 sc->imask |= AR5K_INT_BMISS;
2108 } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { 2145 } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
2109 /* 2146 /*
2110 * In IBSS mode enable the beacon timers but only enable SWBA 2147 * In IBSS mode we use a self-linked tx descriptor and let the
2111 * interrupts if we need to manually prepare beacon frames. 2148 * hardware send the beacons automatically. We have to load it
2112 * Otherwise we use a self-linked tx descriptor and let the
2113 * hardware deal with things. In that case we have to load it
2114 * only once here. 2149 * only once here.
2150 * We use the SWBA interrupt only to keep track of the beacon
2151 * timers in order to detect HW merges (automatic TSF updates).
2115 */ 2152 */
2116 ath5k_beaconq_config(sc); 2153 ath5k_beaconq_config(sc);
2117 2154
2118 if (!ath5k_hw_hasveol(ah)) 2155 sc->imask |= AR5K_INT_SWBA;
2119 sc->imask |= AR5K_INT_SWBA; 2156
2120 else 2157 if (ath5k_hw_hasveol(ah))
2121 ath5k_beacon_send(sc); 2158 ath5k_beacon_send(sc);
2122 } 2159 }
2123 /* TODO else AP */ 2160 /* TODO else AP */
@@ -2320,8 +2357,24 @@ ath5k_intr(int irq, void *dev_id)
2320 * Handle beacon transmission directly; deferring 2357 * Handle beacon transmission directly; deferring
2321 * this is too slow to meet timing constraints 2358 * this is too slow to meet timing constraints
2322 * under load. 2359 * under load.
2360 *
2361 * In IBSS mode we use this interrupt just to
2362 * keep track of the next TBTT (target beacon
2363 * transmission time) in order to detect hardware
2364 * merges (TSF updates).
2323 */ 2365 */
2324 ath5k_beacon_send(sc); 2366 if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
2367 /* XXX: only if VEOL suppported */
2368 u64 tsf = ath5k_hw_get_tsf64(ah);
2369 sc->nexttbtt += sc->bintval;
2370 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
2371 "SWBA nexttbtt: %x hw_tu: %x "
2372 "TSF: %llx\n",
2373 sc->nexttbtt,
2374 TSF_TO_TU(tsf), tsf);
2375 } else {
2376 ath5k_beacon_send(sc);
2377 }
2325 } 2378 }
2326 if (status & AR5K_INT_RXEOL) { 2379 if (status & AR5K_INT_RXEOL) {
2327 /* 2380 /*
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 20c946926090..8287ae787f12 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -166,6 +166,7 @@ struct ath5k_softc {
166 bmisscount, /* missed beacon transmits */ 166 bmisscount, /* missed beacon transmits */
167 bintval, /* beacon interval in TU */ 167 bintval, /* beacon interval in TU */
168 bsent; 168 bsent;
169 unsigned int nexttbtt; /* next beacon time in TU */
169 170
170 struct timer_list calib_tim; /* calibration timer */ 171 struct timer_list calib_tim; /* calibration timer */
171}; 172};