diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 79 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.h | 1 |
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 | |||
1644 | static void | ||
1645 | ath5k_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 | |||
1643 | static void | 1671 | static void |
1644 | ath5k_tasklet_rx(unsigned long data) | 1672 | ath5k_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 | */ |
2098 | static void | 2135 | static void |
2099 | ath5k_beacon_config(struct ath5k_softc *sc) | 2136 | ath5k_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 | }; |