@@ -588,6 +588,7 @@ struct ath_softc {
int led_off_cnt;
int beacon_interval;
+ u32 scan_wait_counter;
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath9k_debug debug;
@@ -2043,6 +2043,74 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
mutex_unlock(&sc->mutex);
}
+static void ath9k_ps_flags_dbg(struct ath_softc *sc)
+{
+#define ATH9K_WAIT_DBG(_reason) do { \
+ if (sc->ps_flags & _reason) \
+ ath_print(common, ATH_DBG_PS, \
+ " %s\n", #_reason); \
+ } while (0)
+
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_print(common, ATH_DBG_PS, "PS flags:\n");
+
+ ATH9K_WAIT_DBG(PS_WAIT_FOR_BEACON);
+ ATH9K_WAIT_DBG(PS_WAIT_FOR_CAB);
+ ATH9K_WAIT_DBG(PS_WAIT_FOR_PSPOLL_DATA);
+ ATH9K_WAIT_DBG(PS_WAIT_FOR_TX_ACK);
+ ATH9K_WAIT_DBG(PS_BEACON_SYNC);
+ ATH9K_WAIT_DBG(PS_NULLFUNC_COMPLETED);
+ ATH9K_WAIT_DBG(PS_ENABLED);
+
+#undef ATH9K_WAIT_DBG
+}
+
+/*
+ * We expect to be disassociated if the counter gets too high.
+ */
+static int ath9k_sw_scan_wait_constraints(struct ieee80211_hw *hw)
+{
+ struct ath_wiphy *aphy = hw->priv;
+ struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int r = 0;
+ u32 wait_for;
+
+ mutex_lock(&sc->mutex);
+
+ wait_for = PS_WAIT_FOR_BEACON |
+ PS_BEACON_SYNC |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ PS_WAIT_FOR_TX_ACK |
+ PS_NULLFUNC_COMPLETED;
+
+ if (sc->ps_flags & wait_for) {
+ sc->scan_wait_counter++;
+ ath_print(common, ATH_DBG_PS,
+ "Holding on channel change due to a "
+ "wait constraint, count: %d, ps_flags: 0x%04x\n",
+ sc->scan_wait_counter,
+ sc->ps_flags);
+ ath9k_ps_flags_dbg(sc);
+ if (sc->ps_flags & PS_NULLFUNC_COMPLETED)
+ r = -EAGAIN;
+ else
+ r = -EBUSY;
+ goto out;
+ }
+
+ sc->scan_wait_counter = 0;
+ ath_print(common, ATH_DBG_PS,
+ "No scan wait contraints found, ps_flags: 0x%04x\n",
+ sc->ps_flags);
+out:
+ mutex_unlock(&sc->mutex);
+
+ return r;
+}
+
/*
* XXX: this requires a revisit after the driver
* scan_complete gets moved to another place/removed in mac80211.
@@ -2089,6 +2157,7 @@ struct ieee80211_ops ath9k_ops = {
.ampdu_action = ath9k_ampdu_action,
.get_survey = ath9k_get_survey,
.sw_scan_start = ath9k_sw_scan_start,
+ .sw_scan_wait_constraints = ath9k_sw_scan_wait_constraints,
.sw_scan_complete = ath9k_sw_scan_complete,
.rfkill_poll = ath9k_rfkill_poll_state,
.set_coverage_class = ath9k_set_coverage_class,