diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 59 |
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 | ||
1717 | static void | 1717 | static void |
1718 | ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb) | 1718 | ath5k_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 */ |