aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath5k/base.c')
-rw-r--r--drivers/net/wireless/ath5k/base.c79
1 files changed, 66 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 /*