142 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
--- a/ath/if_ath.c
 | 
						|
+++ b/ath/if_ath.c
 | 
						|
@@ -161,6 +161,7 @@ static void ath_beacon_send(struct ath_s
 | 
						|
 static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
 | 
						|
 static void ath_beacon_free(struct ath_softc *);
 | 
						|
 static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
 | 
						|
+static void ath_hw_beacon_stop(struct ath_softc *sc);
 | 
						|
 static int ath_desc_alloc(struct ath_softc *);
 | 
						|
 static void ath_desc_free(struct ath_softc *);
 | 
						|
 static void ath_desc_swap(struct ath_desc *);
 | 
						|
@@ -2793,6 +2794,72 @@ ath_set_ack_bitrate(struct ath_softc *sc
 | 
						|
 	return 1;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static void
 | 
						|
+ath_hw_beacon_stop(struct ath_softc *sc)
 | 
						|
+{
 | 
						|
+	HAL_BEACON_TIMERS btimers;
 | 
						|
+
 | 
						|
+	btimers.bt_intval = 0;
 | 
						|
+	btimers.bt_nexttbtt = 0;
 | 
						|
+	btimers.bt_nextdba = 0xffffffff;
 | 
						|
+	btimers.bt_nextswba = 0xffffffff;
 | 
						|
+	btimers.bt_nextatim = 0;
 | 
						|
+
 | 
						|
+	ath_hal_setbeacontimers(sc->sc_ah, &btimers);
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* Fix up the ATIM window after TSF resync */
 | 
						|
+static int
 | 
						|
+ath_hw_check_atim(struct ath_softc *sc, int window, int intval)
 | 
						|
+{
 | 
						|
+#define AR5K_TIMER0_5210       0x802c  /* Next beacon time register */
 | 
						|
+#define AR5K_TIMER0_5211       0x8028
 | 
						|
+#define AR5K_TIMER3_5210       0x8038  /* End of ATIM window time register */
 | 
						|
+#define AR5K_TIMER3_5211       0x8034
 | 
						|
+	struct ath_hal *ah = sc->sc_ah;
 | 
						|
+	int dev = sc->sc_ah->ah_macType;
 | 
						|
+	unsigned int nbtt, atim;
 | 
						|
+	int is_5210 = 0;
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * check if the ATIM window is still correct:
 | 
						|
+	 *   1.) usually ATIM should be NBTT + window
 | 
						|
+	 *   2.) nbtt already updated
 | 
						|
+	 *   3.) nbtt already updated and has wrapped around
 | 
						|
+	 *   4.) atim has wrapped around
 | 
						|
+	 */
 | 
						|
+	switch(dev) {
 | 
						|
+	case 5210:
 | 
						|
+		nbtt = OS_REG_READ(ah, AR5K_TIMER0_5210);
 | 
						|
+		atim = OS_REG_READ(ah, AR5K_TIMER3_5210);
 | 
						|
+		is_5210 = 1;
 | 
						|
+		break;
 | 
						|
+	case 5211:
 | 
						|
+	case 5212:
 | 
						|
+		nbtt = OS_REG_READ(ah, AR5K_TIMER0_5211);
 | 
						|
+		atim = OS_REG_READ(ah, AR5K_TIMER3_5211);
 | 
						|
+		break;
 | 
						|
+	/* NB: 5416+ doesn't do ATIM in hw */
 | 
						|
+	case 5416:
 | 
						|
+	default:
 | 
						|
+		return 0;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if ((atim - nbtt != window) &&				/* 1.) */
 | 
						|
+	    (nbtt - atim != intval - window) &&			/* 2.) */
 | 
						|
+	    ((nbtt | 0x10000) - atim != intval - window) &&	/* 3.) */
 | 
						|
+	    ((atim | 0x10000) - nbtt != window)) {		/* 4.) */
 | 
						|
+		if (is_5210)
 | 
						|
+			OS_REG_WRITE(ah, AR5K_TIMER3_5210, nbtt + window );
 | 
						|
+		else
 | 
						|
+			OS_REG_WRITE(ah, AR5K_TIMER3_5211, nbtt + window );
 | 
						|
+		return atim - nbtt;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+
 | 
						|
 /*
 | 
						|
  * Reset the hardware w/o losing operational state.  This is
 | 
						|
  * basically a more efficient way of doing ath_stop, ath_init,
 | 
						|
@@ -5294,6 +5361,7 @@ ath_beacon_config(struct ath_softc *sc, 
 | 
						|
 	u_int64_t tsf, hw_tsf;
 | 
						|
 	u_int32_t tsftu, hw_tsftu;
 | 
						|
 	u_int32_t intval, nexttbtt = 0;
 | 
						|
+	unsigned long flags;
 | 
						|
 	int reset_tsf = 0;
 | 
						|
 
 | 
						|
 	if (vap == NULL)
 | 
						|
@@ -5301,6 +5369,9 @@ ath_beacon_config(struct ath_softc *sc, 
 | 
						|
 
 | 
						|
 	ni = vap->iv_bss;
 | 
						|
 
 | 
						|
+	/* TSF calculation is timing critical - we don't want to be interrupted here */
 | 
						|
+	local_irq_save(flags);
 | 
						|
+
 | 
						|
 	hw_tsf = ath_hal_gettsf64(ah);
 | 
						|
 	tsf = le64_to_cpu(ni->ni_tstamp.tsf);
 | 
						|
 	hw_tsftu = hw_tsf >> 10;
 | 
						|
@@ -5490,15 +5561,27 @@ ath_beacon_config(struct ath_softc *sc, 
 | 
						|
 				<= ath_hal_sw_beacon_response_time)
 | 
						|
 			nexttbtt += intval;
 | 
						|
 		sc->sc_nexttbtt = nexttbtt;
 | 
						|
+
 | 
						|
+		/* stop beacons before reconfiguring the timers to avoid race
 | 
						|
+		 * conditions. ath_hal_beaconinit will start them again */
 | 
						|
+		ath_hw_beacon_stop(sc);
 | 
						|
+
 | 
						|
 		ath_hal_beaconinit(ah, nexttbtt, intval);
 | 
						|
 		if (intval & HAL_BEACON_RESET_TSF) {
 | 
						|
 			sc->sc_last_tsf = 0;
 | 
						|
 		}
 | 
						|
 		sc->sc_bmisscount = 0;
 | 
						|
 		ath_hal_intrset(ah, sc->sc_imask);
 | 
						|
+
 | 
						|
+		if ((sc->sc_opmode == HAL_M_IBSS) && ath_hw_check_atim(sc, 1, intval & HAL_BEACON_PERIOD)) {
 | 
						|
+			DPRINTF(sc, ATH_DEBUG_BEACON,
 | 
						|
+				"fixed atim window after beacon init\n");
 | 
						|
+		}
 | 
						|
 	}
 | 
						|
 
 | 
						|
 ath_beacon_config_debug:
 | 
						|
+	local_irq_restore(flags);
 | 
						|
+
 | 
						|
 	/* We print all debug messages here, in order to preserve the
 | 
						|
 	 * time critical aspect of this function */
 | 
						|
 	DPRINTF(sc, ATH_DEBUG_BEACON,
 | 
						|
@@ -6401,6 +6484,11 @@ ath_recv_mgmt(struct ieee80211vap * vap,
 | 
						|
 			DPRINTF(sc, ATH_DEBUG_BEACON, 
 | 
						|
 				"Updated beacon timers\n");
 | 
						|
 		}
 | 
						|
+		if ((sc->sc_opmode == HAL_M_IBSS) &&
 | 
						|
+				IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid) &&
 | 
						|
+				ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval)) {
 | 
						|
+			DPRINTF(sc, ATH_DEBUG_ANY, "Fixed ATIM window after beacon recv\n");
 | 
						|
+		}
 | 
						|
 		/* NB: Fall Through */
 | 
						|
 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
 | 
						|
 		if (vap->iv_opmode == IEEE80211_M_IBSS &&
 |