aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorBruno Randolf <bruno@thinktube.com>2008-03-05 04:36:26 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-07 16:07:50 -0500
commit6ba81c2c989291c5893014f84805ce9d196778b0 (patch)
tree1b0c50597accf9c6a7fd7bd83358d587ffc119ed /drivers/net
parente14296cabac60806606b4ebc1a83ee4697876346 (diff)
ath5k: work around wrong beacon rx timestamp in IBSS mode
atheros hardware has a problem with the rx timestamp of some IBSS beacons when they caused a TSF update (they have the same BSSID). the rx timestamp is wrong especially if the beacon frames get bigger than 78 byte (at least on AR5213 and AR5414 hardware). in that case ath5k_extend_tsf() will assume a rs_tstamp overflow and give us a timestamp too far in the past which will cause mac80211 to merge IBSS on every beacon (which is not necessary since the BSSID already matches). but in this case we know that the HW must have synced to the beacons TSF and the rx timestamp must be later than that so we can adjust mactime accordingly. also rename the function to ath5k_check_ibss_tsf() and change comments, since "hw merge" is better described as a TSF update. drivers/net/wireless/ath5k/base.c: 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.c59
1 files changed, 45 insertions, 14 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 5eacc7cdd9e3..b5c0a0d7a81c 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1715,8 +1715,10 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
1715 1715
1716 1716
1717static void 1717static void
1718ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb) 1718ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
1719 struct ieee80211_rx_status *rxs)
1719{ 1720{
1721 u64 tsf, bc_tstamp;
1720 u32 hw_tu; 1722 u32 hw_tu;
1721 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 1723 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
1722 1724
@@ -1727,16 +1729,45 @@ ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
1727 le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && 1729 le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
1728 memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { 1730 memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
1729 /* 1731 /*
1730 * Received an IBSS beacon with the same BSSID. Hardware might 1732 * Received an IBSS beacon with the same BSSID. Hardware *must*
1731 * have updated the TSF, check if we need to update timers. 1733 * have updated the local TSF. We have to work around various
1734 * hardware bugs, though...
1732 */ 1735 */
1733 hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah)); 1736 tsf = ath5k_hw_get_tsf64(sc->ah);
1734 if (hw_tu >= sc->nexttbtt) { 1737 bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp);
1735 ath5k_beacon_update_timers(sc, 1738 hw_tu = TSF_TO_TU(tsf);
1736 le64_to_cpu(mgmt->u.beacon.timestamp)); 1739
1740 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
1741 "beacon %llx mactime %llx (diff %lld) tsf now %llx\n",
1742 bc_tstamp, rxs->mactime,
1743 (rxs->mactime - bc_tstamp), tsf);
1744
1745 /*
1746 * Sometimes the HW will give us a wrong tstamp in the rx
1747 * status, causing the timestamp extension to go wrong.
1748 * (This seems to happen especially with beacon frames bigger
1749 * than 78 byte (incl. FCS))
1750 * But we know that the receive timestamp must be later than the
1751 * timestamp of the beacon since HW must have synced to that.
1752 *
1753 * NOTE: here we assume mactime to be after the frame was
1754 * received, not like mac80211 which defines it at the start.
1755 */
1756 if (bc_tstamp > rxs->mactime) {
1737 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, 1757 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
1738 "detected HW merge from received beacon\n"); 1758 "fixing mactime from %llx to %llx\n",
1759 rxs->mactime, tsf);
1760 rxs->mactime = tsf;
1739 } 1761 }
1762
1763 /*
1764 * Local TSF might have moved higher than our beacon timers,
1765 * in that case we have to update them to continue sending
1766 * beacons. This also takes care of synchronizing beacon sending
1767 * times with other stations.
1768 */
1769 if (hw_tu >= sc->nexttbtt)
1770 ath5k_beacon_update_timers(sc, bc_tstamp);
1740 } 1771 }
1741} 1772}
1742 1773
@@ -1885,7 +1916,7 @@ accept:
1885 1916
1886 /* check beacons in IBSS mode */ 1917 /* check beacons in IBSS mode */
1887 if (sc->opmode == IEEE80211_IF_TYPE_IBSS) 1918 if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
1888 ath5k_check_ibss_hw_merge(sc, skb); 1919 ath5k_check_ibss_tsf(sc, skb, &rxs);
1889 1920
1890 __ieee80211_rx(sc->hw, skb, &rxs); 1921 __ieee80211_rx(sc->hw, skb, &rxs);
1891 sc->led_rxrate = rs.rs_rate; 1922 sc->led_rxrate = rs.rs_rate;
@@ -2118,7 +2149,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
2118 * beacon timer registers. 2149 * beacon timer registers.
2119 * 2150 *
2120 * This is called in a variety of situations, e.g. when a beacon is received, 2151 * This is called in a variety of situations, e.g. when a beacon is received,
2121 * when a HW merge has been detected, but also when an new IBSS is created or 2152 * when a TSF update has been detected, but also when an new IBSS is created or
2122 * when we otherwise know we have to update the timers, but we keep it in this 2153 * when we otherwise know we have to update the timers, but we keep it in this
2123 * function to have it all together in one place. 2154 * function to have it all together in one place.
2124 */ 2155 */
@@ -2218,7 +2249,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
2218 * another AP to associate with. 2249 * another AP to associate with.
2219 * 2250 *
2220 * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA 2251 * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
2221 * interrupts to detect HW merges only. 2252 * interrupts to detect TSF updates only.
2222 * 2253 *
2223 * AP mode is missing. 2254 * AP mode is missing.
2224 */ 2255 */
@@ -2238,7 +2269,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
2238 * hardware send the beacons automatically. We have to load it 2269 * hardware send the beacons automatically. We have to load it
2239 * only once here. 2270 * only once here.
2240 * We use the SWBA interrupt only to keep track of the beacon 2271 * We use the SWBA interrupt only to keep track of the beacon
2241 * timers in order to detect HW merges (automatic TSF updates). 2272 * timers in order to detect automatic TSF updates.
2242 */ 2273 */
2243 ath5k_beaconq_config(sc); 2274 ath5k_beaconq_config(sc);
2244 2275
@@ -2451,8 +2482,8 @@ ath5k_intr(int irq, void *dev_id)
2451 * 2482 *
2452 * In IBSS mode we use this interrupt just to 2483 * In IBSS mode we use this interrupt just to
2453 * keep track of the next TBTT (target beacon 2484 * keep track of the next TBTT (target beacon
2454 * transmission time) in order to detect hardware 2485 * transmission time) in order to detect wether
2455 * merges (TSF updates). 2486 * automatic TSF updates happened.
2456 */ 2487 */
2457 if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { 2488 if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
2458 /* XXX: only if VEOL suppported */ 2489 /* XXX: only if VEOL suppported */