void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_set_beacon(struct ath_softc *sc);
+bool ath9k_csa_is_finished(struct ath_softc *sc);
 
 /*******************/
 /* Link Monitoring */
 #endif
 
        struct ath_descdma txsdma;
+       struct ieee80211_vif *csa_vif;
 
        struct ath_ant_comb ant_comb;
        u8 ant_tx, ant_rx;
 
                (unsigned long long)tsfadjust, avp->av_bslot);
 }
 
+bool ath9k_csa_is_finished(struct ath_softc *sc)
+{
+       struct ieee80211_vif *vif;
+
+       vif = sc->csa_vif;
+       if (!vif || !vif->csa_active)
+               return false;
+
+       if (!ieee80211_csa_is_complete(vif))
+               return false;
+
+       ieee80211_csa_finish(vif);
+
+       sc->csa_vif = NULL;
+       return true;
+}
+
 void ath9k_beacon_tasklet(unsigned long data)
 {
        struct ath_softc *sc = (struct ath_softc *)data;
                return;
        }
 
+       /* EDMA devices check that in the tx completion function. */
+       if (!edma && ath9k_csa_is_finished(sc))
+               return;
+
        slot = ath9k_beacon_choose_slot(sc);
        vif = sc->beacon.bslot[slot];
 
 
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
        hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
+       hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 
 #ifdef CONFIG_PM_SLEEP
        if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
 
        if (ath9k_uses_beacons(vif->type))
                ath9k_beacon_remove_slot(sc, vif);
 
+       if (sc->csa_vif == vif)
+               sc->csa_vif = NULL;
+
        ath9k_ps_wakeup(sc);
        ath9k_calculate_summary_state(hw, NULL);
        ath9k_ps_restore(sc);
        clear_bit(SC_OP_SCANNING, &sc->sc_flags);
 }
 
+static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
+                                       struct cfg80211_chan_def *chandef)
+{
+       struct ath_softc *sc = hw->priv;
+
+       /* mac80211 does not support CSA in multi-if cases (yet) */
+       if (WARN_ON(sc->csa_vif))
+               return;
+
+       sc->csa_vif = vif;
+}
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
 #endif
        .sw_scan_start      = ath9k_sw_scan_start,
        .sw_scan_complete   = ath9k_sw_scan_complete,
+       .channel_switch_beacon     = ath9k_channel_switch_beacon,
 };
 
                if (ts.qid == sc->beacon.beaconq) {
                        sc->beacon.tx_processed = true;
                        sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
+
+                       ath9k_csa_is_finished(sc);
                        continue;
                }