diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch
index 9e1a55432fe6e93cb43a5b0097a1ded2b638784a..ca232a0e530186910c0359657ef09d5df827d681 100644
--- a/package/kernel/mac80211/patches/300-pending_work.patch
+++ b/package/kernel/mac80211/patches/300-pending_work.patch
@@ -45,9 +45,38 @@
  			    TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
  			    TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
  			    TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
+@@ -455,6 +455,15 @@ void ieee80211_sta_debugfs_add(struct st
+ 	DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
+ 	DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
+ 
++	if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
++		debugfs_create_x32("driver_buffered_tids", 0400,
++				   sta->debugfs.dir,
++				   (u32 *)&sta->driver_buffered_tids);
++	else
++		debugfs_create_x64("driver_buffered_tids", 0400,
++				   sta->debugfs.dir,
++				   (u64 *)&sta->driver_buffered_tids);
++
+ 	drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir);
+ }
+ 
 --- a/net/mac80211/iface.c
 +++ b/net/mac80211/iface.c
-@@ -463,7 +463,6 @@ int ieee80211_do_open(struct wireless_de
+@@ -274,6 +274,12 @@ static int ieee80211_check_concurrent_if
+ 			if (iftype == NL80211_IFTYPE_ADHOC &&
+ 			    nsdata->vif.type == NL80211_IFTYPE_ADHOC)
+ 				return -EBUSY;
++			/*
++			 * will not add another interface while any channel
++			 * switch is active.
++			 */
++			if (nsdata->vif.csa_active)
++				return -EBUSY;
+ 
+ 			/*
+ 			 * The remaining checks are only performed for interfaces
+@@ -463,7 +469,6 @@ int ieee80211_do_open(struct wireless_de
  	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
  	struct net_device *dev = wdev->netdev;
  	struct ieee80211_local *local = sdata->local;
@@ -55,7 +84,7 @@
  	u32 changed = 0;
  	int res;
  	u32 hw_reconf_flags = 0;
-@@ -629,30 +628,8 @@ int ieee80211_do_open(struct wireless_de
+@@ -629,30 +634,8 @@ int ieee80211_do_open(struct wireless_de
  
  	set_bit(SDATA_STATE_RUNNING, &sdata->state);
  
@@ -87,7 +116,16 @@
  
  	/*
  	 * set_multicast_list will be invoked by the networking core
-@@ -1116,6 +1093,74 @@ static void ieee80211_if_setup(struct ne
+@@ -809,6 +792,8 @@ static void ieee80211_do_stop(struct iee
+ 	cancel_work_sync(&local->dynamic_ps_enable_work);
+ 
+ 	cancel_work_sync(&sdata->recalc_smps);
++	sdata->vif.csa_active = false;
++	cancel_work_sync(&sdata->csa_finalize_work);
+ 
+ 	cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
+ 
+@@ -1116,6 +1101,74 @@ static void ieee80211_if_setup(struct ne
  	dev->destructor = free_netdev;
  }
  
@@ -162,7 +200,7 @@
  static void ieee80211_iface_work(struct work_struct *work)
  {
  	struct ieee80211_sub_if_data *sdata =
-@@ -1220,6 +1265,9 @@ static void ieee80211_iface_work(struct 
+@@ -1220,6 +1273,9 @@ static void ieee80211_iface_work(struct 
  				break;
  			ieee80211_mesh_rx_queued_mgmt(sdata, skb);
  			break;
@@ -172,9 +210,61 @@
  		default:
  			WARN(1, "frame for unexpected interface type");
  			break;
+@@ -1282,6 +1338,7 @@ static void ieee80211_setup_sdata(struct
+ 	skb_queue_head_init(&sdata->skb_queue);
+ 	INIT_WORK(&sdata->work, ieee80211_iface_work);
+ 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
++	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
+ 
+ 	switch (type) {
+ 	case NL80211_IFTYPE_P2P_GO:
 --- a/net/mac80211/rc80211_minstrel_ht.c
 +++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct 
+@@ -365,6 +365,14 @@ minstrel_ht_update_stats(struct minstrel
+ 		}
+ 	}
+ 
++#ifdef CPTCFG_MAC80211_DEBUGFS
++	/* use fixed index if set */
++	if (mp->fixed_rate_idx != -1) {
++		mi->max_tp_rate = mp->fixed_rate_idx;
++		mi->max_tp_rate2 = mp->fixed_rate_idx;
++		mi->max_prob_rate = mp->fixed_rate_idx;
++	}
++#endif
+ 
+ 	mi->stats_update = jiffies;
+ }
+@@ -774,6 +782,11 @@ minstrel_ht_get_rate(void *priv, struct 
+ 	info->flags |= mi->tx_flags;
+ 	minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
+ 
++#ifdef CPTCFG_MAC80211_DEBUGFS
++	if (mp->fixed_rate_idx != -1)
++		return;
++#endif
++
+ 	/* Don't use EAPOL frames for sampling on non-mrr hw */
+ 	if (mp->hw->max_rates == 1 &&
+ 	    txrc->skb->protocol == cpu_to_be16(ETH_P_PAE))
+@@ -781,16 +794,6 @@ minstrel_ht_get_rate(void *priv, struct 
+ 	else
+ 		sample_idx = minstrel_get_sample_rate(mp, mi);
+ 
+-#ifdef CPTCFG_MAC80211_DEBUGFS
+-	/* use fixed index if set */
+-	if (mp->fixed_rate_idx != -1) {
+-		mi->max_tp_rate = mp->fixed_rate_idx;
+-		mi->max_tp_rate2 = mp->fixed_rate_idx;
+-		mi->max_prob_rate = mp->fixed_rate_idx;
+-		sample_idx = -1;
+-	}
+-#endif
+-
+ 	mi->total_packets++;
+ 
+ 	/* wraparound */
+@@ -804,10 +807,18 @@ minstrel_ht_get_rate(void *priv, struct 
  
  	sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
  	info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
@@ -194,7 +284,7 @@
  }
  
  static void
-@@ -820,6 +828,9 @@ minstrel_ht_update_cck(struct minstrel_p
+@@ -820,6 +831,9 @@ minstrel_ht_update_cck(struct minstrel_p
  	if (sband->band != IEEE80211_BAND_2GHZ)
  		return;
  
@@ -754,7 +844,76 @@
  #undef PADBYTES
  }
  
-@@ -1188,53 +1275,86 @@ static void ath_tx_fill_desc(struct ath_
+@@ -999,7 +1086,7 @@ void ath_update_max_aggr_framelen(struct
+ }
+ 
+ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
+-			     struct ath_tx_info *info, int len)
++			     struct ath_tx_info *info, int len, bool rts)
+ {
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct sk_buff *skb;
+@@ -1008,6 +1095,7 @@ static void ath_buf_set_rate(struct ath_
+ 	const struct ieee80211_rate *rate;
+ 	struct ieee80211_hdr *hdr;
+ 	struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
++	u32 rts_thresh = sc->hw->wiphy->rts_threshold;
+ 	int i;
+ 	u8 rix = 0;
+ 
+@@ -1030,7 +1118,17 @@ static void ath_buf_set_rate(struct ath_
+ 		rix = rates[i].idx;
+ 		info->rates[i].Tries = rates[i].count;
+ 
+-		    if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
++		/*
++		 * Handle RTS threshold for unaggregated HT frames.
++		 */
++		if (bf_isampdu(bf) && !bf_isaggr(bf) &&
++		    (rates[i].flags & IEEE80211_TX_RC_MCS) &&
++		    unlikely(rts_thresh != (u32) -1)) {
++			if (!rts_thresh || (len > rts_thresh))
++				rts = true;
++		}
++
++		if (rts || rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ 			info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ 			info->flags |= ATH9K_TXDESC_RTSENA;
+ 		} else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+@@ -1123,6 +1221,8 @@ static void ath_tx_fill_desc(struct ath_
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct ath_buf *bf_first = NULL;
+ 	struct ath_tx_info info;
++	u32 rts_thresh = sc->hw->wiphy->rts_threshold;
++	bool rts = false;
+ 
+ 	memset(&info, 0, sizeof(info));
+ 	info.is_first = true;
+@@ -1159,7 +1259,22 @@ static void ath_tx_fill_desc(struct ath_
+ 				info.flags |= (u32) bf->bf_state.bfs_paprd <<
+ 					      ATH9K_TXDESC_PAPRD_S;
+ 
+-			ath_buf_set_rate(sc, bf, &info, len);
++			/*
++			 * mac80211 doesn't handle RTS threshold for HT because
++			 * the decision has to be taken based on AMPDU length
++			 * and aggregation is done entirely inside ath9k.
++			 * Set the RTS/CTS flag for the first subframe based
++			 * on the threshold.
++			 */
++			if (aggr && (bf == bf_first) &&
++			    unlikely(rts_thresh != (u32) -1)) {
++				/*
++				 * "len" is the size of the entire AMPDU.
++				 */
++				if (!rts_thresh || (len > rts_thresh))
++					rts = true;
++			}
++			ath_buf_set_rate(sc, bf, &info, len, rts);
+ 		}
+ 
+ 		info.buf_addr[0] = bf->bf_buf_addr;
+@@ -1188,53 +1303,86 @@ static void ath_tx_fill_desc(struct ath_
  	}
  }
  
@@ -850,18 +1009,18 @@
 +		*stop = true;
 +		return false;
 +	}
-+
+ 
+-		ath_tx_fill_desc(sc, bf, txq, aggr_len);
+-		ath_tx_txqaddbuf(sc, txq, &bf_q, false);
+-	} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
+-		 status != ATH_AGGR_BAW_CLOSED);
 +	ath_set_rates(tid->an->vif, tid->an->sta, bf);
 +	if (aggr)
 +		last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
 +					tid_q, &aggr_len);
 +	else
 +		ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
- 
--		ath_tx_fill_desc(sc, bf, txq, aggr_len);
--		ath_tx_txqaddbuf(sc, txq, &bf_q, false);
--	} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
--		 status != ATH_AGGR_BAW_CLOSED);
++
 +	if (list_empty(&bf_q))
 +		return false;
 +
@@ -876,7 +1035,7 @@
  }
  
  int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
-@@ -1258,6 +1378,9 @@ int ath_tx_aggr_start(struct ath_softc *
+@@ -1258,6 +1406,9 @@ int ath_tx_aggr_start(struct ath_softc *
  		an->mpdudensity = density;
  	}
  
@@ -886,7 +1045,7 @@
  	txtid->active = true;
  	txtid->paused = true;
  	*ssn = txtid->seq_start = txtid->seq_next;
-@@ -1277,8 +1400,9 @@ void ath_tx_aggr_stop(struct ath_softc *
+@@ -1277,8 +1428,9 @@ void ath_tx_aggr_stop(struct ath_softc *
  
  	ath_txq_lock(sc, txq);
  	txtid->active = false;
@@ -897,7 +1056,7 @@
  	ath_txq_unlock_complete(sc, txq);
  }
  
-@@ -1302,7 +1426,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
+@@ -1302,7 +1454,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
  
  		ath_txq_lock(sc, txq);
  
@@ -906,7 +1065,7 @@
  
  		tid->sched = false;
  		list_del(&tid->list);
-@@ -1334,7 +1458,7 @@ void ath_tx_aggr_wakeup(struct ath_softc
+@@ -1334,7 +1486,7 @@ void ath_tx_aggr_wakeup(struct ath_softc
  		ath_txq_lock(sc, txq);
  		ac->clear_ps_filter = true;
  
@@ -915,7 +1074,7 @@
  			ath_tx_queue_tid(txq, tid);
  			ath_txq_schedule(sc, txq);
  		}
-@@ -1359,7 +1483,7 @@ void ath_tx_aggr_resume(struct ath_softc
+@@ -1359,7 +1511,7 @@ void ath_tx_aggr_resume(struct ath_softc
  	tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
  	tid->paused = false;
  
@@ -924,7 +1083,7 @@
  		ath_tx_queue_tid(txq, tid);
  		ath_txq_schedule(sc, txq);
  	}
-@@ -1379,6 +1503,7 @@ void ath9k_release_buffered_frames(struc
+@@ -1379,6 +1531,7 @@ void ath9k_release_buffered_frames(struc
  	struct ieee80211_tx_info *info;
  	struct list_head bf_q;
  	struct ath_buf *bf_tail = NULL, *bf;
@@ -932,7 +1091,7 @@
  	int sent = 0;
  	int i;
  
-@@ -1394,15 +1519,15 @@ void ath9k_release_buffered_frames(struc
+@@ -1394,15 +1547,15 @@ void ath9k_release_buffered_frames(struc
  			continue;
  
  		ath_txq_lock(sc, tid->ac->txq);
@@ -952,7 +1111,7 @@
  			bf->bf_state.bf_type &= ~BUF_AGGR;
  			if (bf_tail)
  				bf_tail->bf_next = bf;
-@@ -1412,7 +1537,7 @@ void ath9k_release_buffered_frames(struc
+@@ -1412,7 +1565,7 @@ void ath9k_release_buffered_frames(struc
  			sent++;
  			TX_STAT_INC(txq->axq_qnum, a_queued_hw);
  
@@ -961,7 +1120,7 @@
  				ieee80211_sta_set_buffered(an->sta, i, false);
  		}
  		ath_txq_unlock_complete(sc, tid->ac->txq);
-@@ -1571,7 +1696,7 @@ static void ath_drain_txq_list(struct at
+@@ -1571,7 +1724,7 @@ static void ath_drain_txq_list(struct at
  	while (!list_empty(list)) {
  		bf = list_first_entry(list, struct ath_buf, list);
  
@@ -970,7 +1129,7 @@
  			list_del(&bf->list);
  
  			ath_tx_return_buffer(sc, bf);
-@@ -1665,25 +1790,27 @@ void ath_tx_cleanupq(struct ath_softc *s
+@@ -1665,25 +1818,27 @@ void ath_tx_cleanupq(struct ath_softc *s
   */
  void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
  {
@@ -1003,7 +1162,7 @@
  			tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
  					       list);
  			list_del(&tid->list);
-@@ -1692,17 +1819,17 @@ void ath_txq_schedule(struct ath_softc *
+@@ -1692,17 +1847,17 @@ void ath_txq_schedule(struct ath_softc *
  			if (tid->paused)
  				continue;
  
@@ -1025,7 +1184,7 @@
  				break;
  		}
  
-@@ -1711,9 +1838,17 @@ void ath_txq_schedule(struct ath_softc *
+@@ -1711,9 +1866,17 @@ void ath_txq_schedule(struct ath_softc *
  			list_add_tail(&ac->list, &txq->axq_acq);
  		}
  
@@ -1045,7 +1204,7 @@
  	}
  
  	rcu_read_unlock();
-@@ -1792,57 +1927,6 @@ static void ath_tx_txqaddbuf(struct ath_
+@@ -1792,57 +1955,6 @@ static void ath_tx_txqaddbuf(struct ath_
  	}
  }
  
@@ -1103,7 +1262,7 @@
  static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
  			       struct ath_atx_tid *tid, struct sk_buff *skb)
  {
-@@ -1985,6 +2069,7 @@ static int ath_tx_prepare(struct ieee802
+@@ -1985,6 +2097,7 @@ static int ath_tx_prepare(struct ieee802
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  	struct ieee80211_sta *sta = txctl->sta;
  	struct ieee80211_vif *vif = info->control.vif;
@@ -1111,7 +1270,7 @@
  	struct ath_softc *sc = hw->priv;
  	int frmlen = skb->len + FCS_LEN;
  	int padpos, padsize;
-@@ -1992,6 +2077,10 @@ static int ath_tx_prepare(struct ieee802
+@@ -1992,6 +2105,10 @@ static int ath_tx_prepare(struct ieee802
  	/* NOTE:  sta can be NULL according to net/mac80211.h */
  	if (sta)
  		txctl->an = (struct ath_node *)sta->drv_priv;
@@ -1122,7 +1281,7 @@
  
  	if (info->control.hw_key)
  		frmlen += info->control.hw_key->icv_len;
-@@ -2041,7 +2130,6 @@ int ath_tx_start(struct ieee80211_hw *hw
+@@ -2041,7 +2158,6 @@ int ath_tx_start(struct ieee80211_hw *hw
  	struct ath_txq *txq = txctl->txq;
  	struct ath_atx_tid *tid = NULL;
  	struct ath_buf *bf;
@@ -1130,7 +1289,7 @@
  	int q;
  	int ret;
  
-@@ -2069,27 +2157,31 @@ int ath_tx_start(struct ieee80211_hw *hw
+@@ -2069,27 +2185,31 @@ int ath_tx_start(struct ieee80211_hw *hw
  		ath_txq_unlock(sc, txq);
  		txq = sc->tx.uapsdq;
  		ath_txq_lock(sc, txq);
@@ -1173,7 +1332,16 @@
  		if (txctl->paprd)
  			dev_kfree_skb_any(skb);
  		else
-@@ -2189,7 +2281,7 @@ static void ath_tx_complete(struct ath_s
+@@ -2142,7 +2262,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
+ 
+ 		bf->bf_lastbf = bf;
+ 		ath_set_rates(vif, NULL, bf);
+-		ath_buf_set_rate(sc, bf, &info, fi->framelen);
++		ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
+ 		duration += info.rates[0].PktDuration;
+ 		if (bf_tail)
+ 			bf_tail->bf_next = bf;
+@@ -2189,7 +2309,7 @@ static void ath_tx_complete(struct ath_s
  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  	struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
@@ -1182,7 +1350,7 @@
  	unsigned long flags;
  
  	ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
-@@ -2225,21 +2317,7 @@ static void ath_tx_complete(struct ath_s
+@@ -2225,21 +2345,7 @@ static void ath_tx_complete(struct ath_s
  	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
  
  	__skb_queue_tail(&txq->complete_q, skb);
@@ -1205,7 +1373,7 @@
  }
  
  static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-@@ -2360,8 +2438,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2360,8 +2466,7 @@ static void ath_tx_processq(struct ath_s
  
  		if (list_empty(&txq->axq_q)) {
  			txq->axq_link = NULL;
@@ -1215,7 +1383,7 @@
  			break;
  		}
  		bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
-@@ -2375,7 +2452,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2375,7 +2480,7 @@ static void ath_tx_processq(struct ath_s
  		 * it with the STALE flag.
  		 */
  		bf_held = NULL;
@@ -1224,7 +1392,7 @@
  			bf_held = bf;
  			if (list_is_last(&bf_held->list, &txq->axq_q))
  				break;
-@@ -2399,7 +2476,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2399,7 +2504,7 @@ static void ath_tx_processq(struct ath_s
  		 * however leave the last descriptor back as the holding
  		 * descriptor for hw.
  		 */
@@ -1233,7 +1401,7 @@
  		INIT_LIST_HEAD(&bf_head);
  		if (!list_is_singular(&lastbf->list))
  			list_cut_position(&bf_head,
-@@ -2470,7 +2547,7 @@ void ath_tx_edma_tasklet(struct ath_soft
+@@ -2470,7 +2575,7 @@ void ath_tx_edma_tasklet(struct ath_soft
  		}
  
  		bf = list_first_entry(fifo_list, struct ath_buf, list);
@@ -1242,7 +1410,7 @@
  			list_del(&bf->list);
  			ath_tx_return_buffer(sc, bf);
  			bf = list_first_entry(fifo_list, struct ath_buf, list);
-@@ -2492,7 +2569,7 @@ void ath_tx_edma_tasklet(struct ath_soft
+@@ -2492,7 +2597,7 @@ void ath_tx_edma_tasklet(struct ath_soft
  				ath_tx_txqaddbuf(sc, txq, &bf_q, true);
  			}
  		} else {
@@ -1251,7 +1419,7 @@
  			if (bf != lastbf)
  				list_cut_position(&bf_head, fifo_list,
  						  lastbf->list.prev);
-@@ -2583,6 +2660,7 @@ void ath_tx_node_init(struct ath_softc *
+@@ -2583,6 +2688,7 @@ void ath_tx_node_init(struct ath_softc *
  		tid->paused    = false;
  		tid->active	   = false;
  		__skb_queue_head_init(&tid->buf_q);
@@ -1259,7 +1427,7 @@
  		acno = TID_TO_WME_AC(tidno);
  		tid->ac = &an->ac[acno];
  	}
-@@ -2590,6 +2668,7 @@ void ath_tx_node_init(struct ath_softc *
+@@ -2590,6 +2696,7 @@ void ath_tx_node_init(struct ath_softc *
  	for (acno = 0, ac = &an->ac[acno];
  	     acno < IEEE80211_NUM_ACS; acno++, ac++) {
  		ac->sched    = false;
@@ -1269,7 +1437,27 @@
  	}
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -966,6 +966,8 @@ static int ath9k_add_interface(struct ie
+@@ -173,8 +173,7 @@ static void ath_restart_work(struct ath_
+ {
+ 	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+ 
+-	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) ||
+-	    AR_SREV_9550(sc->sc_ah))
++	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
+ 		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+ 				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+ 
+@@ -238,9 +237,6 @@ static bool ath_complete_reset(struct at
+ 		ath_restart_work(sc);
+ 	}
+ 
+-	if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
+-		ath_ant_comb_update(sc);
+-
+ 	ieee80211_wake_queues(sc->hw);
+ 
+ 	return true;
+@@ -966,6 +962,8 @@ static int ath9k_add_interface(struct ie
  	struct ath_softc *sc = hw->priv;
  	struct ath_hw *ah = sc->sc_ah;
  	struct ath_common *common = ath9k_hw_common(ah);
@@ -1278,7 +1466,7 @@
  
  	mutex_lock(&sc->mutex);
  
-@@ -979,6 +981,12 @@ static int ath9k_add_interface(struct ie
+@@ -979,6 +977,12 @@ static int ath9k_add_interface(struct ie
  	if (ath9k_uses_beacons(vif->type))
  		ath9k_beacon_assign_slot(sc, vif);
  
@@ -1291,7 +1479,7 @@
  	mutex_unlock(&sc->mutex);
  	return 0;
  }
-@@ -1016,6 +1024,7 @@ static void ath9k_remove_interface(struc
+@@ -1016,6 +1020,7 @@ static void ath9k_remove_interface(struc
  {
  	struct ath_softc *sc = hw->priv;
  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1299,7 +1487,7 @@
  
  	ath_dbg(common, CONFIG, "Detach Interface\n");
  
-@@ -1030,6 +1039,8 @@ static void ath9k_remove_interface(struc
+@@ -1030,6 +1035,8 @@ static void ath9k_remove_interface(struc
  	ath9k_calculate_summary_state(hw, NULL);
  	ath9k_ps_restore(sc);
  
@@ -1308,7 +1496,36 @@
  	mutex_unlock(&sc->mutex);
  }
  
-@@ -1374,9 +1385,6 @@ static void ath9k_sta_notify(struct ieee
+@@ -1193,8 +1200,6 @@ static int ath9k_config(struct ieee80211
+ 
+ 	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
+ 		struct ieee80211_channel *curchan = hw->conf.chandef.chan;
+-		enum nl80211_channel_type channel_type =
+-			cfg80211_get_chandef_type(&conf->chandef);
+ 		int pos = curchan->hw_value;
+ 		int old_pos = -1;
+ 		unsigned long flags;
+@@ -1202,8 +1207,8 @@ static int ath9k_config(struct ieee80211
+ 		if (ah->curchan)
+ 			old_pos = ah->curchan - &ah->channels[0];
+ 
+-		ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
+-			curchan->center_freq, channel_type);
++		ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
++			curchan->center_freq, hw->conf.chandef.width);
+ 
+ 		/* update survey stats for the old channel before switching */
+ 		spin_lock_irqsave(&common->cc_lock, flags);
+@@ -1211,7 +1216,7 @@ static int ath9k_config(struct ieee80211
+ 		spin_unlock_irqrestore(&common->cc_lock, flags);
+ 
+ 		ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
+-					  curchan, channel_type);
++					  &conf->chandef);
+ 
+ 		/*
+ 		 * If the operating channel changes, change the survey in-use flags
+@@ -1374,9 +1379,6 @@ static void ath9k_sta_notify(struct ieee
  	struct ath_softc *sc = hw->priv;
  	struct ath_node *an = (struct ath_node *) sta->drv_priv;
  
@@ -1318,7 +1535,7 @@
  	switch (cmd) {
  	case STA_NOTIFY_SLEEP:
  		an->sleeping = true;
-@@ -2094,7 +2102,7 @@ static void ath9k_wow_add_pattern(struct
+@@ -2094,7 +2096,7 @@ static void ath9k_wow_add_pattern(struct
  {
  	struct ath_hw *ah = sc->sc_ah;
  	struct ath9k_wow_pattern *wow_pattern = NULL;
@@ -1374,7 +1591,38 @@
  		p = &wow->patterns[i];
 --- a/include/net/cfg80211.h
 +++ b/include/net/cfg80211.h
-@@ -1698,7 +1698,7 @@ struct cfg80211_pmksa {
+@@ -639,6 +639,30 @@ struct cfg80211_ap_settings {
+ };
+ 
+ /**
++ * struct cfg80211_csa_settings - channel switch settings
++ *
++ * Used for channel switch
++ *
++ * @chandef: defines the channel to use after the switch
++ * @beacon_csa: beacon data while performing the switch
++ * @counter_offset_beacon: offset for the counter within the beacon (tail)
++ * @counter_offset_presp: offset for the counter within the probe response
++ * @beacon_after: beacon data to be used on the new channel
++ * @radar_required: whether radar detection is required on the new channel
++ * @block_tx: whether transmissions should be blocked while changing
++ * @count: number of beacons until switch
++ */
++struct cfg80211_csa_settings {
++	struct cfg80211_chan_def chandef;
++	struct cfg80211_beacon_data beacon_csa;
++	u16 counter_offset_beacon, counter_offset_presp;
++	struct cfg80211_beacon_data beacon_after;
++	bool radar_required;
++	bool block_tx;
++	u8 count;
++};
++
++/**
+  * enum station_parameters_apply_mask - station parameter values to apply
+  * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
+  * @STATION_PARAM_APPLY_CAPABILITY: apply new capability
+@@ -1698,7 +1722,7 @@ struct cfg80211_pmksa {
  };
  
  /**
@@ -1383,7 +1631,7 @@
   * @mask: bitmask where to match pattern and where to ignore bytes,
   *	one bit per byte, in same format as nl80211
   * @pattern: bytes to match where bitmask is 1
-@@ -1708,7 +1708,7 @@ struct cfg80211_pmksa {
+@@ -1708,7 +1732,7 @@ struct cfg80211_pmksa {
   * Internal note: @mask and @pattern are allocated in one chunk of
   * memory, free @mask only!
   */
@@ -1392,7 +1640,7 @@
  	u8 *mask, *pattern;
  	int pattern_len;
  	int pkt_offset;
-@@ -1770,7 +1770,7 @@ struct cfg80211_wowlan {
+@@ -1770,7 +1794,7 @@ struct cfg80211_wowlan {
  	bool any, disconnect, magic_pkt, gtk_rekey_failure,
  	     eap_identity_req, four_way_handshake,
  	     rfkill_release;
@@ -1401,9 +1649,104 @@
  	struct cfg80211_wowlan_tcp *tcp;
  	int n_patterns;
  };
+@@ -2071,6 +2095,8 @@ struct cfg80211_update_ft_ies_params {
+  *	driver can take the most appropriate actions.
+  * @crit_proto_stop: Indicates critical protocol no longer needs increased link
+  *	reliability. This operation can not fail.
++ *
++ * @channel_switch: initiate channel-switch procedure (with CSA)
+  */
+ struct cfg80211_ops {
+ 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
+@@ -2306,6 +2332,10 @@ struct cfg80211_ops {
+ 				    u16 duration);
+ 	void	(*crit_proto_stop)(struct wiphy *wiphy,
+ 				   struct wireless_dev *wdev);
++
++	int	(*channel_switch)(struct wiphy *wiphy,
++				  struct net_device *dev,
++				  struct cfg80211_csa_settings *params);
+ };
+ 
+ /*
+@@ -2371,6 +2401,8 @@ struct cfg80211_ops {
+  * @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
+  * @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
+  * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
++ * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
++ *	beaconing mode (AP, IBSS, Mesh, ...).
+  */
+ enum wiphy_flags {
+ 	WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
+@@ -2395,6 +2427,7 @@ enum wiphy_flags {
+ 	WIPHY_FLAG_OFFCHAN_TX			= BIT(20),
+ 	WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL	= BIT(21),
+ 	WIPHY_FLAG_SUPPORTS_5_10_MHZ		= BIT(22),
++	WIPHY_FLAG_HAS_CHANNEL_SWITCH		= BIT(23),
+ };
+ 
+ /**
 --- a/include/uapi/linux/nl80211.h
 +++ b/include/uapi/linux/nl80211.h
-@@ -3060,11 +3060,11 @@ enum nl80211_tx_power_setting {
+@@ -648,6 +648,16 @@
+  * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
+  *	return back to normal.
+  *
++ * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
++ *	the new channel information (Channel Switch Announcement - CSA)
++ *	in the beacon for some time (as defined in the
++ *	%NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
++ *	new channel. Userspace provides the new channel information (using
++ *	%NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
++ *	width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
++ *	other station that transmission must be blocked until the channel
++ *	switch is complete.
++ *
+  * @NL80211_CMD_MAX: highest used command number
+  * @__NL80211_CMD_AFTER_LAST: internal use
+  */
+@@ -810,6 +820,8 @@ enum nl80211_commands {
+ 	NL80211_CMD_CRIT_PROTOCOL_START,
+ 	NL80211_CMD_CRIT_PROTOCOL_STOP,
+ 
++	NL80211_CMD_CHANNEL_SWITCH,
++
+ 	/* add new commands above here */
+ 
+ 	/* used to define NL80211_CMD_MAX below */
+@@ -1436,6 +1448,18 @@ enum nl80211_commands {
+  *	allowed to be used with the first @NL80211_CMD_SET_STATION command to
+  *	update a TDLS peer STA entry.
+  *
++ * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's
++ *	until the channel switch event.
++ * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
++ *	must be blocked on the current channel (before the channel switch
++ *	operation).
++ * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
++ *	for the time while performing a channel switch.
++ * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
++ *	field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
++ * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
++ *	field in the probe response (%NL80211_ATTR_PROBE_RESP).
++ *
+  * @NL80211_ATTR_MAX: highest attribute number currently defined
+  * @__NL80211_ATTR_AFTER_LAST: internal use
+  */
+@@ -1736,6 +1760,12 @@ enum nl80211_attrs {
+ 
+ 	NL80211_ATTR_PEER_AID,
+ 
++	NL80211_ATTR_CH_SWITCH_COUNT,
++	NL80211_ATTR_CH_SWITCH_BLOCK_TX,
++	NL80211_ATTR_CSA_IES,
++	NL80211_ATTR_CSA_C_OFF_BEACON,
++	NL80211_ATTR_CSA_C_OFF_PRESP,
++
+ 	/* add attributes here, update the policy in nl80211.c */
+ 
+ 	__NL80211_ATTR_AFTER_LAST,
+@@ -3060,11 +3090,11 @@ enum nl80211_tx_power_setting {
  };
  
  /**
@@ -1419,7 +1762,7 @@
   *	a bit for each byte in the pattern. The lowest-order bit corresponds
   *	to the first byte of the pattern, but the bytes of the pattern are
   *	in a little-endian-like format, i.e. the 9th byte of the pattern
-@@ -3075,23 +3075,23 @@ enum nl80211_tx_power_setting {
+@@ -3075,23 +3105,23 @@ enum nl80211_tx_power_setting {
   *	Note that the pattern matching is done as though frames were not
   *	802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
   *	first (including SNAP header unpacking) and then matched.
@@ -1454,7 +1797,7 @@
   * @max_patterns: maximum number of patterns supported
   * @min_pattern_len: minimum length of each pattern
   * @max_pattern_len: maximum length of each pattern
-@@ -3101,13 +3101,22 @@ enum nl80211_wowlan_packet_pattern_attr 
+@@ -3101,13 +3131,22 @@ enum nl80211_wowlan_packet_pattern_attr 
   * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
   * capability information given by the kernel to userspace.
   */
@@ -1478,7 +1821,7 @@
  /**
   * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
   * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
-@@ -3127,7 +3136,7 @@ struct nl80211_wowlan_pattern_support {
+@@ -3127,7 +3166,7 @@ struct nl80211_wowlan_pattern_support {
   *	pattern matching is done after the packet is converted to the MSDU.
   *
   *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
@@ -1487,7 +1830,7 @@
   *
   *	When reporting wakeup. it is a u32 attribute containing the 0-based
   *	index of the pattern that caused the wakeup, in the patterns passed
-@@ -3284,7 +3293,7 @@ struct nl80211_wowlan_tcp_data_token_fea
+@@ -3284,7 +3323,7 @@ struct nl80211_wowlan_tcp_data_token_fea
   * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
   *	u32 attribute holding the maximum length
   * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
@@ -1511,7 +1854,19 @@
  	 * peer's power mode is known
 --- a/net/wireless/nl80211.c
 +++ b/net/wireless/nl80211.c
-@@ -441,10 +441,12 @@ static int nl80211_prepare_wdev_dump(str
+@@ -349,6 +349,11 @@ static const struct nla_policy nl80211_p
+ 	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
+ 				  .len = IEEE80211_MAX_DATA_LEN },
+ 	[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
++	[NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
++	[NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
++	[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
++	[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
++	[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
+ };
+ 
+ /* policy for the key attributes */
+@@ -441,10 +446,12 @@ static int nl80211_prepare_wdev_dump(str
  			goto out_unlock;
  		}
  		*rdev = wiphy_to_dev((*wdev)->wiphy);
@@ -1526,7 +1881,7 @@
  		struct wireless_dev *tmp;
  
  		if (!wiphy) {
-@@ -974,7 +976,7 @@ static int nl80211_send_wowlan(struct sk
+@@ -974,7 +981,7 @@ static int nl80211_send_wowlan(struct sk
  		return -ENOBUFS;
  
  	if (dev->wiphy.wowlan->n_patterns) {
@@ -1535,7 +1890,16 @@
  			.max_patterns = dev->wiphy.wowlan->n_patterns,
  			.min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
  			.max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
-@@ -1568,8 +1570,10 @@ static int nl80211_dump_wiphy(struct sk_
+@@ -1393,6 +1400,8 @@ static int nl80211_send_wiphy(struct cfg
+ 		if (state->split) {
+ 			CMD(crit_proto_start, CRIT_PROTOCOL_START);
+ 			CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
++			if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
++				CMD(channel_switch, CHANNEL_SWITCH);
+ 		}
+ 
+ #ifdef CPTCFG_NL80211_TESTMODE
+@@ -1568,8 +1577,10 @@ static int nl80211_dump_wiphy(struct sk_
  	rtnl_lock();
  	if (!state) {
  		state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -1547,7 +1911,18 @@
  		state->filter_wiphy = -1;
  		ret = nl80211_dump_wiphy_parse(skb, cb, state);
  		if (ret) {
-@@ -4770,9 +4774,9 @@ do {									    \
+@@ -2620,8 +2631,8 @@ static int nl80211_get_key(struct sk_buf
+ 
+ 	hdr = nl80211hdr_put(msg, genl_info_snd_portid(info), info->snd_seq, 0,
+ 			     NL80211_CMD_NEW_KEY);
+-	if (IS_ERR(hdr))
+-		return PTR_ERR(hdr);
++	if (!hdr)
++		return -ENOBUFS;
+ 
+ 	cookie.msg = msg;
+ 	cookie.idx = key_idx;
+@@ -4770,9 +4781,9 @@ do {									    \
  	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
  				  mask, NL80211_MESHCONF_FORWARDING,
  				  nla_get_u8);
@@ -1559,7 +1934,129 @@
  	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
  				  mask, NL80211_MESHCONF_HT_OPMODE,
  				  nla_get_u16);
-@@ -6615,12 +6619,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_ev
+@@ -5578,6 +5589,111 @@ static int nl80211_start_radar_detection
+ 	return err;
+ }
+ 
++static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
++{
++	struct cfg80211_registered_device *rdev = info->user_ptr[0];
++	struct net_device *dev = info->user_ptr[1];
++	struct wireless_dev *wdev = dev->ieee80211_ptr;
++	struct cfg80211_csa_settings params;
++	/* csa_attrs is defined static to avoid waste of stack size - this
++	 * function is called under RTNL lock, so this should not be a problem.
++	 */
++	static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
++	u8 radar_detect_width = 0;
++	int err;
++
++	if (!rdev->ops->channel_switch ||
++	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
++		return -EOPNOTSUPP;
++
++	/* may add IBSS support later */
++	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
++	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
++		return -EOPNOTSUPP;
++
++	memset(&params, 0, sizeof(params));
++
++	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
++	    !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
++		return -EINVAL;
++
++	/* only important for AP, IBSS and mesh create IEs internally */
++	if (!info->attrs[NL80211_ATTR_CSA_IES])
++		return -EINVAL;
++
++	/* useless if AP is not running */
++	if (!wdev->beacon_interval)
++		return -EINVAL;
++
++	params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
++
++	err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
++	if (err)
++		return err;
++
++	err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
++			       info->attrs[NL80211_ATTR_CSA_IES],
++			       nl80211_policy);
++	if (err)
++		return err;
++
++	err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
++	if (err)
++		return err;
++
++	if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
++		return -EINVAL;
++
++	params.counter_offset_beacon =
++		nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
++	if (params.counter_offset_beacon >= params.beacon_csa.tail_len)
++		return -EINVAL;
++
++	/* sanity check - counters should be the same */
++	if (params.beacon_csa.tail[params.counter_offset_beacon] !=
++	    params.count)
++		return -EINVAL;
++
++	if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
++		params.counter_offset_presp =
++			nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
++		if (params.counter_offset_presp >=
++		    params.beacon_csa.probe_resp_len)
++			return -EINVAL;
++
++		if (params.beacon_csa.probe_resp[params.counter_offset_presp] !=
++		    params.count)
++			return -EINVAL;
++	}
++
++	err = nl80211_parse_chandef(rdev, info, &params.chandef);
++	if (err)
++		return err;
++
++	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
++		return -EINVAL;
++
++	err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
++	if (err < 0) {
++		return err;
++	} else if (err) {
++		radar_detect_width = BIT(params.chandef.width);
++		params.radar_required = true;
++	}
++
++	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
++					   params.chandef.chan,
++					   CHAN_MODE_SHARED,
++					   radar_detect_width);
++	if (err)
++		return err;
++
++	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
++		params.block_tx = true;
++
++	return rdev_channel_switch(rdev, dev, &params);
++}
++
+ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
+ 			    u32 seq, int flags,
+ 			    struct cfg80211_registered_device *rdev,
+@@ -6507,6 +6623,9 @@ static int nl80211_testmode_dump(struct 
+ 					   NL80211_CMD_TESTMODE);
+ 		struct nlattr *tmdata;
+ 
++		if (!hdr)
++			break;
++
+ 		if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
+ 			genlmsg_cancel(skb, hdr);
+ 			break;
+@@ -6615,12 +6734,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_ev
  
  void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
  {
@@ -1575,7 +2072,31 @@
  }
  EXPORT_SYMBOL(cfg80211_testmode_event);
  #endif
-@@ -7593,12 +7599,11 @@ static int nl80211_send_wowlan_patterns(
+@@ -6949,9 +7070,8 @@ static int nl80211_remain_on_channel(str
+ 
+ 	hdr = nl80211hdr_put(msg, genl_info_snd_portid(info), info->snd_seq, 0,
+ 			     NL80211_CMD_REMAIN_ON_CHANNEL);
+-
+-	if (IS_ERR(hdr)) {
+-		err = PTR_ERR(hdr);
++	if (!hdr) {
++		err = -ENOBUFS;
+ 		goto free_msg;
+ 	}
+ 
+@@ -7249,9 +7369,8 @@ static int nl80211_tx_mgmt(struct sk_buf
+ 
+ 		hdr = nl80211hdr_put(msg, genl_info_snd_portid(info), info->snd_seq, 0,
+ 				     NL80211_CMD_FRAME);
+-
+-		if (IS_ERR(hdr)) {
+-			err = PTR_ERR(hdr);
++		if (!hdr) {
++			err = -ENOBUFS;
+ 			goto free_msg;
+ 		}
+ 	}
+@@ -7593,12 +7712,11 @@ static int nl80211_send_wowlan_patterns(
  		if (!nl_pat)
  			return -ENOBUFS;
  		pat_len = wowlan->patterns[i].pattern_len;
@@ -1592,7 +2113,7 @@
  				wowlan->patterns[i].pkt_offset))
  			return -ENOBUFS;
  		nla_nest_end(msg, nl_pat);
-@@ -7939,7 +7944,7 @@ static int nl80211_set_wowlan(struct sk_
+@@ -7939,7 +8057,7 @@ static int nl80211_set_wowlan(struct sk_
  		struct nlattr *pat;
  		int n_patterns = 0;
  		int rem, pat_len, mask_len, pkt_offset;
@@ -1601,7 +2122,7 @@
  
  		nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
  				    rem)
-@@ -7958,26 +7963,25 @@ static int nl80211_set_wowlan(struct sk_
+@@ -7958,26 +8076,25 @@ static int nl80211_set_wowlan(struct sk_
  
  		nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
  				    rem) {
@@ -1636,7 +2157,7 @@
  			if (pkt_offset > wowlan->max_pkt_offset)
  				goto error;
  			new_triggers.patterns[i].pkt_offset = pkt_offset;
-@@ -7991,11 +7995,11 @@ static int nl80211_set_wowlan(struct sk_
+@@ -7991,11 +8108,11 @@ static int nl80211_set_wowlan(struct sk_
  			new_triggers.patterns[i].pattern =
  				new_triggers.patterns[i].mask + mask_len;
  			memcpy(new_triggers.patterns[i].mask,
@@ -1650,7 +2171,36 @@
  			       pat_len);
  			i++;
  		}
-@@ -10066,7 +10070,8 @@ void cfg80211_mgmt_tx_status(struct wire
+@@ -8130,9 +8247,8 @@ static int nl80211_probe_client(struct s
+ 
+ 	hdr = nl80211hdr_put(msg, genl_info_snd_portid(info), info->snd_seq, 0,
+ 			     NL80211_CMD_PROBE_CLIENT);
+-
+-	if (IS_ERR(hdr)) {
+-		err = PTR_ERR(hdr);
++	if (!hdr) {
++		err = -ENOBUFS;
+ 		goto free_msg;
+ 	}
+ 
+@@ -9041,7 +9157,15 @@ static struct genl_ops nl80211_ops[] = {
+ 		.flags = GENL_ADMIN_PERM,
+ 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ 				  NL80211_FLAG_NEED_RTNL,
+-	}
++	},
++	{
++		.cmd = NL80211_CMD_CHANNEL_SWITCH,
++		.doit = nl80211_channel_switch,
++		.policy = nl80211_policy,
++		.flags = GENL_ADMIN_PERM,
++		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
++				  NL80211_FLAG_NEED_RTNL,
++	},
+ };
+ 
+ static struct genl_multicast_group nl80211_mlme_mcgrp = {
+@@ -10066,7 +10190,8 @@ void cfg80211_mgmt_tx_status(struct wire
  
  	genlmsg_end(msg, hdr);
  
@@ -1766,9 +2316,51 @@
  }
  
  static int cfg80211_sme_connect(struct wireless_dev *wdev,
+@@ -953,21 +976,19 @@ int cfg80211_disconnect(struct cfg80211_
+ 			struct net_device *dev, u16 reason, bool wextev)
+ {
+ 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+-	int err;
++	int err = 0;
+ 
+ 	ASSERT_WDEV_LOCK(wdev);
+ 
+ 	kfree(wdev->connect_keys);
+ 	wdev->connect_keys = NULL;
+ 
+-	if (wdev->conn) {
++	if (wdev->conn)
+ 		err = cfg80211_sme_disconnect(wdev, reason);
+-	} else if (!rdev->ops->disconnect) {
++	else if (!rdev->ops->disconnect)
+ 		cfg80211_mlme_down(rdev, dev);
+-		err = 0;
+-	} else {
++	else if (wdev->current_bss)
+ 		err = rdev_disconnect(rdev, dev, reason);
+-	}
+ 
+ 	return err;
+ }
 --- a/net/mac80211/rc80211_minstrel.c
 +++ b/net/mac80211/rc80211_minstrel.c
-@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct iee
+@@ -203,6 +203,15 @@ minstrel_update_stats(struct minstrel_pr
+ 	memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
+ 	mi->max_prob_rate = tmp_prob_rate;
+ 
++#ifdef CPTCFG_MAC80211_DEBUGFS
++	/* use fixed index if set */
++	if (mp->fixed_rate_idx != -1) {
++		mi->max_tp_rate[0] = mp->fixed_rate_idx;
++		mi->max_tp_rate[1] = mp->fixed_rate_idx;
++		mi->max_prob_rate = mp->fixed_rate_idx;
++	}
++#endif
++
+ 	/* Reset update timer */
+ 	mi->stats_update = jiffies;
+ 
+@@ -290,7 +299,7 @@ minstrel_get_rate(void *priv, struct iee
  	struct minstrel_rate *msr, *mr;
  	unsigned int ndx;
  	bool mrr_capable;
@@ -1777,7 +2369,16 @@
  	int delta;
  	int sampling_ratio;
  
-@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct iee
+@@ -310,10 +319,16 @@ minstrel_get_rate(void *priv, struct iee
+ 	/* increase sum packet counter */
+ 	mi->packet_count++;
+ 
++#ifdef CPTCFG_MAC80211_DEBUGFS
++	if (mp->fixed_rate_idx != -1)
++		return;
++#endif
++
+ 	delta = (mi->packet_count * sampling_ratio / 100) -
  			(mi->sample_count + mi->sample_deferred / 2);
  
  	/* delta < 0: no sampling required */
@@ -1959,7 +2560,23 @@
  			sdata_info(sdata,
  				   "cannot understand ECSA IE operating class %d, disconnecting\n",
  				   elems->ext_chansw_ie->new_operating_class);
-@@ -3394,10 +3412,13 @@ static int ieee80211_probe_auth(struct i
+@@ -1110,6 +1128,15 @@ ieee80211_sta_process_chanswitch(struct 
+ 	case -1:
+ 		cfg80211_chandef_create(&new_chandef, new_chan,
+ 					NL80211_CHAN_NO_HT);
++		/* keep width for 5/10 MHz channels */
++		switch (sdata->vif.bss_conf.chandef.width) {
++		case NL80211_CHAN_WIDTH_5:
++		case NL80211_CHAN_WIDTH_10:
++			new_chandef.width = sdata->vif.bss_conf.chandef.width;
++			break;
++		default:
++			break;
++		}
+ 		break;
+ 	}
+ 
+@@ -3394,10 +3421,13 @@ static int ieee80211_probe_auth(struct i
  
  	if (tx_flags == 0) {
  		auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -1975,7 +2592,7 @@
  	}
  
  	return 0;
-@@ -3434,7 +3455,11 @@ static int ieee80211_do_assoc(struct iee
+@@ -3434,7 +3464,11 @@ static int ieee80211_do_assoc(struct iee
  		assoc_data->timeout_started = true;
  		run_again(sdata, assoc_data->timeout);
  	} else {
@@ -1988,7 +2605,7 @@
  	}
  
  	return 0;
-@@ -3829,7 +3854,7 @@ static int ieee80211_prep_channel(struct
+@@ -3829,7 +3863,7 @@ static int ieee80211_prep_channel(struct
  	ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
  						     cbss->channel,
  						     ht_oper, vht_oper,
@@ -2565,9 +3182,268 @@
  	int av_bslot;
  	bool primary_sta_vif;
  	__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
+@@ -585,19 +581,14 @@ static inline void ath_fill_led_pin(stru
+ #define ATH_ANT_DIV_COMB_MAX_COUNT 100
+ #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
+ #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
++#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI 50
++#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI 50
+ 
+ #define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
+ #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
+ #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
+ #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
+ 
+-enum ath9k_ant_div_comb_lna_conf {
+-	ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
+-	ATH_ANT_DIV_COMB_LNA2,
+-	ATH_ANT_DIV_COMB_LNA1,
+-	ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
+-};
+-
+ struct ath_ant_comb {
+ 	u16 count;
+ 	u16 total_pkt_count;
+@@ -614,27 +605,36 @@ struct ath_ant_comb {
+ 	int rssi_first;
+ 	int rssi_second;
+ 	int rssi_third;
++	int ant_ratio;
++	int ant_ratio2;
+ 	bool alt_good;
+ 	int quick_scan_cnt;
+-	int main_conf;
++	enum ath9k_ant_div_comb_lna_conf main_conf;
+ 	enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
+ 	enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
+ 	bool first_ratio;
+ 	bool second_ratio;
+ 	unsigned long scan_start_time;
++
++	/*
++	 * Card-specific config values.
++	 */
++	int low_rssi_thresh;
++	int fast_div_bias;
+ };
+ 
+ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
+-void ath_ant_comb_update(struct ath_softc *sc);
+ 
+ /********************/
+ /* Main driver core */
+ /********************/
+ 
+-#define ATH9K_PCI_CUS198 0x0001
+-#define ATH9K_PCI_CUS230 0x0002
+-#define ATH9K_PCI_CUS217 0x0004
+-#define ATH9K_PCI_WOW    0x0008
++#define ATH9K_PCI_CUS198     0x0001
++#define ATH9K_PCI_CUS230     0x0002
++#define ATH9K_PCI_CUS217     0x0004
++#define ATH9K_PCI_WOW        0x0008
++#define ATH9K_PCI_BT_ANT_DIV 0x0010
++#define ATH9K_PCI_D3_L1_WAR  0x0020
+ 
+ /*
+  * Default cache line size, in bytes.
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -607,6 +607,28 @@ static ssize_t read_file_xmit(struct fil
+@@ -270,25 +270,29 @@ static const struct file_operations fops
+ 	.llseek = default_llseek,
+ };
+ 
+-static ssize_t read_file_ant_diversity(struct file *file, char __user *user_buf,
+-				       size_t count, loff_t *ppos)
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++
++static ssize_t read_file_bt_ant_diversity(struct file *file,
++					  char __user *user_buf,
++					  size_t count, loff_t *ppos)
+ {
+ 	struct ath_softc *sc = file->private_data;
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ 	char buf[32];
+ 	unsigned int len;
+ 
+-	len = sprintf(buf, "%d\n", common->antenna_diversity);
++	len = sprintf(buf, "%d\n", common->bt_ant_diversity);
+ 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ }
+ 
+-static ssize_t write_file_ant_diversity(struct file *file,
+-					const char __user *user_buf,
+-					size_t count, loff_t *ppos)
++static ssize_t write_file_bt_ant_diversity(struct file *file,
++					   const char __user *user_buf,
++					   size_t count, loff_t *ppos)
+ {
+ 	struct ath_softc *sc = file->private_data;
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+-	unsigned long antenna_diversity;
++	struct ath9k_hw_capabilities *pCap = &sc->sc_ah->caps;
++	unsigned long bt_ant_diversity;
+ 	char buf[32];
+ 	ssize_t len;
+ 
+@@ -296,26 +300,147 @@ static ssize_t write_file_ant_diversity(
+ 	if (copy_from_user(buf, user_buf, len))
+ 		return -EFAULT;
+ 
+-	if (!AR_SREV_9565(sc->sc_ah))
++	if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
+ 		goto exit;
+ 
+ 	buf[len] = '\0';
+-	if (strict_strtoul(buf, 0, &antenna_diversity))
++	if (kstrtoul(buf, 0, &bt_ant_diversity))
+ 		return -EINVAL;
+ 
+-	common->antenna_diversity = !!antenna_diversity;
++	common->bt_ant_diversity = !!bt_ant_diversity;
+ 	ath9k_ps_wakeup(sc);
+-	ath_ant_comb_update(sc);
+-	ath_dbg(common, CONFIG, "Antenna diversity: %d\n",
+-		common->antenna_diversity);
++	ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity);
++	ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n",
++		common->bt_ant_diversity);
+ 	ath9k_ps_restore(sc);
+ exit:
+ 	return count;
+ }
+ 
+-static const struct file_operations fops_ant_diversity = {
+-	.read = read_file_ant_diversity,
+-	.write = write_file_ant_diversity,
++static const struct file_operations fops_bt_ant_diversity = {
++	.read = read_file_bt_ant_diversity,
++	.write = write_file_bt_ant_diversity,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
++#endif
++
++void ath9k_debug_stat_ant(struct ath_softc *sc,
++			  struct ath_hw_antcomb_conf *div_ant_conf,
++			  int main_rssi_avg, int alt_rssi_avg)
++{
++	struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
++	struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
++
++	as_main->lna_attempt_cnt[div_ant_conf->main_lna_conf]++;
++	as_alt->lna_attempt_cnt[div_ant_conf->alt_lna_conf]++;
++
++	as_main->rssi_avg = main_rssi_avg;
++	as_alt->rssi_avg = alt_rssi_avg;
++}
++
++static ssize_t read_file_antenna_diversity(struct file *file,
++					   char __user *user_buf,
++					   size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
++	struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
++	struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
++	struct ath_hw_antcomb_conf div_ant_conf;
++	unsigned int len = 0, size = 1024;
++	ssize_t retval = 0;
++	char *buf;
++	char *lna_conf_str[4] = {"LNA1_MINUS_LNA2",
++				 "LNA2",
++				 "LNA1",
++				 "LNA1_PLUS_LNA2"};
++
++	buf = kzalloc(size, GFP_KERNEL);
++	if (buf == NULL)
++		return -ENOMEM;
++
++	if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) {
++		len += snprintf(buf + len, size - len, "%s\n",
++				"Antenna Diversity Combining is disabled");
++		goto exit;
++	}
++
++	ath9k_ps_wakeup(sc);
++	ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
++	len += snprintf(buf + len, size - len, "Current MAIN config : %s\n",
++			lna_conf_str[div_ant_conf.main_lna_conf]);
++	len += snprintf(buf + len, size - len, "Current ALT config  : %s\n",
++			lna_conf_str[div_ant_conf.alt_lna_conf]);
++	len += snprintf(buf + len, size - len, "Average MAIN RSSI   : %d\n",
++			as_main->rssi_avg);
++	len += snprintf(buf + len, size - len, "Average ALT RSSI    : %d\n\n",
++			as_alt->rssi_avg);
++	ath9k_ps_restore(sc);
++
++	len += snprintf(buf + len, size - len, "Packet Receive Cnt:\n");
++	len += snprintf(buf + len, size - len, "-------------------\n");
++
++	len += snprintf(buf + len, size - len, "%30s%15s\n",
++			"MAIN", "ALT");
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"TOTAL COUNT",
++			as_main->recv_cnt,
++			as_alt->recv_cnt);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA1",
++			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1],
++			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA2",
++			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2],
++			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA1 + LNA2",
++			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
++			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA1 - LNA2",
++			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
++			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
++
++	len += snprintf(buf + len, size - len, "\nLNA Config Attempts:\n");
++	len += snprintf(buf + len, size - len, "--------------------\n");
++
++	len += snprintf(buf + len, size - len, "%30s%15s\n",
++			"MAIN", "ALT");
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA1",
++			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1],
++			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA2",
++			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2],
++			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA1 + LNA2",
++			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
++			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
++	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
++			"LNA1 - LNA2",
++			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
++			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
++
++exit:
++	if (len > size)
++		len = size;
++
++	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++	kfree(buf);
++
++	return retval;
++}
++
++static const struct file_operations fops_antenna_diversity = {
++	.read = read_file_antenna_diversity,
+ 	.open = simple_open,
+ 	.owner = THIS_MODULE,
+ 	.llseek = default_llseek,
+@@ -607,6 +732,28 @@ static ssize_t read_file_xmit(struct fil
  	return retval;
  }
  
@@ -2596,7 +3472,7 @@
  static ssize_t read_file_queues(struct file *file, char __user *user_buf,
  				size_t count, loff_t *ppos)
  {
-@@ -624,24 +646,13 @@ static ssize_t read_file_queues(struct f
+@@ -624,24 +771,13 @@ static ssize_t read_file_queues(struct f
  
  	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
  		txq = sc->tx.txq_map[i];
@@ -2626,9 +3502,30 @@
  	if (len > size)
  		len = size;
  
+@@ -1818,9 +1954,11 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
+ 	debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
+ 			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
+-	debugfs_create_file("diversity", S_IRUSR | S_IWUSR,
+-			    sc->debug.debugfs_phy, sc, &fops_ant_diversity);
++	debugfs_create_file("antenna_diversity", S_IRUSR,
++			    sc->debug.debugfs_phy, sc, &fops_antenna_diversity);
+ #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++	debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR,
++			    sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity);
+ 	debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
+ 			    &fops_btcoex);
+ #endif
 --- a/net/mac80211/ibss.c
 +++ b/net/mac80211/ibss.c
-@@ -36,7 +36,7 @@
+@@ -30,13 +30,14 @@
+ 
+ #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
+ #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
++#define IEEE80211_IBSS_RSN_INACTIVITY_LIMIT (10 * HZ)
+ 
+ #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+ 
  
  static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
  				      const u8 *bssid, const int beacon_int,
@@ -2637,7 +3534,7 @@
  				      const u32 basic_rates,
  				      const u16 capability, u64 tsf,
  				      bool creator)
-@@ -51,6 +51,7 @@ static void __ieee80211_sta_join_ibss(st
+@@ -51,6 +52,7 @@ static void __ieee80211_sta_join_ibss(st
  	u32 bss_change;
  	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
  	struct cfg80211_chan_def chandef;
@@ -2645,7 +3542,7 @@
  	struct beacon_data *presp;
  	int frame_len;
  
-@@ -81,7 +82,9 @@ static void __ieee80211_sta_join_ibss(st
+@@ -81,7 +83,9 @@ static void __ieee80211_sta_join_ibss(st
  
  	sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
  
@@ -2656,7 +3553,7 @@
  	if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
  		chandef.width = NL80211_CHAN_WIDTH_20;
  		chandef.center_freq1 = chan->center_freq;
-@@ -259,10 +262,12 @@ static void ieee80211_sta_join_ibss(stru
+@@ -259,10 +263,12 @@ static void ieee80211_sta_join_ibss(stru
  	struct cfg80211_bss *cbss =
  		container_of((void *)bss, struct cfg80211_bss, priv);
  	struct ieee80211_supported_band *sband;
@@ -2669,7 +3566,7 @@
  	u64 tsf;
  
  	sdata_assert_lock(sdata);
-@@ -270,6 +275,26 @@ static void ieee80211_sta_join_ibss(stru
+@@ -270,6 +276,26 @@ static void ieee80211_sta_join_ibss(stru
  	if (beacon_int < 10)
  		beacon_int = 10;
  
@@ -2696,7 +3593,7 @@
  	sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
  
  	basic_rates = 0;
-@@ -294,7 +319,7 @@ static void ieee80211_sta_join_ibss(stru
+@@ -294,7 +320,7 @@ static void ieee80211_sta_join_ibss(stru
  
  	__ieee80211_sta_join_ibss(sdata, cbss->bssid,
  				  beacon_int,
@@ -2705,7 +3602,50 @@
  				  basic_rates,
  				  cbss->capability,
  				  tsf, false);
-@@ -736,7 +761,7 @@ static void ieee80211_sta_create_ibss(st
+@@ -672,6 +698,33 @@ static int ieee80211_sta_active_ibss(str
+ 	return active;
+ }
+ 
++static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct sta_info *sta, *tmp;
++	unsigned long exp_time = IEEE80211_IBSS_INACTIVITY_LIMIT;
++	unsigned long exp_rsn_time = IEEE80211_IBSS_RSN_INACTIVITY_LIMIT;
++
++	mutex_lock(&local->sta_mtx);
++
++	list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
++		if (sdata != sta->sdata)
++			continue;
++
++		if (time_after(jiffies, sta->last_rx + exp_time) ||
++		    (time_after(jiffies, sta->last_rx + exp_rsn_time) &&
++		     sta->sta_state != IEEE80211_STA_AUTHORIZED)) {
++			sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n",
++				sta->sta_state != IEEE80211_STA_AUTHORIZED ?
++				"not authorized " : "", sta->sta.addr);
++
++			WARN_ON(__sta_info_destroy(sta));
++		}
++	}
++
++	mutex_unlock(&local->sta_mtx);
++}
++
+ /*
+  * This function is called with state == IEEE80211_IBSS_MLME_JOINED
+  */
+@@ -685,7 +738,7 @@ static void ieee80211_sta_merge_ibss(str
+ 	mod_timer(&ifibss->timer,
+ 		  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
+ 
+-	ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
++	ieee80211_ibss_sta_expire(sdata);
+ 
+ 	if (time_before(jiffies, ifibss->last_scan_completed +
+ 		       IEEE80211_IBSS_MERGE_INTERVAL))
+@@ -736,7 +789,7 @@ static void ieee80211_sta_create_ibss(st
  		sdata->drop_unencrypted = 0;
  
  	__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
@@ -2714,7 +3654,7 @@
  				  capability, 0, true);
  }
  
-@@ -792,6 +817,17 @@ static void ieee80211_sta_find_ibss(stru
+@@ -792,6 +845,17 @@ static void ieee80211_sta_find_ibss(stru
  		return;
  	}
  
@@ -2732,7 +3672,7 @@
  	ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n");
  
  	/* Selected IBSS not found in current scan results - try to scan */
-@@ -1138,6 +1174,7 @@ int ieee80211_ibss_leave(struct ieee8021
+@@ -1138,6 +1202,7 @@ int ieee80211_ibss_leave(struct ieee8021
  	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
  	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
  						BSS_CHANGED_IBSS);
@@ -2742,7 +3682,60 @@
  
 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
 +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1173,6 +1173,10 @@ skip_ws_det:
+@@ -632,6 +632,22 @@ static void ar9003_hw_override_ini(struc
+ 
+ 	REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
+ 		    AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
++
++	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
++		REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
++			  AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
++
++		if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
++				   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
++			ah->enabled_cals |= TX_IQ_CAL;
++		else
++			ah->enabled_cals &= ~TX_IQ_CAL;
++
++		if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
++			ah->enabled_cals |= TX_CL_CAL;
++		else
++			ah->enabled_cals &= ~TX_CL_CAL;
++	}
+ }
+ 
+ static void ar9003_hw_prog_ini(struct ath_hw *ah,
+@@ -814,29 +830,12 @@ static int ar9003_hw_process_ini(struct 
+ 	if (chan->channel == 2484)
+ 		ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
+ 
+-	if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
+-		REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
+-			  AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
+-
+ 	ah->modes_index = modesIndex;
+ 	ar9003_hw_override_ini(ah);
+ 	ar9003_hw_set_channel_regs(ah, chan);
+ 	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+ 	ath9k_hw_apply_txpower(ah, chan, false);
+ 
+-	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+-		if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+-				   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
+-			ah->enabled_cals |= TX_IQ_CAL;
+-		else
+-			ah->enabled_cals &= ~TX_IQ_CAL;
+-
+-		if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
+-			ah->enabled_cals |= TX_CL_CAL;
+-		else
+-			ah->enabled_cals &= ~TX_CL_CAL;
+-	}
+-
+ 	return 0;
+ }
+ 
+@@ -1173,6 +1172,10 @@ skip_ws_det:
  		 * is_on == 0 means MRC CCK is OFF (more noise imm)
  		 */
  		bool is_on = param ? 1 : 0;
@@ -2753,40 +3746,250 @@
  		REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
  			      AR_PHY_MRC_CCK_ENABLE, is_on);
  		REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -42,8 +42,6 @@ static void ath_rx_buf_link(struct ath_s
- 	struct ath_desc *ds;
- 	struct sk_buff *skb;
- 
--	ATH_RXBUF_RESET(bf);
--
- 	ds = bf->bf_desc;
- 	ds->ds_link = 0; /* link to null */
- 	ds->ds_data = bf->bf_buf_addr;
-@@ -70,6 +68,14 @@ static void ath_rx_buf_link(struct ath_s
- 	sc->rx.rxlink = &ds->ds_link;
+@@ -1413,65 +1416,111 @@ static void ar9003_hw_antdiv_comb_conf_s
+ 	REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
  }
  
-+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf)
-+{
-+	if (sc->rx.buf_hold)
-+		ath_rx_buf_link(sc, sc->rx.buf_hold);
-+
-+	sc->rx.buf_hold = bf;
-+}
+-static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
+-						  bool enable)
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
 +
- static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
++static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
  {
- 	/* XXX block beacon interrupts */
-@@ -117,7 +123,6 @@ static bool ath_rx_edma_buf_link(struct 
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
+ 	u8 ant_div_ctl1;
+ 	u32 regval;
  
- 	skb = bf->bf_mpdu;
+-	if (!AR_SREV_9565(ah))
++	if (!AR_SREV_9485(ah) && !AR_SREV_9565(ah))
+ 		return;
+ 
+-	ah->shared_chain_lnadiv = enable;
++	if (AR_SREV_9485(ah)) {
++		regval = ar9003_hw_ant_ctrl_common_2_get(ah,
++						 IS_CHAN_2GHZ(ah->curchan));
++		if (enable) {
++			regval &= ~AR_SWITCH_TABLE_COM2_ALL;
++			regval |= ah->config.ant_ctrl_comm2g_switch_enable;
++		}
++		REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2,
++			      AR_SWITCH_TABLE_COM2_ALL, regval);
++	}
++
+ 	ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ 
++	/*
++	 * Set MAIN/ALT LNA conf.
++	 * Set MAIN/ALT gain_tb.
++	 */
+ 	regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ 	regval &= (~AR_ANT_DIV_CTRL_ALL);
+ 	regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S;
+-	regval &= ~AR_PHY_ANT_DIV_LNADIV;
+-	regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
+-
+-	if (enable)
+-		regval |= AR_ANT_DIV_ENABLE;
+-
+ 	REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+ 
+-	regval = REG_READ(ah, AR_PHY_CCK_DETECT);
+-	regval &= ~AR_FAST_DIV_ENABLE;
+-	regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
+-
+-	if (enable)
+-		regval |= AR_FAST_DIV_ENABLE;
+-
+-	REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
+-
+-	if (enable) {
+-		REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
+-			    (1 << AR_PHY_ANT_SW_RX_PROT_S));
+-		if (ah->curchan && IS_CHAN_2GHZ(ah->curchan))
+-			REG_SET_BIT(ah, AR_PHY_RESTART,
+-				    AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
+-		REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
+-			    AR_BTCOEX_WL_LNADIV_FORCE_ON);
+-	} else {
+-		REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE);
+-		REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
+-			    (1 << AR_PHY_ANT_SW_RX_PROT_S));
+-		REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE);
+-		REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
+-			    AR_BTCOEX_WL_LNADIV_FORCE_ON);
+-
++	if (AR_SREV_9485_11_OR_LATER(ah)) {
++		/*
++		 * Enable LNA diversity.
++		 */
+ 		regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+-		regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF |
+-			AR_PHY_ANT_DIV_ALT_LNACONF |
+-			AR_PHY_ANT_DIV_MAIN_GAINTB |
+-			AR_PHY_ANT_DIV_ALT_GAINTB);
+-		regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S);
+-		regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S);
++		regval &= ~AR_PHY_ANT_DIV_LNADIV;
++		regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
++		if (enable)
++			regval |= AR_ANT_DIV_ENABLE;
++
+ 		REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
++
++		/*
++		 * Enable fast antenna diversity.
++		 */
++		regval = REG_READ(ah, AR_PHY_CCK_DETECT);
++		regval &= ~AR_FAST_DIV_ENABLE;
++		regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
++		if (enable)
++			regval |= AR_FAST_DIV_ENABLE;
++
++		REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
++
++		if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
++			regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
++			regval &= (~(AR_PHY_ANT_DIV_MAIN_LNACONF |
++				     AR_PHY_ANT_DIV_ALT_LNACONF |
++				     AR_PHY_ANT_DIV_ALT_GAINTB |
++				     AR_PHY_ANT_DIV_MAIN_GAINTB));
++			/*
++			 * Set MAIN to LNA1 and ALT to LNA2 at the
++			 * beginning.
++			 */
++			regval |= (ATH_ANT_DIV_COMB_LNA1 <<
++				   AR_PHY_ANT_DIV_MAIN_LNACONF_S);
++			regval |= (ATH_ANT_DIV_COMB_LNA2 <<
++				   AR_PHY_ANT_DIV_ALT_LNACONF_S);
++			REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
++		}
++	} else if (AR_SREV_9565(ah)) {
++		if (enable) {
++			REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
++				    (1 << AR_PHY_ANT_SW_RX_PROT_S));
++			if (ah->curchan && IS_CHAN_2GHZ(ah->curchan))
++				REG_SET_BIT(ah, AR_PHY_RESTART,
++					    AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
++			REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
++				    AR_BTCOEX_WL_LNADIV_FORCE_ON);
++		} else {
++			REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE);
++			REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
++				    (1 << AR_PHY_ANT_SW_RX_PROT_S));
++			REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE);
++			REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
++				    AR_BTCOEX_WL_LNADIV_FORCE_ON);
++
++			regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
++			regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF |
++				    AR_PHY_ANT_DIV_ALT_LNACONF |
++				    AR_PHY_ANT_DIV_MAIN_GAINTB |
++				    AR_PHY_ANT_DIV_ALT_GAINTB);
++			regval |= (ATH_ANT_DIV_COMB_LNA1 <<
++				   AR_PHY_ANT_DIV_MAIN_LNACONF_S);
++			regval |= (ATH_ANT_DIV_COMB_LNA2 <<
++				   AR_PHY_ANT_DIV_ALT_LNACONF_S);
++			REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
++		}
+ 	}
+ }
+ 
++#endif
++
+ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
+ 				      struct ath9k_channel *chan,
+ 				      u8 *ini_reloaded)
+@@ -1518,6 +1567,18 @@ static int ar9003_hw_fast_chan_change(st
+ 
+ 	REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+ 
++	if (AR_SREV_9462_20_OR_LATER(ah)) {
++		/*
++		 * CUS217 mix LNA mode.
++		 */
++		if (ar9003_hw_get_rx_gain_idx(ah) == 2) {
++			REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_core,
++					1, regWrites);
++			REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_postamble,
++					modesIndex, regWrites);
++		}
++	}
++
+ 	/*
+ 	 * For 5GHz channels requiring Fast Clock, apply
+ 	 * different modal values.
+@@ -1528,7 +1589,11 @@ static int ar9003_hw_fast_chan_change(st
+ 	if (AR_SREV_9565(ah))
+ 		REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites);
+ 
+-	REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
++	/*
++	 * JAPAN regulatory.
++	 */
++	if (chan->channel == 2484)
++		ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
+ 
+ 	ah->modes_index = modesIndex;
+ 	*ini_reloaded = true;
+@@ -1631,11 +1696,14 @@ void ar9003_hw_attach_phy_ops(struct ath
+ 
+ 	ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
+ 	ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
+-	ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
+ 	ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+ 	ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
+ 	ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
+ 
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++	ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity;
++#endif
++
+ 	ar9003_hw_set_nf_limits(ah);
+ 	ar9003_hw_set_radar_conf(ah);
+ 	memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -42,8 +42,6 @@ static void ath_rx_buf_link(struct ath_s
+ 	struct ath_desc *ds;
+ 	struct sk_buff *skb;
+ 
+-	ATH_RXBUF_RESET(bf);
+-
+ 	ds = bf->bf_desc;
+ 	ds->ds_link = 0; /* link to null */
+ 	ds->ds_data = bf->bf_buf_addr;
+@@ -70,6 +68,14 @@ static void ath_rx_buf_link(struct ath_s
+ 	sc->rx.rxlink = &ds->ds_link;
+ }
+ 
++static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf)
++{
++	if (sc->rx.buf_hold)
++		ath_rx_buf_link(sc, sc->rx.buf_hold);
++
++	sc->rx.buf_hold = bf;
++}
++
+ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
+ {
+ 	/* XXX block beacon interrupts */
+@@ -117,7 +123,6 @@ static bool ath_rx_edma_buf_link(struct 
+ 
+ 	skb = bf->bf_mpdu;
  
 -	ATH_RXBUF_RESET(bf);
  	memset(skb->data, 0, ah->caps.rx_status_len);
  	dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
  				ah->caps.rx_status_len, DMA_TO_DEVICE);
+@@ -185,7 +190,7 @@ static void ath_rx_edma_cleanup(struct a
+ 
+ static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
+ {
+-	skb_queue_head_init(&rx_edma->rx_fifo);
++	__skb_queue_head_init(&rx_edma->rx_fifo);
+ 	rx_edma->rx_fifo_hwsize = size;
+ }
+ 
 @@ -432,6 +437,7 @@ int ath_startrecv(struct ath_softc *sc)
  	if (list_empty(&sc->rx.rxbuf))
  		goto start_recv;
@@ -2805,7 +4008,579 @@
  	ds = bf->bf_desc;
  
  	/*
-@@ -1375,7 +1384,7 @@ requeue:
+@@ -755,7 +764,6 @@ static bool ath9k_rx_accept(struct ath_c
+ 	bool is_mc, is_valid_tkip, strip_mic, mic_error;
+ 	struct ath_hw *ah = common->ah;
+ 	__le16 fc;
+-	u8 rx_status_len = ah->caps.rx_status_len;
+ 
+ 	fc = hdr->frame_control;
+ 
+@@ -777,25 +785,6 @@ static bool ath9k_rx_accept(struct ath_c
+ 	    !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
+ 		rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
+ 
+-	if (!rx_stats->rs_datalen) {
+-		RX_STAT_INC(rx_len_err);
+-		return false;
+-	}
+-
+-        /*
+-         * rs_status follows rs_datalen so if rs_datalen is too large
+-         * we can take a hint that hardware corrupted it, so ignore
+-         * those frames.
+-         */
+-	if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) {
+-		RX_STAT_INC(rx_len_err);
+-		return false;
+-	}
+-
+-	/* Only use error bits from the last fragment */
+-	if (rx_stats->rs_more)
+-		return true;
+-
+ 	mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) &&
+ 		!ieee80211_has_morefrags(fc) &&
+ 		!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
+@@ -814,8 +803,6 @@ static bool ath9k_rx_accept(struct ath_c
+ 			rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
+ 			mic_error = false;
+ 		}
+-		if (rx_stats->rs_status & ATH9K_RXERR_PHY)
+-			return false;
+ 
+ 		if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
+ 		    (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
+@@ -898,129 +885,65 @@ static int ath9k_process_rate(struct ath
+ 
+ static void ath9k_process_rssi(struct ath_common *common,
+ 			       struct ieee80211_hw *hw,
+-			       struct ieee80211_hdr *hdr,
+-			       struct ath_rx_status *rx_stats)
++			       struct ath_rx_status *rx_stats,
++			       struct ieee80211_rx_status *rxs)
+ {
+ 	struct ath_softc *sc = hw->priv;
+ 	struct ath_hw *ah = common->ah;
+ 	int last_rssi;
+ 	int rssi = rx_stats->rs_rssi;
+ 
+-	if (!rx_stats->is_mybeacon ||
+-	    ((ah->opmode != NL80211_IFTYPE_STATION) &&
+-	     (ah->opmode != NL80211_IFTYPE_ADHOC)))
++	/*
++	 * RSSI is not available for subframes in an A-MPDU.
++	 */
++	if (rx_stats->rs_moreaggr) {
++		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ 		return;
+-
+-	if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
+-		ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi);
+-
+-	last_rssi = sc->last_rssi;
+-	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+-		rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
+-	if (rssi < 0)
+-		rssi = 0;
+-
+-	/* Update Beacon RSSI, this is used by ANI. */
+-	ah->stats.avgbrssi = rssi;
+-}
+-
+-/*
+- * For Decrypt or Demic errors, we only mark packet status here and always push
+- * up the frame up to let mac80211 handle the actual error case, be it no
+- * decryption key or real decryption error. This let us keep statistics there.
+- */
+-static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
+-				   struct ieee80211_hdr *hdr,
+-				   struct ath_rx_status *rx_stats,
+-				   struct ieee80211_rx_status *rx_status,
+-				   bool *decrypt_error)
+-{
+-	struct ieee80211_hw *hw = sc->hw;
+-	struct ath_hw *ah = sc->sc_ah;
+-	struct ath_common *common = ath9k_hw_common(ah);
+-	bool discard_current = sc->rx.discard_next;
+-
+-	sc->rx.discard_next = rx_stats->rs_more;
+-	if (discard_current)
+-		return -EINVAL;
++	}
+ 
+ 	/*
+-	 * everything but the rate is checked here, the rate check is done
+-	 * separately to avoid doing two lookups for a rate for each frame.
++	 * Check if the RSSI for the last subframe in an A-MPDU
++	 * or an unaggregated frame is valid.
+ 	 */
+-	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+-		return -EINVAL;
+-
+-	/* Only use status info from the last fragment */
+-	if (rx_stats->rs_more)
+-		return 0;
++	if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) {
++		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
++		return;
++	}
+ 
+-	if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+-		return -EINVAL;
++	/*
++	 * Update Beacon RSSI, this is used by ANI.
++	 */
++	if (rx_stats->is_mybeacon &&
++	    ((ah->opmode == NL80211_IFTYPE_STATION) ||
++	     (ah->opmode == NL80211_IFTYPE_ADHOC))) {
++		ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi);
++		last_rssi = sc->last_rssi;
+ 
+-	ath9k_process_rssi(common, hw, hdr, rx_stats);
++		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
++			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
++		if (rssi < 0)
++			rssi = 0;
+ 
+-	rx_status->band = hw->conf.chandef.chan->band;
+-	rx_status->freq = hw->conf.chandef.chan->center_freq;
+-	rx_status->signal = ah->noise + rx_stats->rs_rssi;
+-	rx_status->antenna = rx_stats->rs_antenna;
+-	rx_status->flag |= RX_FLAG_MACTIME_END;
+-	if (rx_stats->rs_moreaggr)
+-		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
++		ah->stats.avgbrssi = rssi;
++	}
+ 
+-	sc->rx.discard_next = false;
+-	return 0;
++	rxs->signal = ah->noise + rx_stats->rs_rssi;
+ }
+ 
+-static void ath9k_rx_skb_postprocess(struct ath_common *common,
+-				     struct sk_buff *skb,
+-				     struct ath_rx_status *rx_stats,
+-				     struct ieee80211_rx_status *rxs,
+-				     bool decrypt_error)
++static void ath9k_process_tsf(struct ath_rx_status *rs,
++			      struct ieee80211_rx_status *rxs,
++			      u64 tsf)
+ {
+-	struct ath_hw *ah = common->ah;
+-	struct ieee80211_hdr *hdr;
+-	int hdrlen, padpos, padsize;
+-	u8 keyix;
+-	__le16 fc;
++	u32 tsf_lower = tsf & 0xffffffff;
+ 
+-	/* see if any padding is done by the hw and remove it */
+-	hdr = (struct ieee80211_hdr *) skb->data;
+-	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+-	fc = hdr->frame_control;
+-	padpos = ieee80211_hdrlen(fc);
++	rxs->mactime = (tsf & ~0xffffffffULL) | rs->rs_tstamp;
++	if (rs->rs_tstamp > tsf_lower &&
++	    unlikely(rs->rs_tstamp - tsf_lower > 0x10000000))
++		rxs->mactime -= 0x100000000ULL;
+ 
+-	/* The MAC header is padded to have 32-bit boundary if the
+-	 * packet payload is non-zero. The general calculation for
+-	 * padsize would take into account odd header lengths:
+-	 * padsize = (4 - padpos % 4) % 4; However, since only
+-	 * even-length headers are used, padding can only be 0 or 2
+-	 * bytes and we can optimize this a bit. In addition, we must
+-	 * not try to remove padding from short control frames that do
+-	 * not have payload. */
+-	padsize = padpos & 3;
+-	if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+-		memmove(skb->data + padsize, skb->data, padpos);
+-		skb_pull(skb, padsize);
+-	}
+-
+-	keyix = rx_stats->rs_keyix;
+-
+-	if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+-	    ieee80211_has_protected(fc)) {
+-		rxs->flag |= RX_FLAG_DECRYPTED;
+-	} else if (ieee80211_has_protected(fc)
+-		   && !decrypt_error && skb->len >= hdrlen + 4) {
+-		keyix = skb->data[hdrlen + 3] >> 6;
+-
+-		if (test_bit(keyix, common->keymap))
+-			rxs->flag |= RX_FLAG_DECRYPTED;
+-	}
+-	if (ah->sw_mgmt_crypto &&
+-	    (rxs->flag & RX_FLAG_DECRYPTED) &&
+-	    ieee80211_is_mgmt(fc))
+-		/* Use software decrypt for management frames. */
+-		rxs->flag &= ~RX_FLAG_DECRYPTED;
++	if (rs->rs_tstamp < tsf_lower &&
++	    unlikely(tsf_lower - rs->rs_tstamp > 0x10000000))
++		rxs->mactime += 0x100000000ULL;
+ }
+ 
+ #ifdef CPTCFG_ATH9K_DEBUGFS
+@@ -1133,6 +1056,234 @@ static int ath_process_fft(struct ath_so
+ #endif
+ }
+ 
++static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
++{
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath_common *common = ath9k_hw_common(ah);
++
++	if (ieee80211_is_beacon(hdr->frame_control)) {
++		RX_STAT_INC(rx_beacons);
++		if (!is_zero_ether_addr(common->curbssid) &&
++		    ether_addr_equal(hdr->addr3, common->curbssid))
++			return true;
++	}
++
++	return false;
++}
++
++/*
++ * For Decrypt or Demic errors, we only mark packet status here and always push
++ * up the frame up to let mac80211 handle the actual error case, be it no
++ * decryption key or real decryption error. This let us keep statistics there.
++ */
++static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
++				   struct sk_buff *skb,
++				   struct ath_rx_status *rx_stats,
++				   struct ieee80211_rx_status *rx_status,
++				   bool *decrypt_error, u64 tsf)
++{
++	struct ieee80211_hw *hw = sc->hw;
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath_common *common = ath9k_hw_common(ah);
++	struct ieee80211_hdr *hdr;
++	bool discard_current = sc->rx.discard_next;
++	int ret = 0;
++
++	/*
++	 * Discard corrupt descriptors which are marked in
++	 * ath_get_next_rx_buf().
++	 */
++	sc->rx.discard_next = rx_stats->rs_more;
++	if (discard_current)
++		return -EINVAL;
++
++	/*
++	 * Discard zero-length packets.
++	 */
++	if (!rx_stats->rs_datalen) {
++		RX_STAT_INC(rx_len_err);
++		return -EINVAL;
++	}
++
++        /*
++         * rs_status follows rs_datalen so if rs_datalen is too large
++         * we can take a hint that hardware corrupted it, so ignore
++         * those frames.
++         */
++	if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
++		RX_STAT_INC(rx_len_err);
++		return -EINVAL;
++	}
++
++	/* Only use status info from the last fragment */
++	if (rx_stats->rs_more)
++		return 0;
++
++	/*
++	 * Return immediately if the RX descriptor has been marked
++	 * as corrupt based on the various error bits.
++	 *
++	 * This is different from the other corrupt descriptor
++	 * condition handled above.
++	 */
++	if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
++
++	ath9k_process_tsf(rx_stats, rx_status, tsf);
++	ath_debug_stat_rx(sc, rx_stats);
++
++	/*
++	 * Process PHY errors and return so that the packet
++	 * can be dropped.
++	 */
++	if (rx_stats->rs_status & ATH9K_RXERR_PHY) {
++		ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime);
++		if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
++			RX_STAT_INC(rx_spectral);
++
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	/*
++	 * everything but the rate is checked here, the rate check is done
++	 * separately to avoid doing two lookups for a rate for each frame.
++	 */
++	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
++	if (rx_stats->is_mybeacon) {
++		sc->hw_busy_count = 0;
++		ath_start_rx_poll(sc, 3);
++	}
++
++	if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
++		ret =-EINVAL;
++		goto exit;
++	}
++
++	ath9k_process_rssi(common, hw, rx_stats, rx_status);
++
++	rx_status->band = hw->conf.chandef.chan->band;
++	rx_status->freq = hw->conf.chandef.chan->center_freq;
++	rx_status->antenna = rx_stats->rs_antenna;
++	rx_status->flag |= RX_FLAG_MACTIME_END;
++
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++	if (ieee80211_is_data_present(hdr->frame_control) &&
++	    !ieee80211_is_qos_nullfunc(hdr->frame_control))
++		sc->rx.num_pkts++;
++#endif
++
++exit:
++	sc->rx.discard_next = false;
++	return ret;
++}
++
++static void ath9k_rx_skb_postprocess(struct ath_common *common,
++				     struct sk_buff *skb,
++				     struct ath_rx_status *rx_stats,
++				     struct ieee80211_rx_status *rxs,
++				     bool decrypt_error)
++{
++	struct ath_hw *ah = common->ah;
++	struct ieee80211_hdr *hdr;
++	int hdrlen, padpos, padsize;
++	u8 keyix;
++	__le16 fc;
++
++	/* see if any padding is done by the hw and remove it */
++	hdr = (struct ieee80211_hdr *) skb->data;
++	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
++	fc = hdr->frame_control;
++	padpos = ieee80211_hdrlen(fc);
++
++	/* The MAC header is padded to have 32-bit boundary if the
++	 * packet payload is non-zero. The general calculation for
++	 * padsize would take into account odd header lengths:
++	 * padsize = (4 - padpos % 4) % 4; However, since only
++	 * even-length headers are used, padding can only be 0 or 2
++	 * bytes and we can optimize this a bit. In addition, we must
++	 * not try to remove padding from short control frames that do
++	 * not have payload. */
++	padsize = padpos & 3;
++	if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
++		memmove(skb->data + padsize, skb->data, padpos);
++		skb_pull(skb, padsize);
++	}
++
++	keyix = rx_stats->rs_keyix;
++
++	if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
++	    ieee80211_has_protected(fc)) {
++		rxs->flag |= RX_FLAG_DECRYPTED;
++	} else if (ieee80211_has_protected(fc)
++		   && !decrypt_error && skb->len >= hdrlen + 4) {
++		keyix = skb->data[hdrlen + 3] >> 6;
++
++		if (test_bit(keyix, common->keymap))
++			rxs->flag |= RX_FLAG_DECRYPTED;
++	}
++	if (ah->sw_mgmt_crypto &&
++	    (rxs->flag & RX_FLAG_DECRYPTED) &&
++	    ieee80211_is_mgmt(fc))
++		/* Use software decrypt for management frames. */
++		rxs->flag &= ~RX_FLAG_DECRYPTED;
++}
++
++/*
++ * Run the LNA combining algorithm only in these cases:
++ *
++ * Standalone WLAN cards with both LNA/Antenna diversity
++ * enabled in the EEPROM.
++ *
++ * WLAN+BT cards which are in the supported card list
++ * in ath_pci_id_table and the user has loaded the
++ * driver with "bt_ant_diversity" set to true.
++ */
++static void ath9k_antenna_check(struct ath_softc *sc,
++				struct ath_rx_status *rs)
++{
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
++	struct ath_common *common = ath9k_hw_common(ah);
++
++	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB))
++		return;
++
++	/*
++	 * All MPDUs in an aggregate will use the same LNA
++	 * as the first MPDU.
++	 */
++	if (rs->rs_isaggr && !rs->rs_firstaggr)
++		return;
++
++	/*
++	 * Change the default rx antenna if rx diversity
++	 * chooses the other antenna 3 times in a row.
++	 */
++	if (sc->rx.defant != rs->rs_antenna) {
++		if (++sc->rx.rxotherant >= 3)
++			ath_setdefantenna(sc, rs->rs_antenna);
++	} else {
++		sc->rx.rxotherant = 0;
++	}
++
++	if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) {
++		if (common->bt_ant_diversity)
++			ath_ant_comb_scan(sc, rs);
++	} else {
++		ath_ant_comb_scan(sc, rs);
++	}
++}
++
+ static void ath9k_apply_ampdu_details(struct ath_softc *sc,
+ 	struct ath_rx_status *rs, struct ieee80211_rx_status *rxs)
+ {
+@@ -1159,15 +1310,12 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 	struct ieee80211_hw *hw = sc->hw;
+-	struct ieee80211_hdr *hdr;
+ 	int retval;
+ 	struct ath_rx_status rs;
+ 	enum ath9k_rx_qtype qtype;
+ 	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
+ 	int dma_type;
+-	u8 rx_status_len = ah->caps.rx_status_len;
+ 	u64 tsf = 0;
+-	u32 tsf_lower = 0;
+ 	unsigned long flags;
+ 	dma_addr_t new_buf_addr;
+ 
+@@ -1179,7 +1327,6 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 	qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
+ 
+ 	tsf = ath9k_hw_gettsf64(ah);
+-	tsf_lower = tsf & 0xffffffff;
+ 
+ 	do {
+ 		bool decrypt_error = false;
+@@ -1206,55 +1353,14 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 		else
+ 			hdr_skb = skb;
+ 
+-		hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len);
+ 		rxs = IEEE80211_SKB_RXCB(hdr_skb);
+-		if (ieee80211_is_beacon(hdr->frame_control)) {
+-			RX_STAT_INC(rx_beacons);
+-			if (!is_zero_ether_addr(common->curbssid) &&
+-			    ether_addr_equal(hdr->addr3, common->curbssid))
+-				rs.is_mybeacon = true;
+-			else
+-				rs.is_mybeacon = false;
+-		}
+-		else
+-			rs.is_mybeacon = false;
+-
+-		if (ieee80211_is_data_present(hdr->frame_control) &&
+-		    !ieee80211_is_qos_nullfunc(hdr->frame_control))
+-			sc->rx.num_pkts++;
+-
+-		ath_debug_stat_rx(sc, &rs);
+-
+ 		memset(rxs, 0, sizeof(struct ieee80211_rx_status));
+ 
+-		rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
+-		if (rs.rs_tstamp > tsf_lower &&
+-		    unlikely(rs.rs_tstamp - tsf_lower > 0x10000000))
+-			rxs->mactime -= 0x100000000ULL;
+-
+-		if (rs.rs_tstamp < tsf_lower &&
+-		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
+-			rxs->mactime += 0x100000000ULL;
+-
+-		if (rs.rs_phyerr == ATH9K_PHYERR_RADAR)
+-			ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime);
+-
+-		if (rs.rs_status & ATH9K_RXERR_PHY) {
+-			if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {
+-				RX_STAT_INC(rx_spectral);
+-				goto requeue_drop_frag;
+-			}
+-		}
+-
+-		retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs,
+-						 &decrypt_error);
++		retval = ath9k_rx_skb_preprocess(sc, hdr_skb, &rs, rxs,
++						 &decrypt_error, tsf);
+ 		if (retval)
+ 			goto requeue_drop_frag;
+ 
+-		if (rs.is_mybeacon) {
+-			sc->hw_busy_count = 0;
+-			ath_start_rx_poll(sc, 3);
+-		}
+ 		/* Ensure we always have an skb to requeue once we are done
+ 		 * processing the current buffer's skb */
+ 		requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
+@@ -1308,8 +1414,6 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 			sc->rx.frag = skb;
+ 			goto requeue;
+ 		}
+-		if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC)
+-			goto requeue_drop_frag;
+ 
+ 		if (sc->rx.frag) {
+ 			int space = skb->len - skb_tailroom(hdr_skb);
+@@ -1328,22 +1432,6 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 			skb = hdr_skb;
+ 		}
+ 
+-
+-		if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
+-
+-			/*
+-			 * change the default rx antenna if rx diversity
+-			 * chooses the other antenna 3 times in a row.
+-			 */
+-			if (sc->rx.defant != rs.rs_antenna) {
+-				if (++sc->rx.rxotherant >= 3)
+-					ath_setdefantenna(sc, rs.rs_antenna);
+-			} else {
+-				sc->rx.rxotherant = 0;
+-			}
+-
+-		}
+-
+ 		if (rxs->flag & RX_FLAG_MMIC_STRIPPED)
+ 			skb_trim(skb, skb->len - 8);
+ 
+@@ -1355,8 +1443,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 			ath_rx_ps(sc, skb, rs.is_mybeacon);
+ 		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ 
+-		if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
+-			ath_ant_comb_scan(sc, &rs);
++		ath9k_antenna_check(sc, &rs);
+ 
+ 		ath9k_apply_ampdu_details(sc, &rs, rxs);
+ 
+@@ -1375,7 +1462,7 @@ requeue:
  		if (edma) {
  			ath_rx_edma_buf_link(sc, qtype);
  		} else {
@@ -2816,7 +4591,110 @@
  	} while (1);
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -802,7 +802,8 @@ void ath9k_set_hw_capab(struct ath_softc
+@@ -53,9 +53,9 @@ static int ath9k_btcoex_enable;
+ module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
+ MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
+ 
+-static int ath9k_enable_diversity;
+-module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444);
+-MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565");
++static int ath9k_bt_ant_diversity;
++module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444);
++MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity");
+ 
+ bool is_ath9k_unloaded;
+ /* We use the hw_value as an index into our private channel structure */
+@@ -516,6 +516,7 @@ static void ath9k_init_misc(struct ath_s
+ static void ath9k_init_platform(struct ath_softc *sc)
+ {
+ 	struct ath_hw *ah = sc->sc_ah;
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 
+ 	if (common->bus_ops->ath_bus_type != ATH_PCI)
+@@ -525,12 +526,27 @@ static void ath9k_init_platform(struct a
+ 			       ATH9K_PCI_CUS230)) {
+ 		ah->config.xlna_gpio = 9;
+ 		ah->config.xatten_margin_cfg = true;
++		ah->config.alt_mingainidx = true;
++		ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88;
++		sc->ant_comb.low_rssi_thresh = 20;
++		sc->ant_comb.fast_div_bias = 3;
+ 
+ 		ath_info(common, "Set parameters for %s\n",
+ 			 (sc->driver_data & ATH9K_PCI_CUS198) ?
+ 			 "CUS198" : "CUS230");
+-	} else if (sc->driver_data & ATH9K_PCI_CUS217) {
++	}
++
++	if (sc->driver_data & ATH9K_PCI_CUS217)
+ 		ath_info(common, "CUS217 card detected\n");
++
++	if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) {
++		pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV;
++		ath_info(common, "Set BT/WLAN RX diversity capability\n");
++	}
++
++	if (sc->driver_data & ATH9K_PCI_D3_L1_WAR) {
++		ah->config.pcie_waen = 0x0040473b;
++		ath_info(common, "Enable WAR for ASPM D3/L1\n");
+ 	}
+ }
+ 
+@@ -584,6 +600,7 @@ static int ath9k_init_softc(u16 devid, s
+ {
+ 	struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ 	struct ath_hw *ah = NULL;
++	struct ath9k_hw_capabilities *pCap;
+ 	struct ath_common *common;
+ 	int ret = 0, i;
+ 	int csz = 0;
+@@ -600,6 +617,7 @@ static int ath9k_init_softc(u16 devid, s
+ 	ah->reg_ops.rmw = ath9k_reg_rmw;
+ 	atomic_set(&ah->intr_ref_cnt, -1);
+ 	sc->sc_ah = ah;
++	pCap = &ah->caps;
+ 
+ 	sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET);
+ 
+@@ -631,11 +649,15 @@ static int ath9k_init_softc(u16 devid, s
+ 	ath9k_init_platform(sc);
+ 
+ 	/*
+-	 * Enable Antenna diversity only when BTCOEX is disabled
+-	 * and the user manually requests the feature.
++	 * Enable WLAN/BT RX Antenna diversity only when:
++	 *
++	 * - BTCOEX is disabled.
++	 * - the user manually requests the feature.
++	 * - the HW cap is set using the platform data.
+ 	 */
+-	if (!common->btcoex_enabled && ath9k_enable_diversity)
+-		common->antenna_diversity = 1;
++	if (!common->btcoex_enabled && ath9k_bt_ant_diversity &&
++	    (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
++		common->bt_ant_diversity = 1;
+ 
+ 	spin_lock_init(&common->cc_lock);
+ 
+@@ -710,13 +732,15 @@ static void ath9k_init_band_txpower(stru
+ 	struct ieee80211_supported_band *sband;
+ 	struct ieee80211_channel *chan;
+ 	struct ath_hw *ah = sc->sc_ah;
++	struct cfg80211_chan_def chandef;
+ 	int i;
+ 
+ 	sband = &sc->sbands[band];
+ 	for (i = 0; i < sband->n_channels; i++) {
+ 		chan = &sband->channels[i];
+ 		ah->curchan = &ah->channels[chan->hw_value];
+-		ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20);
++		cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
++		ath9k_cmn_update_ichannel(ah->curchan, &chandef);
+ 		ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
+ 	}
+ }
+@@ -802,7 +826,8 @@ void ath9k_set_hw_capab(struct ath_softc
  		IEEE80211_HW_PS_NULLFUNC_STACK |
  		IEEE80211_HW_SPECTRUM_MGMT |
  		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
@@ -2852,11 +4730,3023 @@
  	 * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -1499,6 +1499,7 @@ enum ieee80211_hw_flags {
- 	IEEE80211_HW_SUPPORTS_RC_TABLE			= 1<<24,
- 	IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF		= 1<<25,
+@@ -152,11 +152,14 @@ struct ieee80211_low_level_stats {
+  * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed
+  * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed
+  * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
++ * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
++ *	this is used only with channel switching with CSA
+  */
+ enum ieee80211_chanctx_change {
+ 	IEEE80211_CHANCTX_CHANGE_WIDTH		= BIT(0),
+ 	IEEE80211_CHANCTX_CHANGE_RX_CHAINS	= BIT(1),
+ 	IEEE80211_CHANCTX_CHANGE_RADAR		= BIT(2),
++	IEEE80211_CHANCTX_CHANGE_CHANNEL	= BIT(3),
+ };
+ 
+ /**
+@@ -1080,6 +1083,7 @@ enum ieee80211_vif_flags {
+  * @addr: address of this interface
+  * @p2p: indicates whether this AP or STA interface is a p2p
+  *	interface, i.e. a GO or p2p-sta respectively
++ * @csa_active: marks whether a channel switch is going on
+  * @driver_flags: flags/capabilities the driver has for this interface,
+  *	these need to be set (or cleared) when the interface is added
+  *	or, if supported by the driver, the interface type is changed
+@@ -1102,6 +1106,7 @@ struct ieee80211_vif {
+ 	struct ieee80211_bss_conf bss_conf;
+ 	u8 addr[ETH_ALEN];
+ 	bool p2p;
++	bool csa_active;
+ 
+ 	u8 cab_queue;
+ 	u8 hw_queue[IEEE80211_NUM_ACS];
+@@ -1499,6 +1504,7 @@ enum ieee80211_hw_flags {
+ 	IEEE80211_HW_SUPPORTS_RC_TABLE			= 1<<24,
+ 	IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF		= 1<<25,
  	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 +	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
  };
  
  /**
+@@ -2633,6 +2639,16 @@ enum ieee80211_roc_type {
+  * @ipv6_addr_change: IPv6 address assignment on the given interface changed.
+  *	Currently, this is only called for managed or P2P client interfaces.
+  *	This callback is optional; it must not sleep.
++ *
++ * @channel_switch_beacon: Starts a channel switch to a new channel.
++ *	Beacons are modified to include CSA or ECSA IEs before calling this
++ *	function. The corresponding count fields in these IEs must be
++ *	decremented, and when they reach zero the driver must call
++ *	ieee80211_csa_finish(). Drivers which use ieee80211_beacon_get()
++ *	get the csa counter decremented by mac80211, but must check if it is
++ *	zero using ieee80211_csa_is_complete() after the beacon has been
++ *	transmitted and then call ieee80211_csa_finish().
++ *
+  */
+ struct ieee80211_ops {
+ 	void (*tx)(struct ieee80211_hw *hw,
+@@ -2830,6 +2846,9 @@ struct ieee80211_ops {
+ 				 struct ieee80211_vif *vif,
+ 				 struct inet6_dev *idev);
+ #endif
++	void (*channel_switch_beacon)(struct ieee80211_hw *hw,
++				      struct ieee80211_vif *vif,
++				      struct cfg80211_chan_def *chandef);
+ };
+ 
+ /**
+@@ -3325,6 +3344,25 @@ static inline struct sk_buff *ieee80211_
+ }
+ 
+ /**
++ * ieee80211_csa_finish - notify mac80211 about channel switch
++ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
++ *
++ * After a channel switch announcement was scheduled and the counter in this
++ * announcement hit zero, this function must be called by the driver to
++ * notify mac80211 that the channel can be changed.
++ */
++void ieee80211_csa_finish(struct ieee80211_vif *vif);
++
++/**
++ * ieee80211_csa_is_complete - find out if counters reached zero
++ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
++ *
++ * This function returns whether the channel switch counters reached zero.
++ */
++bool ieee80211_csa_is_complete(struct ieee80211_vif *vif);
++
++
++/**
+  * ieee80211_proberesp_get - retrieve a Probe Response template
+  * @hw: pointer obtained from ieee80211_alloc_hw().
+  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -854,8 +854,8 @@ static int ieee80211_set_probe_resp(stru
+ 	return 0;
+ }
+ 
+-static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+-				   struct cfg80211_beacon_data *params)
++int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
++			    struct cfg80211_beacon_data *params)
+ {
+ 	struct beacon_data *new, *old;
+ 	int new_head_len, new_tail_len;
+@@ -1018,6 +1018,12 @@ static int ieee80211_change_beacon(struc
+ 
+ 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ 
++	/* don't allow changing the beacon while CSA is in place - offset
++	 * of channel switch counter may change
++	 */
++	if (sdata->vif.csa_active)
++		return -EBUSY;
++
+ 	old = rtnl_dereference(sdata->u.ap.beacon);
+ 	if (!old)
+ 		return -ENOENT;
+@@ -1042,6 +1048,10 @@ static int ieee80211_stop_ap(struct wiph
+ 		return -ENOENT;
+ 	old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
+ 
++	/* abort any running channel switch */
++	sdata->vif.csa_active = false;
++	cancel_work_sync(&sdata->csa_finalize_work);
++
+ 	/* turn off carrier for this interface and dependent VLANs */
+ 	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ 		netif_carrier_off(vlan->dev);
+@@ -2784,6 +2794,178 @@ static int ieee80211_start_radar_detecti
+ 	return 0;
+ }
+ 
++static struct cfg80211_beacon_data *
++cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
++{
++	struct cfg80211_beacon_data *new_beacon;
++	u8 *pos;
++	int len;
++
++	len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
++	      beacon->proberesp_ies_len + beacon->assocresp_ies_len +
++	      beacon->probe_resp_len;
++
++	new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
++	if (!new_beacon)
++		return NULL;
++
++	pos = (u8 *)(new_beacon + 1);
++	if (beacon->head_len) {
++		new_beacon->head_len = beacon->head_len;
++		new_beacon->head = pos;
++		memcpy(pos, beacon->head, beacon->head_len);
++		pos += beacon->head_len;
++	}
++	if (beacon->tail_len) {
++		new_beacon->tail_len = beacon->tail_len;
++		new_beacon->tail = pos;
++		memcpy(pos, beacon->tail, beacon->tail_len);
++		pos += beacon->tail_len;
++	}
++	if (beacon->beacon_ies_len) {
++		new_beacon->beacon_ies_len = beacon->beacon_ies_len;
++		new_beacon->beacon_ies = pos;
++		memcpy(pos, beacon->beacon_ies, beacon->beacon_ies_len);
++		pos += beacon->beacon_ies_len;
++	}
++	if (beacon->proberesp_ies_len) {
++		new_beacon->proberesp_ies_len = beacon->proberesp_ies_len;
++		new_beacon->proberesp_ies = pos;
++		memcpy(pos, beacon->proberesp_ies, beacon->proberesp_ies_len);
++		pos += beacon->proberesp_ies_len;
++	}
++	if (beacon->assocresp_ies_len) {
++		new_beacon->assocresp_ies_len = beacon->assocresp_ies_len;
++		new_beacon->assocresp_ies = pos;
++		memcpy(pos, beacon->assocresp_ies, beacon->assocresp_ies_len);
++		pos += beacon->assocresp_ies_len;
++	}
++	if (beacon->probe_resp_len) {
++		new_beacon->probe_resp_len = beacon->probe_resp_len;
++		beacon->probe_resp = pos;
++		memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
++		pos += beacon->probe_resp_len;
++	}
++
++	return new_beacon;
++}
++
++void ieee80211_csa_finalize_work(struct work_struct *work)
++{
++	struct ieee80211_sub_if_data *sdata =
++		container_of(work, struct ieee80211_sub_if_data,
++			     csa_finalize_work);
++	struct ieee80211_local *local = sdata->local;
++	int err, changed;
++
++	if (!ieee80211_sdata_running(sdata))
++		return;
++
++	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
++		return;
++
++	sdata->radar_required = sdata->csa_radar_required;
++	err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
++					   &changed);
++	if (WARN_ON(err < 0))
++		return;
++
++	err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
++	if (err < 0)
++		return;
++
++	changed |= err;
++	kfree(sdata->u.ap.next_beacon);
++	sdata->u.ap.next_beacon = NULL;
++	sdata->vif.csa_active = false;
++
++	ieee80211_wake_queues_by_reason(&sdata->local->hw,
++					IEEE80211_MAX_QUEUE_MAP,
++					IEEE80211_QUEUE_STOP_REASON_CSA);
++
++	ieee80211_bss_info_change_notify(sdata, changed);
++
++	cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
++}
++
++static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
++				    struct cfg80211_csa_settings *params)
++{
++	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++	struct ieee80211_local *local = sdata->local;
++	struct ieee80211_chanctx_conf *chanctx_conf;
++	struct ieee80211_chanctx *chanctx;
++	int err, num_chanctx;
++
++	if (!list_empty(&local->roc_list) || local->scanning)
++		return -EBUSY;
++
++	if (sdata->wdev.cac_started)
++		return -EBUSY;
++
++	if (cfg80211_chandef_identical(&params->chandef,
++				       &sdata->vif.bss_conf.chandef))
++		return -EINVAL;
++
++	rcu_read_lock();
++	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
++	if (!chanctx_conf) {
++		rcu_read_unlock();
++		return -EBUSY;
++	}
++
++	/* don't handle for multi-VIF cases */
++	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
++	if (chanctx->refcount > 1) {
++		rcu_read_unlock();
++		return -EBUSY;
++	}
++	num_chanctx = 0;
++	list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
++		num_chanctx++;
++	rcu_read_unlock();
++
++	if (num_chanctx > 1)
++		return -EBUSY;
++
++	/* don't allow another channel switch if one is already active. */
++	if (sdata->vif.csa_active)
++		return -EBUSY;
++
++	/* only handle AP for now. */
++	switch (sdata->vif.type) {
++	case NL80211_IFTYPE_AP:
++		break;
++	default:
++		return -EOPNOTSUPP;
++	}
++
++	sdata->u.ap.next_beacon = cfg80211_beacon_dup(&params->beacon_after);
++	if (!sdata->u.ap.next_beacon)
++		return -ENOMEM;
++
++	sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
++	sdata->csa_counter_offset_presp = params->counter_offset_presp;
++	sdata->csa_radar_required = params->radar_required;
++
++	if (params->block_tx)
++		ieee80211_stop_queues_by_reason(&local->hw,
++				IEEE80211_MAX_QUEUE_MAP,
++				IEEE80211_QUEUE_STOP_REASON_CSA);
++
++	err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
++	if (err < 0)
++		return err;
++
++	local->csa_chandef = params->chandef;
++	sdata->vif.csa_active = true;
++
++	ieee80211_bss_info_change_notify(sdata, err);
++	drv_channel_switch_beacon(sdata, &params->chandef);
++
++	return 0;
++}
++
+ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+ 			     struct ieee80211_channel *chan, bool offchan,
+ 			     unsigned int wait, const u8 *buf, size_t len,
+@@ -3501,4 +3683,5 @@ struct cfg80211_ops mac80211_config_ops 
+ 	.get_et_strings = ieee80211_get_et_strings,
+ 	.get_channel = ieee80211_cfg_get_channel,
+ 	.start_radar_detection = ieee80211_start_radar_detection,
++	.channel_switch = ieee80211_channel_switch,
+ };
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -410,6 +410,64 @@ int ieee80211_vif_use_channel(struct iee
+ 	return ret;
+ }
+ 
++int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
++				 const struct cfg80211_chan_def *chandef,
++				 u32 *changed)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct ieee80211_chanctx_conf *conf;
++	struct ieee80211_chanctx *ctx;
++	int ret;
++	u32 chanctx_changed = 0;
++
++	/* should never be called if not performing a channel switch. */
++	if (WARN_ON(!sdata->vif.csa_active))
++		return -EINVAL;
++
++	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
++				     IEEE80211_CHAN_DISABLED))
++		return -EINVAL;
++
++	mutex_lock(&local->chanctx_mtx);
++	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
++					 lockdep_is_held(&local->chanctx_mtx));
++	if (!conf) {
++		ret = -EINVAL;
++		goto out;
++	}
++
++	ctx = container_of(conf, struct ieee80211_chanctx, conf);
++	if (ctx->refcount != 1) {
++		ret = -EINVAL;
++		goto out;
++	}
++
++	if (sdata->vif.bss_conf.chandef.width != chandef->width) {
++		chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
++		*changed |= BSS_CHANGED_BANDWIDTH;
++	}
++
++	sdata->vif.bss_conf.chandef = *chandef;
++	ctx->conf.def = *chandef;
++
++	chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
++	drv_change_chanctx(local, ctx, chanctx_changed);
++
++	if (!local->use_chanctx) {
++		local->_oper_chandef = *chandef;
++		ieee80211_hw_config(local, 0);
++	}
++
++	ieee80211_recalc_chanctx_chantype(local, ctx);
++	ieee80211_recalc_smps_chanctx(local, ctx);
++	ieee80211_recalc_radar_chanctx(local, ctx);
++
++	ret = 0;
++ out:
++	mutex_unlock(&local->chanctx_mtx);
++	return ret;
++}
++
+ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
+ 				   const struct cfg80211_chan_def *chandef,
+ 				   u32 *changed)
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -1104,4 +1104,17 @@ static inline void drv_ipv6_addr_change(
+ }
+ #endif
+ 
++static inline void
++drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
++			  struct cfg80211_chan_def *chandef)
++{
++	struct ieee80211_local *local = sdata->local;
++
++	if (local->ops->channel_switch_beacon) {
++		trace_drv_channel_switch_beacon(local, sdata, chandef);
++		local->ops->channel_switch_beacon(&local->hw, &sdata->vif,
++						  chandef);
++	}
++}
++
+ #endif /* __MAC80211_DRIVER_OPS */
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -53,9 +53,6 @@ struct ieee80211_local;
+  * increased memory use (about 2 kB of RAM per entry). */
+ #define IEEE80211_FRAGMENT_MAX 4
+ 
+-#define TU_TO_JIFFIES(x)	(usecs_to_jiffies((x) * 1024))
+-#define TU_TO_EXP_TIME(x)	(jiffies + TU_TO_JIFFIES(x))
+-
+ /* power level hasn't been configured (or set to automatic) */
+ #define IEEE80211_UNSET_POWER_LEVEL	INT_MIN
+ 
+@@ -259,6 +256,8 @@ struct ieee80211_if_ap {
+ 	struct beacon_data __rcu *beacon;
+ 	struct probe_resp __rcu *probe_resp;
+ 
++	/* to be used after channel switch. */
++	struct cfg80211_beacon_data *next_beacon;
+ 	struct list_head vlans;
+ 
+ 	struct ps_data ps;
+@@ -713,6 +712,11 @@ struct ieee80211_sub_if_data {
+ 
+ 	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
+ 
++	struct work_struct csa_finalize_work;
++	int csa_counter_offset_beacon;
++	int csa_counter_offset_presp;
++	bool csa_radar_required;
++
+ 	/* used to reconfigure hardware SM PS */
+ 	struct work_struct recalc_smps;
+ 
+@@ -1346,6 +1350,9 @@ void ieee80211_roc_notify_destroy(struct
+ void ieee80211_sw_roc_work(struct work_struct *work);
+ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
+ 
++/* channel switch handling */
++void ieee80211_csa_finalize_work(struct work_struct *work);
++
+ /* interface handling */
+ int ieee80211_iface_init(void);
+ void ieee80211_iface_exit(void);
+@@ -1367,6 +1374,8 @@ void ieee80211_del_virtual_monitor(struc
+ 
+ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
+ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
++int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
++			    struct cfg80211_beacon_data *params);
+ 
+ static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
+ {
+@@ -1627,6 +1636,11 @@ int __must_check
+ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
+ 			       const struct cfg80211_chan_def *chandef,
+ 			       u32 *changed);
++/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
++int __must_check
++ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
++			     const struct cfg80211_chan_def *chandef,
++			     u32 *changed);
+ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
+ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
+--- a/net/mac80211/trace.h
++++ b/net/mac80211/trace.h
+@@ -1906,6 +1906,32 @@ TRACE_EVENT(api_radar_detected,
+ 	)
+ );
+ 
++TRACE_EVENT(drv_channel_switch_beacon,
++	TP_PROTO(struct ieee80211_local *local,
++		 struct ieee80211_sub_if_data *sdata,
++		 struct cfg80211_chan_def *chandef),
++
++	TP_ARGS(local, sdata, chandef),
++
++	TP_STRUCT__entry(
++		LOCAL_ENTRY
++		VIF_ENTRY
++		CHANDEF_ENTRY
++	),
++
++	TP_fast_assign(
++		LOCAL_ASSIGN;
++		VIF_ASSIGN;
++		CHANDEF_ASSIGN(chandef);
++	),
++
++	TP_printk(
++		LOCAL_PR_FMT VIF_PR_FMT " channel switch to " CHANDEF_PR_FMT,
++		LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG
++	)
++);
++
++
+ #ifdef CPTCFG_MAC80211_MESSAGE_TRACING
+ #undef TRACE_SYSTEM
+ #define TRACE_SYSTEM mac80211_msg
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -2326,6 +2326,81 @@ static int ieee80211_beacon_add_tim(stru
+ 	return 0;
+ }
+ 
++void ieee80211_csa_finish(struct ieee80211_vif *vif)
++{
++	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
++
++	ieee80211_queue_work(&sdata->local->hw,
++			     &sdata->csa_finalize_work);
++}
++EXPORT_SYMBOL(ieee80211_csa_finish);
++
++static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
++				 struct beacon_data *beacon)
++{
++	struct probe_resp *resp;
++	int counter_offset_beacon = sdata->csa_counter_offset_beacon;
++	int counter_offset_presp = sdata->csa_counter_offset_presp;
++
++	/* warn if the driver did not check for/react to csa completeness */
++	if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
++		return;
++
++	((u8 *)beacon->tail)[counter_offset_beacon]--;
++
++	if (sdata->vif.type == NL80211_IFTYPE_AP &&
++	    counter_offset_presp) {
++		rcu_read_lock();
++		resp = rcu_dereference(sdata->u.ap.probe_resp);
++
++		/* if nl80211 accepted the offset, this should not happen. */
++		if (WARN_ON(!resp)) {
++			rcu_read_unlock();
++			return;
++		}
++		resp->data[counter_offset_presp]--;
++		rcu_read_unlock();
++	}
++}
++
++bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
++{
++	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
++	struct beacon_data *beacon = NULL;
++	u8 *beacon_data;
++	size_t beacon_data_len;
++	int counter_beacon = sdata->csa_counter_offset_beacon;
++	int ret = false;
++
++	if (!ieee80211_sdata_running(sdata))
++		return false;
++
++	rcu_read_lock();
++	if (vif->type == NL80211_IFTYPE_AP) {
++		struct ieee80211_if_ap *ap = &sdata->u.ap;
++
++		beacon = rcu_dereference(ap->beacon);
++		if (WARN_ON(!beacon || !beacon->tail))
++			goto out;
++		beacon_data = beacon->tail;
++		beacon_data_len = beacon->tail_len;
++	} else {
++		WARN_ON(1);
++		goto out;
++	}
++
++	if (WARN_ON(counter_beacon > beacon_data_len))
++		goto out;
++
++	if (beacon_data[counter_beacon] == 0)
++		ret = true;
++ out:
++	rcu_read_unlock();
++
++	return ret;
++}
++EXPORT_SYMBOL(ieee80211_csa_is_complete);
++
+ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
+ 					 struct ieee80211_vif *vif,
+ 					 u16 *tim_offset, u16 *tim_length)
+@@ -2356,6 +2431,9 @@ struct sk_buff *ieee80211_beacon_get_tim
+ 		struct beacon_data *beacon = rcu_dereference(ap->beacon);
+ 
+ 		if (beacon) {
++			if (sdata->vif.csa_active)
++				ieee80211_update_csa(sdata, beacon);
++
+ 			/*
+ 			 * headroom, head length,
+ 			 * tail length and maximum TIM length
+--- a/net/wireless/rdev-ops.h
++++ b/net/wireless/rdev-ops.h
+@@ -923,4 +923,16 @@ static inline void rdev_crit_proto_stop(
+ 	trace_rdev_return_void(&rdev->wiphy);
+ }
+ 
++static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev,
++				      struct net_device *dev,
++				      struct cfg80211_csa_settings *params)
++{
++	int ret;
++
++	trace_rdev_channel_switch(&rdev->wiphy, dev, params);
++	ret = rdev->ops->channel_switch(&rdev->wiphy, dev, params);
++	trace_rdev_return_int(&rdev->wiphy, ret);
++	return ret;
++}
++
+ #endif /* __CFG80211_RDEV_OPS */
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -1841,6 +1841,39 @@ TRACE_EVENT(rdev_crit_proto_stop,
+ 		  WIPHY_PR_ARG, WDEV_PR_ARG)
+ );
+ 
++TRACE_EVENT(rdev_channel_switch,
++	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
++		 struct cfg80211_csa_settings *params),
++	TP_ARGS(wiphy, netdev, params),
++	TP_STRUCT__entry(
++		WIPHY_ENTRY
++		NETDEV_ENTRY
++		CHAN_DEF_ENTRY
++		__field(u16, counter_offset_beacon)
++		__field(u16, counter_offset_presp)
++		__field(bool, radar_required)
++		__field(bool, block_tx)
++		__field(u8, count)
++	),
++	TP_fast_assign(
++		WIPHY_ASSIGN;
++		NETDEV_ASSIGN;
++		CHAN_DEF_ASSIGN(&params->chandef);
++		__entry->counter_offset_beacon = params->counter_offset_beacon;
++		__entry->counter_offset_presp = params->counter_offset_presp;
++		__entry->radar_required = params->radar_required;
++		__entry->block_tx = params->block_tx;
++		__entry->count = params->count;
++	),
++	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT
++		  ", block_tx: %d, count: %u, radar_required: %d"
++		  ", counter offsets (beacon/presp): %u/%u",
++		  WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
++		  __entry->block_tx, __entry->count, __entry->radar_required,
++		  __entry->counter_offset_beacon,
++		  __entry->counter_offset_presp)
++);
++
+ /*************************************************************
+  *	     cfg80211 exported functions traces		     *
+  *************************************************************/
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -159,7 +159,7 @@ struct ath_common {
+ 
+ 	bool btcoex_enabled;
+ 	bool disable_ani;
+-	bool antenna_diversity;
++	bool bt_ant_diversity;
+ };
+ 
+ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
+--- a/drivers/net/wireless/ath/ath9k/antenna.c
++++ b/drivers/net/wireless/ath/ath9k/antenna.c
+@@ -16,37 +16,119 @@
+ 
+ #include "ath9k.h"
+ 
+-static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
++/*
++ * AR9285
++ * ======
++ *
++ * EEPROM has 2 4-bit fields containing the card configuration.
++ *
++ * antdiv_ctl1:
++ * ------------
++ * bb_enable_ant_div_lnadiv : 1
++ * bb_ant_div_alt_gaintb    : 1
++ * bb_ant_div_main_gaintb   : 1
++ * bb_enable_ant_fast_div   : 1
++ *
++ * antdiv_ctl2:
++ * -----------
++ * bb_ant_div_alt_lnaconf  : 2
++ * bb_ant_div_main_lnaconf : 2
++ *
++ * The EEPROM bits are used as follows:
++ * ------------------------------------
++ *
++ * bb_enable_ant_div_lnadiv      - Enable LNA path rx antenna diversity/combining.
++ *                                 Set in AR_PHY_MULTICHAIN_GAIN_CTL.
++ *
++ * bb_ant_div_[alt/main]_gaintb  - 0 -> Antenna config Alt/Main uses gaintable 0
++ *                                 1 -> Antenna config Alt/Main uses gaintable 1
++ *                                 Set in AR_PHY_MULTICHAIN_GAIN_CTL.
++ *
++ * bb_enable_ant_fast_div        - Enable fast antenna diversity.
++ *                                 Set in AR_PHY_CCK_DETECT.
++ *
++ * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
++ *                                 Set in AR_PHY_MULTICHAIN_GAIN_CTL.
++ *                                 10=LNA1
++ *                                 01=LNA2
++ *                                 11=LNA1+LNA2
++ *                                 00=LNA1-LNA2
++ *
++ * AR9485 / AR9565 / AR9331
++ * ========================
++ *
++ * The same bits are present in the EEPROM, but the location in the
++ * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).
++ *
++ * ant_div_alt_lnaconf      ==> bit 0~1
++ * ant_div_main_lnaconf     ==> bit 2~3
++ * ant_div_alt_gaintb       ==> bit 4
++ * ant_div_main_gaintb      ==> bit 5
++ * enable_ant_div_lnadiv    ==> bit 6
++ * enable_ant_fast_div      ==> bit 7
++ */
++
++static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb,
++					       int alt_ratio, int maxdelta,
+ 					       int mindelta, int main_rssi_avg,
+ 					       int alt_rssi_avg, int pkt_count)
+ {
+-	return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+-		 (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
+-		(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
++	if (pkt_count <= 50)
++		return false;
++
++	if (alt_rssi_avg > main_rssi_avg + mindelta)
++		return true;
++
++	if (alt_ratio >= antcomb->ant_ratio2 &&
++	    alt_rssi_avg >= antcomb->low_rssi_thresh &&
++	    (alt_rssi_avg > main_rssi_avg + maxdelta))
++		return true;
++
++	return false;
+ }
+ 
+-static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
+-					      int curr_main_set, int curr_alt_set,
+-					      int alt_rssi_avg, int main_rssi_avg)
++static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
++					      struct ath_ant_comb *antcomb,
++					      int alt_ratio, int alt_rssi_avg,
++					      int main_rssi_avg)
+ {
+-	bool result = false;
+-	switch (div_group) {
++	bool result, set1, set2;
++
++	result = set1 = set2 = false;
++
++	if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
++	    conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
++		set1 = true;
++
++	if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
++	    conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
++		set2 = true;
++
++	switch (conf->div_group) {
+ 	case 0:
+ 		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ 			result = true;
+ 		break;
+ 	case 1:
+ 	case 2:
+-		if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
+-		      (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
+-		      (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+-		     ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
+-		      (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
+-		      (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
+-		    (alt_rssi_avg >= 4))
++		if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
++			break;
++
++		if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
++		    (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) ||
++		    (alt_ratio > antcomb->ant_ratio))
+ 			result = true;
+-		else
+-			result = false;
++
++		break;
++	case 3:
++		if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
++			break;
++
++		if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
++		    (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) ||
++		    (alt_ratio > antcomb->ant_ratio))
++			result = true;
++
+ 		break;
+ 	}
+ 
+@@ -108,6 +190,74 @@ static void ath_lnaconf_alt_good_scan(st
+ 	}
+ }
+ 
++static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
++				  struct ath_hw_antcomb_conf *conf)
++{
++	/* set alt to the conf with maximun ratio */
++	if (antcomb->first_ratio && antcomb->second_ratio) {
++		if (antcomb->rssi_second > antcomb->rssi_third) {
++			/* first alt*/
++			if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
++			    (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
++				/* Set alt LNA1 or LNA2*/
++				if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
++					conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++				else
++					conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++			else
++				/* Set alt to A+B or A-B */
++				conf->alt_lna_conf =
++					antcomb->first_quick_scan_conf;
++		} else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
++			   (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
++			/* Set alt LNA1 or LNA2 */
++			if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++			else
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++		} else {
++			/* Set alt to A+B or A-B */
++			conf->alt_lna_conf = antcomb->second_quick_scan_conf;
++		}
++	} else if (antcomb->first_ratio) {
++		/* first alt */
++		if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
++		    (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
++			/* Set alt LNA1 or LNA2 */
++			if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++			else
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++		else
++			/* Set alt to A+B or A-B */
++			conf->alt_lna_conf = antcomb->first_quick_scan_conf;
++	} else if (antcomb->second_ratio) {
++		/* second alt */
++		if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
++		    (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
++			/* Set alt LNA1 or LNA2 */
++			if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++			else
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++		else
++			/* Set alt to A+B or A-B */
++			conf->alt_lna_conf = antcomb->second_quick_scan_conf;
++	} else {
++		/* main is largest */
++		if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
++		    (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
++			/* Set alt LNA1 or LNA2 */
++			if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++			else
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++		else
++			/* Set alt to A+B or A-B */
++			conf->alt_lna_conf = antcomb->main_conf;
++	}
++}
++
+ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
+ 				       struct ath_hw_antcomb_conf *div_ant_conf,
+ 				       int main_rssi_avg, int alt_rssi_avg,
+@@ -129,7 +279,7 @@ static void ath_select_ant_div_from_quic
+ 
+ 		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+ 			/* main is LNA1 */
+-			if (ath_is_alt_ant_ratio_better(alt_ratio,
++			if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ 						main_rssi_avg, alt_rssi_avg,
+@@ -138,7 +288,7 @@ static void ath_select_ant_div_from_quic
+ 			else
+ 				antcomb->first_ratio = false;
+ 		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+-			if (ath_is_alt_ant_ratio_better(alt_ratio,
++			if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ 						main_rssi_avg, alt_rssi_avg,
+@@ -147,11 +297,11 @@ static void ath_select_ant_div_from_quic
+ 			else
+ 				antcomb->first_ratio = false;
+ 		} else {
+-			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+-			      (alt_rssi_avg > main_rssi_avg +
+-			       ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+-			     (alt_rssi_avg > main_rssi_avg)) &&
+-			    (antcomb->total_pkt_count > 50))
++			if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
++						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
++						0,
++						main_rssi_avg, alt_rssi_avg,
++						antcomb->total_pkt_count))
+ 				antcomb->first_ratio = true;
+ 			else
+ 				antcomb->first_ratio = false;
+@@ -164,17 +314,21 @@ static void ath_select_ant_div_from_quic
+ 		antcomb->rssi_first = main_rssi_avg;
+ 		antcomb->rssi_third = alt_rssi_avg;
+ 
+-		if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
++		switch(antcomb->second_quick_scan_conf) {
++		case ATH_ANT_DIV_COMB_LNA1:
+ 			antcomb->rssi_lna1 = alt_rssi_avg;
+-		else if (antcomb->second_quick_scan_conf ==
+-			 ATH_ANT_DIV_COMB_LNA2)
++			break;
++		case ATH_ANT_DIV_COMB_LNA2:
+ 			antcomb->rssi_lna2 = alt_rssi_avg;
+-		else if (antcomb->second_quick_scan_conf ==
+-			 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
++			break;
++		case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+ 			if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
+ 				antcomb->rssi_lna2 = main_rssi_avg;
+ 			else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
+ 				antcomb->rssi_lna1 = main_rssi_avg;
++			break;
++		default:
++			break;
+ 		}
+ 
+ 		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+@@ -184,7 +338,7 @@ static void ath_select_ant_div_from_quic
+ 			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+ 
+ 		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+-			if (ath_is_alt_ant_ratio_better(alt_ratio,
++			if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ 						main_rssi_avg, alt_rssi_avg,
+@@ -193,7 +347,7 @@ static void ath_select_ant_div_from_quic
+ 			else
+ 				antcomb->second_ratio = false;
+ 		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+-			if (ath_is_alt_ant_ratio_better(alt_ratio,
++			if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ 						ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ 						main_rssi_avg, alt_rssi_avg,
+@@ -202,105 +356,18 @@ static void ath_select_ant_div_from_quic
+ 			else
+ 				antcomb->second_ratio = false;
+ 		} else {
+-			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+-			      (alt_rssi_avg > main_rssi_avg +
+-			       ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+-			     (alt_rssi_avg > main_rssi_avg)) &&
+-			    (antcomb->total_pkt_count > 50))
++			if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
++						ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
++						0,
++						main_rssi_avg, alt_rssi_avg,
++						antcomb->total_pkt_count))
+ 				antcomb->second_ratio = true;
+ 			else
+ 				antcomb->second_ratio = false;
+ 		}
+ 
+-		/* set alt to the conf with maximun ratio */
+-		if (antcomb->first_ratio && antcomb->second_ratio) {
+-			if (antcomb->rssi_second > antcomb->rssi_third) {
+-				/* first alt*/
+-				if ((antcomb->first_quick_scan_conf ==
+-				    ATH_ANT_DIV_COMB_LNA1) ||
+-				    (antcomb->first_quick_scan_conf ==
+-				    ATH_ANT_DIV_COMB_LNA2))
+-					/* Set alt LNA1 or LNA2*/
+-					if (div_ant_conf->main_lna_conf ==
+-					    ATH_ANT_DIV_COMB_LNA2)
+-						div_ant_conf->alt_lna_conf =
+-							ATH_ANT_DIV_COMB_LNA1;
+-					else
+-						div_ant_conf->alt_lna_conf =
+-							ATH_ANT_DIV_COMB_LNA2;
+-				else
+-					/* Set alt to A+B or A-B */
+-					div_ant_conf->alt_lna_conf =
+-						antcomb->first_quick_scan_conf;
+-			} else if ((antcomb->second_quick_scan_conf ==
+-				   ATH_ANT_DIV_COMB_LNA1) ||
+-				   (antcomb->second_quick_scan_conf ==
+-				   ATH_ANT_DIV_COMB_LNA2)) {
+-				/* Set alt LNA1 or LNA2 */
+-				if (div_ant_conf->main_lna_conf ==
+-				    ATH_ANT_DIV_COMB_LNA2)
+-					div_ant_conf->alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-				else
+-					div_ant_conf->alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-			} else {
+-				/* Set alt to A+B or A-B */
+-				div_ant_conf->alt_lna_conf =
+-					antcomb->second_quick_scan_conf;
+-			}
+-		} else if (antcomb->first_ratio) {
+-			/* first alt */
+-			if ((antcomb->first_quick_scan_conf ==
+-			    ATH_ANT_DIV_COMB_LNA1) ||
+-			    (antcomb->first_quick_scan_conf ==
+-			    ATH_ANT_DIV_COMB_LNA2))
+-					/* Set alt LNA1 or LNA2 */
+-				if (div_ant_conf->main_lna_conf ==
+-				    ATH_ANT_DIV_COMB_LNA2)
+-					div_ant_conf->alt_lna_conf =
+-							ATH_ANT_DIV_COMB_LNA1;
+-				else
+-					div_ant_conf->alt_lna_conf =
+-							ATH_ANT_DIV_COMB_LNA2;
+-			else
+-				/* Set alt to A+B or A-B */
+-				div_ant_conf->alt_lna_conf =
+-						antcomb->first_quick_scan_conf;
+-		} else if (antcomb->second_ratio) {
+-				/* second alt */
+-			if ((antcomb->second_quick_scan_conf ==
+-			    ATH_ANT_DIV_COMB_LNA1) ||
+-			    (antcomb->second_quick_scan_conf ==
+-			    ATH_ANT_DIV_COMB_LNA2))
+-				/* Set alt LNA1 or LNA2 */
+-				if (div_ant_conf->main_lna_conf ==
+-				    ATH_ANT_DIV_COMB_LNA2)
+-					div_ant_conf->alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-				else
+-					div_ant_conf->alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-			else
+-				/* Set alt to A+B or A-B */
+-				div_ant_conf->alt_lna_conf =
+-						antcomb->second_quick_scan_conf;
+-		} else {
+-			/* main is largest */
+-			if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
+-			    (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
+-				/* Set alt LNA1 or LNA2 */
+-				if (div_ant_conf->main_lna_conf ==
+-				    ATH_ANT_DIV_COMB_LNA2)
+-					div_ant_conf->alt_lna_conf =
+-							ATH_ANT_DIV_COMB_LNA1;
+-				else
+-					div_ant_conf->alt_lna_conf =
+-							ATH_ANT_DIV_COMB_LNA2;
+-			else
+-				/* Set alt to A+B or A-B */
+-				div_ant_conf->alt_lna_conf = antcomb->main_conf;
+-		}
++		ath_ant_set_alt_ratio(antcomb, div_ant_conf);
++
+ 		break;
+ 	default:
+ 		break;
+@@ -430,8 +497,7 @@ static void ath_ant_div_conf_fast_divbia
+ 			ant_conf->fast_div_bias = 0x1;
+ 			break;
+ 		case 0x10: /* LNA2 A-B */
+-			if (!(antcomb->scan) &&
+-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
++			if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
+ 				ant_conf->fast_div_bias = 0x1;
+ 			else
+ 				ant_conf->fast_div_bias = 0x2;
+@@ -440,15 +506,13 @@ static void ath_ant_div_conf_fast_divbia
+ 			ant_conf->fast_div_bias = 0x1;
+ 			break;
+ 		case 0x13: /* LNA2 A+B */
+-			if (!(antcomb->scan) &&
+-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
++			if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
+ 				ant_conf->fast_div_bias = 0x1;
+ 			else
+ 				ant_conf->fast_div_bias = 0x2;
+ 			break;
+ 		case 0x20: /* LNA1 A-B */
+-			if (!(antcomb->scan) &&
+-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
++			if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
+ 				ant_conf->fast_div_bias = 0x1;
+ 			else
+ 				ant_conf->fast_div_bias = 0x2;
+@@ -457,8 +521,7 @@ static void ath_ant_div_conf_fast_divbia
+ 			ant_conf->fast_div_bias = 0x1;
+ 			break;
+ 		case 0x23: /* LNA1 A+B */
+-			if (!(antcomb->scan) &&
+-				(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
++			if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
+ 				ant_conf->fast_div_bias = 0x1;
+ 			else
+ 				ant_conf->fast_div_bias = 0x2;
+@@ -475,6 +538,9 @@ static void ath_ant_div_conf_fast_divbia
+ 		default:
+ 			break;
+ 		}
++
++		if (antcomb->fast_div_bias)
++			ant_conf->fast_div_bias = antcomb->fast_div_bias;
+ 	} else if (ant_conf->div_group == 3) {
+ 		switch ((ant_conf->main_lna_conf << 4) |
+ 			ant_conf->alt_lna_conf) {
+@@ -540,6 +606,138 @@ static void ath_ant_div_conf_fast_divbia
+ 	}
+ }
+ 
++static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
++			     struct ath_hw_antcomb_conf *conf,
++			     int curr_alt_set, int alt_rssi_avg,
++			     int main_rssi_avg)
++{
++	switch (curr_alt_set) {
++	case ATH_ANT_DIV_COMB_LNA2:
++		antcomb->rssi_lna2 = alt_rssi_avg;
++		antcomb->rssi_lna1 = main_rssi_avg;
++		antcomb->scan = true;
++		/* set to A+B */
++		conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++		conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
++		break;
++	case ATH_ANT_DIV_COMB_LNA1:
++		antcomb->rssi_lna1 = alt_rssi_avg;
++		antcomb->rssi_lna2 = main_rssi_avg;
++		antcomb->scan = true;
++		/* set to A+B */
++		conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++		conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
++		break;
++	case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
++		antcomb->rssi_add = alt_rssi_avg;
++		antcomb->scan = true;
++		/* set to A-B */
++		conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
++		break;
++	case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
++		antcomb->rssi_sub = alt_rssi_avg;
++		antcomb->scan = false;
++		if (antcomb->rssi_lna2 >
++		    (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
++			/* use LNA2 as main LNA */
++			if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
++			    (antcomb->rssi_add > antcomb->rssi_sub)) {
++				/* set to A+B */
++				conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
++			} else if (antcomb->rssi_sub >
++				   antcomb->rssi_lna1) {
++				/* set to A-B */
++				conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
++			} else {
++				/* set to LNA1 */
++				conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++			}
++		} else {
++			/* use LNA1 as main LNA */
++			if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
++			    (antcomb->rssi_add > antcomb->rssi_sub)) {
++				/* set to A+B */
++				conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
++			} else if (antcomb->rssi_sub >
++				   antcomb->rssi_lna1) {
++				/* set to A-B */
++				conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
++			} else {
++				/* set to LNA2 */
++				conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++			}
++		}
++		break;
++	default:
++		break;
++	}
++}
++
++static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
++			       struct ath_ant_comb *antcomb,
++			       int alt_ratio, int alt_rssi_avg,
++			       int main_rssi_avg, int curr_main_set,
++			       int curr_alt_set)
++{
++	bool ret = false;
++
++	if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
++				       alt_rssi_avg, main_rssi_avg)) {
++		if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
++			/*
++			 * Switch main and alt LNA.
++			 */
++			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++			div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++		} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
++			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++			div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++		}
++
++		ret = true;
++	} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
++		   (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
++		/*
++		  Set alt to another LNA.
++		*/
++		if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
++			div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
++		else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
++			div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
++
++		ret = true;
++	}
++
++	return ret;
++}
++
++static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
++{
++	int alt_ratio;
++
++	if (!antcomb->scan || !antcomb->alt_good)
++		return false;
++
++	if (time_after(jiffies, antcomb->scan_start_time +
++		       msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
++		return true;
++
++	if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
++		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
++			     antcomb->total_pkt_count);
++		if (alt_ratio < antcomb->ant_ratio)
++			return true;
++	}
++
++	return false;
++}
++
+ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
+ {
+ 	struct ath_hw_antcomb_conf div_ant_conf;
+@@ -549,41 +747,46 @@ void ath_ant_comb_scan(struct ath_softc 
+ 	int main_rssi = rs->rs_rssi_ctl0;
+ 	int alt_rssi = rs->rs_rssi_ctl1;
+ 	int rx_ant_conf,  main_ant_conf;
+-	bool short_scan = false;
++	bool short_scan = false, ret;
+ 
+ 	rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+ 		       ATH_ANT_RX_MASK;
+ 	main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+ 			 ATH_ANT_RX_MASK;
+ 
++	if (alt_rssi >= antcomb->low_rssi_thresh) {
++		antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
++		antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
++	} else {
++		antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
++		antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
++	}
++
+ 	/* Record packet only when both main_rssi and  alt_rssi is positive */
+ 	if (main_rssi > 0 && alt_rssi > 0) {
+ 		antcomb->total_pkt_count++;
+ 		antcomb->main_total_rssi += main_rssi;
+ 		antcomb->alt_total_rssi  += alt_rssi;
++
+ 		if (main_ant_conf == rx_ant_conf)
+ 			antcomb->main_recv_cnt++;
+ 		else
+ 			antcomb->alt_recv_cnt++;
+ 	}
+ 
+-	/* Short scan check */
+-	if (antcomb->scan && antcomb->alt_good) {
+-		if (time_after(jiffies, antcomb->scan_start_time +
+-		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+-			short_scan = true;
+-		else
+-			if (antcomb->total_pkt_count ==
+-			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+-				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+-					    antcomb->total_pkt_count);
+-				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+-					short_scan = true;
+-			}
++	if (main_ant_conf == rx_ant_conf) {
++		ANT_STAT_INC(ANT_MAIN, recv_cnt);
++		ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
++	} else {
++		ANT_STAT_INC(ANT_ALT, recv_cnt);
++		ANT_LNA_INC(ANT_ALT, rx_ant_conf);
+ 	}
+ 
++	/* Short scan check */
++	short_scan = ath_ant_short_scan_check(antcomb);
++
+ 	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+-	    rs->rs_moreaggr) && !short_scan)
++	     rs->rs_moreaggr) && !short_scan)
+ 		return;
+ 
+ 	if (antcomb->total_pkt_count) {
+@@ -595,15 +798,13 @@ void ath_ant_comb_scan(struct ath_softc 
+ 				 antcomb->total_pkt_count);
+ 	}
+ 
+-
+ 	ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
+ 	curr_alt_set = div_ant_conf.alt_lna_conf;
+ 	curr_main_set = div_ant_conf.main_lna_conf;
+-
+ 	antcomb->count++;
+ 
+ 	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+-		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
++		if (alt_ratio > antcomb->ant_ratio) {
+ 			ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
+ 						  main_rssi_avg);
+ 			antcomb->alt_good = true;
+@@ -617,153 +818,47 @@ void ath_ant_comb_scan(struct ath_softc 
+ 	}
+ 
+ 	if (!antcomb->scan) {
+-		if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
+-					alt_ratio, curr_main_set, curr_alt_set,
+-					alt_rssi_avg, main_rssi_avg)) {
+-			if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+-				/* Switch main and alt LNA */
+-				div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-				div_ant_conf.alt_lna_conf  =
+-						ATH_ANT_DIV_COMB_LNA1;
+-			} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+-				div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-				div_ant_conf.alt_lna_conf  =
+-						ATH_ANT_DIV_COMB_LNA2;
+-			}
+-
+-			goto div_comb_done;
+-		} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+-			   (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+-			/* Set alt to another LNA */
+-			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+-				div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-			else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+-				div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-
+-			goto div_comb_done;
+-		}
+-
+-		if ((alt_rssi_avg < (main_rssi_avg +
+-				     div_ant_conf.lna1_lna2_delta)))
++		ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio,
++					 alt_rssi_avg, main_rssi_avg,
++					 curr_main_set, curr_alt_set);
++		if (ret)
+ 			goto div_comb_done;
+ 	}
+ 
++	if (!antcomb->scan &&
++	    (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
++		goto div_comb_done;
++
+ 	if (!antcomb->scan_not_start) {
+-		switch (curr_alt_set) {
+-		case ATH_ANT_DIV_COMB_LNA2:
+-			antcomb->rssi_lna2 = alt_rssi_avg;
+-			antcomb->rssi_lna1 = main_rssi_avg;
+-			antcomb->scan = true;
+-			/* set to A+B */
+-			div_ant_conf.main_lna_conf =
+-				ATH_ANT_DIV_COMB_LNA1;
+-			div_ant_conf.alt_lna_conf  =
+-				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+-			break;
+-		case ATH_ANT_DIV_COMB_LNA1:
+-			antcomb->rssi_lna1 = alt_rssi_avg;
+-			antcomb->rssi_lna2 = main_rssi_avg;
+-			antcomb->scan = true;
+-			/* set to A+B */
+-			div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+-			div_ant_conf.alt_lna_conf  =
+-				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+-			break;
+-		case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+-			antcomb->rssi_add = alt_rssi_avg;
+-			antcomb->scan = true;
+-			/* set to A-B */
+-			div_ant_conf.alt_lna_conf =
+-				ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+-			break;
+-		case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+-			antcomb->rssi_sub = alt_rssi_avg;
+-			antcomb->scan = false;
+-			if (antcomb->rssi_lna2 >
+-			    (antcomb->rssi_lna1 +
+-			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+-				/* use LNA2 as main LNA */
+-				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+-				    (antcomb->rssi_add > antcomb->rssi_sub)) {
+-					/* set to A+B */
+-					div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-					div_ant_conf.alt_lna_conf  =
+-						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+-				} else if (antcomb->rssi_sub >
+-					   antcomb->rssi_lna1) {
+-					/* set to A-B */
+-					div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-					div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+-				} else {
+-					/* set to LNA1 */
+-					div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-					div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-				}
+-			} else {
+-				/* use LNA1 as main LNA */
+-				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+-				    (antcomb->rssi_add > antcomb->rssi_sub)) {
+-					/* set to A+B */
+-					div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-					div_ant_conf.alt_lna_conf  =
+-						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+-				} else if (antcomb->rssi_sub >
+-					   antcomb->rssi_lna1) {
+-					/* set to A-B */
+-					div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-					div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+-				} else {
+-					/* set to LNA2 */
+-					div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
+-					div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
+-				}
+-			}
+-			break;
+-		default:
+-			break;
+-		}
++		ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
++				 alt_rssi_avg, main_rssi_avg);
+ 	} else {
+ 		if (!antcomb->alt_good) {
+ 			antcomb->scan_not_start = false;
+ 			/* Set alt to another LNA */
+ 			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
+ 				div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
++					ATH_ANT_DIV_COMB_LNA2;
+ 				div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
++					ATH_ANT_DIV_COMB_LNA1;
+ 			} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
+ 				div_ant_conf.main_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA1;
++					ATH_ANT_DIV_COMB_LNA1;
+ 				div_ant_conf.alt_lna_conf =
+-						ATH_ANT_DIV_COMB_LNA2;
++					ATH_ANT_DIV_COMB_LNA2;
+ 			}
+ 			goto div_comb_done;
+ 		}
++		ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
++						   main_rssi_avg, alt_rssi_avg,
++						   alt_ratio);
++		antcomb->quick_scan_cnt++;
+ 	}
+ 
+-	ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+-					   main_rssi_avg, alt_rssi_avg,
+-					   alt_ratio);
+-
+-	antcomb->quick_scan_cnt++;
+-
+ div_comb_done:
+ 	ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
+ 	ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
++	ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
+ 
+ 	antcomb->scan_start_time = jiffies;
+ 	antcomb->total_pkt_count = 0;
+@@ -772,26 +867,3 @@ div_comb_done:
+ 	antcomb->main_recv_cnt = 0;
+ 	antcomb->alt_recv_cnt = 0;
+ }
+-
+-void ath_ant_comb_update(struct ath_softc *sc)
+-{
+-	struct ath_hw *ah = sc->sc_ah;
+-	struct ath_common *common = ath9k_hw_common(ah);
+-	struct ath_hw_antcomb_conf div_ant_conf;
+-	u8 lna_conf;
+-
+-	ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+-
+-	if (sc->ant_rx == 1)
+-		lna_conf = ATH_ANT_DIV_COMB_LNA1;
+-	else
+-		lna_conf = ATH_ANT_DIV_COMB_LNA2;
+-
+-	div_ant_conf.main_lna_conf = lna_conf;
+-	div_ant_conf.alt_lna_conf = lna_conf;
+-
+-	ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+-
+-	if (common->antenna_diversity)
+-		ath9k_hw_antctrl_shared_chain_lnadiv(ah, true);
+-}
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struc
+ 	REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+ 
+ 	if (AR_SREV_9280_20_OR_LATER(ah)) {
+-		val = REG_READ(ah, AR_PCU_MISC_MODE2);
++		/*
++		 * For AR9280 and above, there is a new feature that allows
++		 * Multicast search based on both MAC Address and Key ID.
++		 * By default, this feature is enabled. But since the driver
++		 * is not using this feature, we switch it off; otherwise
++		 * multicast search based on MAC addr only will fail.
++		 */
++		val = REG_READ(ah, AR_PCU_MISC_MODE2) &
++			(~AR_ADHOC_MCAST_KEYID_ENABLE);
+ 
+ 		if (!AR_SREV_9271(ah))
+ 			val &= ~AR_PCU_MISC_MODE2_HWWAR1;
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+@@ -555,6 +555,69 @@ static void ar9002_hw_antdiv_comb_conf_s
+ 	REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
+ }
+ 
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++
++static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
++{
++	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
++	u8 antdiv_ctrl1, antdiv_ctrl2;
++	u32 regval;
++
++	if (enable) {
++		antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE;
++		antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE;
++
++		/*
++		 * Don't disable BT ant to allow BB to control SWCOM.
++		 */
++		btcoex->bt_coex_mode2 &= (~(AR_BT_DISABLE_BT_ANT));
++		REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
++
++		REG_WRITE(ah, AR_PHY_SWITCH_COM, ATH_BT_COEX_ANT_DIV_SWITCH_COM);
++		REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
++	} else {
++		/*
++		 * Disable antenna diversity, use LNA1 only.
++		 */
++		antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A;
++		antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A;
++
++		/*
++		 * Disable BT Ant. to allow concurrent BT and WLAN receive.
++		 */
++		btcoex->bt_coex_mode2 |= AR_BT_DISABLE_BT_ANT;
++		REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
++
++		/*
++		 * Program SWCOM table to make sure RF switch always parks
++		 * at BT side.
++		 */
++		REG_WRITE(ah, AR_PHY_SWITCH_COM, 0);
++		REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
++	}
++
++	regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
++	regval &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
++        /*
++	 * Clear ant_fast_div_bias [14:9] since for WB195,
++	 * the main LNA is always LNA1.
++	 */
++	regval &= (~(AR_PHY_9285_FAST_DIV_BIAS));
++	regval |= SM(antdiv_ctrl1, AR_PHY_9285_ANT_DIV_CTL);
++	regval |= SM(antdiv_ctrl2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
++	regval |= SM((antdiv_ctrl2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
++	regval |= SM((antdiv_ctrl1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB);
++	regval |= SM((antdiv_ctrl1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
++	REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
++
++	regval = REG_READ(ah, AR_PHY_CCK_DETECT);
++	regval &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
++	regval |= SM((antdiv_ctrl1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
++	REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
++}
++
++#endif
++
+ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
+ 				    struct ath_spec_scan *param)
+ {
+@@ -634,5 +697,9 @@ void ar9002_hw_attach_phy_ops(struct ath
+ 	ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
+ 	ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;
+ 
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++	ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity;
++#endif
++
+ 	ar9002_hw_set_nf_limits(ah);
+ }
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+@@ -317,13 +317,15 @@
+ #define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S    29
+ #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB     0x40000000
+ #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S   30
+-#define AR_PHY_9285_ANT_DIV_LNA1            2
+-#define AR_PHY_9285_ANT_DIV_LNA2            1
+-#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2  3
+-#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
+ #define AR_PHY_9285_ANT_DIV_GAINTB_0        0
+ #define AR_PHY_9285_ANT_DIV_GAINTB_1        1
+ 
++#define ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE  0x0b
++#define ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE  0x09
++#define ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A 0x04
++#define ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A 0x09
++#define ATH_BT_COEX_ANT_DIV_SWITCH_COM      0x66666666
++
+ #define AR_PHY_EXT_CCA0             0x99b8
+ #define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
+ #define AR_PHY_EXT_CCA0_THRESH62_S  0
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -3541,13 +3541,12 @@ static u16 ar9003_switch_com_spdt_get(st
+ 	return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt);
+ }
+ 
+-
+-static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
++u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
+ {
+ 	return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon);
+ }
+ 
+-static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
++u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
+ {
+ 	return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon2);
+ }
+@@ -3561,6 +3560,7 @@ static u16 ar9003_hw_ant_ctrl_chain_get(
+ 
+ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
+ {
++	struct ath_common *common = ath9k_hw_common(ah);
+ 	struct ath9k_hw_capabilities *pCap = &ah->caps;
+ 	int chain;
+ 	u32 regval, value, gpio;
+@@ -3614,6 +3614,11 @@ static void ar9003_hw_ant_ctrl_apply(str
+ 	}
+ 
+ 	value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
++	if (AR_SREV_9485(ah) && common->bt_ant_diversity) {
++		regval &= ~AR_SWITCH_TABLE_COM2_ALL;
++		regval |= ah->config.ant_ctrl_comm2g_switch_enable;
++
++	}
+ 	REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
+ 
+ 	if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) {
+@@ -3645,8 +3650,11 @@ static void ar9003_hw_ant_ctrl_apply(str
+ 		regval &= (~AR_PHY_ANT_DIV_LNADIV);
+ 		regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S;
+ 
++		if (AR_SREV_9485(ah) && common->bt_ant_diversity)
++			regval |= AR_ANT_DIV_ENABLE;
++
+ 		if (AR_SREV_9565(ah)) {
+-			if (ah->shared_chain_lnadiv) {
++			if (common->bt_ant_diversity) {
+ 				regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S);
+ 			} else {
+ 				regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S);
+@@ -3656,10 +3664,14 @@ static void ar9003_hw_ant_ctrl_apply(str
+ 
+ 		REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+ 
+-		/*enable fast_div */
++		/* enable fast_div */
+ 		regval = REG_READ(ah, AR_PHY_CCK_DETECT);
+ 		regval &= (~AR_FAST_DIV_ENABLE);
+ 		regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
++
++		if (AR_SREV_9485(ah) && common->bt_ant_diversity)
++			regval |= AR_FAST_DIV_ENABLE;
++
+ 		REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
+ 
+ 		if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
+@@ -3673,9 +3685,9 @@ static void ar9003_hw_ant_ctrl_apply(str
+ 				     AR_PHY_ANT_DIV_ALT_GAINTB |
+ 				     AR_PHY_ANT_DIV_MAIN_GAINTB));
+ 			/* by default use LNA1 for the main antenna */
+-			regval |= (AR_PHY_ANT_DIV_LNA1 <<
++			regval |= (ATH_ANT_DIV_COMB_LNA1 <<
+ 				   AR_PHY_ANT_DIV_MAIN_LNACONF_S);
+-			regval |= (AR_PHY_ANT_DIV_LNA2 <<
++			regval |= (ATH_ANT_DIV_COMB_LNA2 <<
+ 				   AR_PHY_ANT_DIV_ALT_LNACONF_S);
+ 			REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+ 		}
+@@ -3813,6 +3825,11 @@ static void ar9003_hw_atten_apply(struct
+ 			else
+ 				value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
+ 
++			if (ah->config.alt_mingainidx)
++				REG_RMW_FIELD(ah, AR_PHY_EXT_ATTEN_CTL_0,
++					      AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
++					      value);
++
+ 			REG_RMW_FIELD(ah, ext_atten_reg[i],
+ 				      AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
+ 				      value);
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+@@ -334,6 +334,8 @@ struct ar9300_eeprom {
+ 
+ s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah);
+ s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah);
++u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz);
++u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz);
+ 
+ u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz);
+ 
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+@@ -148,6 +148,8 @@
+ #define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S   28
+ #define AR_PHY_EXT_CCA_THRESH62 0x007F0000
+ #define AR_PHY_EXT_CCA_THRESH62_S       16
++#define AR_PHY_EXTCHN_PWRTHR1_ANT_DIV_ALT_ANT_MINGAINIDX    0x0000FF00
++#define AR_PHY_EXTCHN_PWRTHR1_ANT_DIV_ALT_ANT_MINGAINIDX_S  8
+ #define AR_PHY_EXT_MINCCA_PWR   0x01FF0000
+ #define AR_PHY_EXT_MINCCA_PWR_S 16
+ #define AR_PHY_EXT_CYCPWR_THR1 0x0000FE00L
+@@ -296,11 +298,6 @@
+ #define AR_PHY_ANT_DIV_MAIN_GAINTB              0x40000000
+ #define AR_PHY_ANT_DIV_MAIN_GAINTB_S            30
+ 
+-#define AR_PHY_ANT_DIV_LNA1_MINUS_LNA2          0x0
+-#define AR_PHY_ANT_DIV_LNA2                     0x1
+-#define AR_PHY_ANT_DIV_LNA1                     0x2
+-#define AR_PHY_ANT_DIV_LNA1_PLUS_LNA2           0x3
+-
+ #define AR_PHY_EXTCHN_PWRTHR1   (AR_AGC_BASE + 0x2c)
+ #define AR_PHY_EXT_CHN_WIN      (AR_AGC_BASE + 0x30)
+ #define AR_PHY_20_40_DET_THR    (AR_AGC_BASE + 0x34)
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -28,9 +28,13 @@ struct fft_sample_tlv;
+ #ifdef CPTCFG_ATH9K_DEBUGFS
+ #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
+ #define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++
++#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++
++#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++;
+ #else
+ #define TX_STAT_INC(q, c) do { } while (0)
+ #define RESET_STAT_INC(sc, type) do { } while (0)
++#define ANT_STAT_INC(i, c) do { } while (0)
++#define ANT_LNA_INC(i, c) do { } while (0)
+ #endif
+ 
+ enum ath_reset_type {
+@@ -243,11 +247,22 @@ struct ath_rx_stats {
+ 	u32 rx_spectral;
+ };
+ 
++#define ANT_MAIN 0
++#define ANT_ALT  1
++
++struct ath_antenna_stats {
++	u32 recv_cnt;
++	u32 rssi_avg;
++	u32 lna_recv_cnt[4];
++	u32 lna_attempt_cnt[4];
++};
++
+ struct ath_stats {
+ 	struct ath_interrupt_stats istats;
+ 	struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
+ 	struct ath_rx_stats rxstats;
+ 	struct ath_dfs_stats dfs_stats;
++	struct ath_antenna_stats ant_stats[2];
+ 	u32 reset[__RESET_TYPE_MAX];
+ };
+ 
+@@ -281,10 +296,11 @@ void ath9k_sta_remove_debugfs(struct iee
+ 			      struct ieee80211_vif *vif,
+ 			      struct ieee80211_sta *sta,
+ 			      struct dentry *dir);
+-
+ void ath_debug_send_fft_sample(struct ath_softc *sc,
+ 			       struct fft_sample_tlv *fft_sample);
+-
++void ath9k_debug_stat_ant(struct ath_softc *sc,
++			  struct ath_hw_antcomb_conf *div_ant_conf,
++			  int main_rssi_avg, int alt_rssi_avg);
+ #else
+ 
+ #define RX_STAT_INC(c) /* NOP */
+@@ -297,12 +313,10 @@ static inline int ath9k_init_debug(struc
+ static inline void ath9k_deinit_debug(struct ath_softc *sc)
+ {
+ }
+-
+ static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
+ 					    enum ath9k_int status)
+ {
+ }
+-
+ static inline void ath_debug_stat_tx(struct ath_softc *sc,
+ 				     struct ath_buf *bf,
+ 				     struct ath_tx_status *ts,
+@@ -310,11 +324,16 @@ static inline void ath_debug_stat_tx(str
+ 				     unsigned int flags)
+ {
+ }
+-
+ static inline void ath_debug_stat_rx(struct ath_softc *sc,
+ 				     struct ath_rx_status *rs)
+ {
+ }
++static inline void ath9k_debug_stat_ant(struct ath_softc *sc,
++					struct ath_hw_antcomb_conf *div_ant_conf,
++					int main_rssi_avg, int alt_rssi_avg)
++{
++
++}
+ 
+ #endif /* CPTCFG_ATH9K_DEBUGFS */
+ 
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -812,6 +812,7 @@ static void ath9k_hw_4k_set_gain(struct 
+ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
+ 					 struct ath9k_channel *chan)
+ {
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
+ 	struct modal_eep_4k_header *pModal;
+ 	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ 	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+@@ -858,6 +859,24 @@ static void ath9k_hw_4k_set_board_values
+ 
+ 		REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
+ 		regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
++
++		if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
++			/*
++			 * If diversity combining is enabled,
++			 * set MAIN to LNA1 and ALT to LNA2 initially.
++			 */
++			regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
++			regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
++				     AR_PHY_9285_ANT_DIV_ALT_LNACONF));
++
++			regVal |= (ATH_ANT_DIV_COMB_LNA1 <<
++				   AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S);
++			regVal |= (ATH_ANT_DIV_COMB_LNA2 <<
++				   AR_PHY_9285_ANT_DIV_ALT_LNACONF_S);
++			regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
++			regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S);
++			REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
++		}
+ 	}
+ 
+ 	if (pModal->version >= 2) {
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -78,13 +78,16 @@ static inline void ath9k_hw_antdiv_comb_
+ 	ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
+ }
+ 
+-static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
+-							bool enable)
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++
++static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
+ {
+-	if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv)
+-		ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable);
++	if (ath9k_hw_ops(ah)->set_bt_ant_diversity)
++		ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable);
+ }
+ 
++#endif
++
+ /* Private hardware call ops */
+ 
+ /* PHY ops */
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -450,7 +450,6 @@ static void ath9k_hw_init_config(struct 
+ 	ah->config.ack_6mb = 0x0;
+ 	ah->config.cwm_ignore_extcca = 0;
+ 	ah->config.pcie_clock_req = 0;
+-	ah->config.pcie_waen = 0;
+ 	ah->config.analog_shiftreg = 1;
+ 
+ 	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+@@ -1069,7 +1068,7 @@ void ath9k_hw_init_global_settings(struc
+ 		if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+ 		    tx_lat += 11;
+ 
+-		sifstime *= 2;
++		sifstime = 32;
+ 		ack_offset = 16;
+ 		slottime = 13;
+ 	} else if (IS_CHAN_QUARTER_RATE(chan)) {
+@@ -1079,7 +1078,7 @@ void ath9k_hw_init_global_settings(struc
+ 		if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+ 		    tx_lat += 22;
+ 
+-		sifstime *= 4;
++		sifstime = 64;
+ 		ack_offset = 32;
+ 		slottime = 21;
+ 	} else {
+@@ -1116,7 +1115,6 @@ void ath9k_hw_init_global_settings(struc
+ 		ctstimeout += 48 - sifstime - ah->slottime;
+ 	}
+ 
+-
+ 	ath9k_hw_set_sifs_time(ah, sifstime);
+ 	ath9k_hw_setslottime(ah, slottime);
+ 	ath9k_hw_set_ack_timeout(ah, acktimeout);
+@@ -1496,16 +1494,18 @@ static bool ath9k_hw_channel_change(stru
+ 				    struct ath9k_channel *chan)
+ {
+ 	struct ath_common *common = ath9k_hw_common(ah);
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
++	bool band_switch = false, mode_diff = false;
++	u8 ini_reloaded = 0;
+ 	u32 qnum;
+ 	int r;
+-	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
+-	bool band_switch, mode_diff;
+-	u8 ini_reloaded;
+-
+-	band_switch = (chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ)) !=
+-		      (ah->curchan->channelFlags & (CHANNEL_2GHZ |
+-						    CHANNEL_5GHZ));
+-	mode_diff = (chan->chanmode != ah->curchan->chanmode);
++
++	if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
++		u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
++		u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
++		band_switch = (cur != new);
++		mode_diff = (chan->chanmode != ah->curchan->chanmode);
++	}
+ 
+ 	for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
+ 		if (ath9k_hw_numtxpending(ah, qnum)) {
+@@ -1520,11 +1520,12 @@ static bool ath9k_hw_channel_change(stru
+ 		return false;
+ 	}
+ 
+-	if (edma && (band_switch || mode_diff)) {
++	if (band_switch || mode_diff) {
+ 		ath9k_hw_mark_phy_inactive(ah);
+ 		udelay(5);
+ 
+-		ath9k_hw_init_pll(ah, NULL);
++		if (band_switch)
++			ath9k_hw_init_pll(ah, chan);
+ 
+ 		if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) {
+ 			ath_err(common, "Failed to do fast channel change\n");
+@@ -1541,22 +1542,21 @@ static bool ath9k_hw_channel_change(stru
+ 	}
+ 	ath9k_hw_set_clockrate(ah);
+ 	ath9k_hw_apply_txpower(ah, chan, false);
+-	ath9k_hw_rfbus_done(ah);
+ 
+ 	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+ 		ath9k_hw_set_delta_slope(ah, chan);
+ 
+ 	ath9k_hw_spur_mitigate_freq(ah, chan);
+ 
+-	if (edma && (band_switch || mode_diff)) {
+-		ah->ah_flags |= AH_FASTCC;
+-		if (band_switch || ini_reloaded)
+-			ah->eep_ops->set_board_values(ah, chan);
++	if (band_switch || ini_reloaded)
++		ah->eep_ops->set_board_values(ah, chan);
+ 
+-		ath9k_hw_init_bb(ah, chan);
++	ath9k_hw_init_bb(ah, chan);
++	ath9k_hw_rfbus_done(ah);
+ 
+-		if (band_switch || ini_reloaded)
+-			ath9k_hw_init_cal(ah, chan);
++	if (band_switch || ini_reloaded) {
++		ah->ah_flags |= AH_FASTCC;
++		ath9k_hw_init_cal(ah, chan);
+ 		ah->ah_flags &= ~AH_FASTCC;
+ 	}
+ 
+@@ -1778,16 +1778,11 @@ static void ath9k_hw_init_desc(struct at
+ /*
+  * Fast channel change:
+  * (Change synthesizer based on channel freq without resetting chip)
+- *
+- * Don't do FCC when
+- *   - Flag is not set
+- *   - Chip is just coming out of full sleep
+- *   - Channel to be set is same as current channel
+- *   - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel)
+  */
+ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
+ {
+ 	struct ath_common *common = ath9k_hw_common(ah);
++	struct ath9k_hw_capabilities *pCap = &ah->caps;
+ 	int ret;
+ 
+ 	if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI)
+@@ -1806,9 +1801,21 @@ static int ath9k_hw_do_fastcc(struct ath
+ 	    (CHANNEL_HALF | CHANNEL_QUARTER))
+ 		goto fail;
+ 
+-	if ((chan->channelFlags & CHANNEL_ALL) !=
+-	    (ah->curchan->channelFlags & CHANNEL_ALL))
+-		goto fail;
++	/*
++	 * If cross-band fcc is not supoprted, bail out if
++	 * either channelFlags or chanmode differ.
++	 *
++	 * chanmode will be different if the HT operating mode
++	 * changes because of CSA.
++	 */
++	if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH)) {
++		if ((chan->channelFlags & CHANNEL_ALL) !=
++		    (ah->curchan->channelFlags & CHANNEL_ALL))
++			goto fail;
++
++		if (chan->chanmode != ah->curchan->chanmode)
++			goto fail;
++	}
+ 
+ 	if (!ath9k_hw_check_alive(ah))
+ 		goto fail;
+@@ -2047,7 +2054,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ 
+ 	ath9k_hw_apply_gpio_override(ah);
+ 
+-	if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv)
++	if (AR_SREV_9565(ah) && common->bt_ant_diversity)
+ 		REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
+ 
+ 	return 0;
+@@ -2550,34 +2557,28 @@ int ath9k_hw_fill_cap_info(struct ath_hw
+ 	if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
+ 		pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
+ 
+-	if (AR_SREV_9285(ah))
++	if (AR_SREV_9285(ah)) {
+ 		if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
+ 			ant_div_ctl1 =
+ 				ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+-			if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
++			if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) {
+ 				pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
++				ath_info(common, "Enable LNA combining\n");
++			}
+ 		}
++	}
++
+ 	if (AR_SREV_9300_20_OR_LATER(ah)) {
+ 		if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
+ 			pCap->hw_caps |= ATH9K_HW_CAP_APM;
+ 	}
+ 
+-
+ 	if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
+ 		ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+-		/*
+-		 * enable the diversity-combining algorithm only when
+-		 * both enable_lna_div and enable_fast_div are set
+-		 *		Table for Diversity
+-		 * ant_div_alt_lnaconf		bit 0-1
+-		 * ant_div_main_lnaconf		bit 2-3
+-		 * ant_div_alt_gaintb		bit 4
+-		 * ant_div_main_gaintb		bit 5
+-		 * enable_ant_div_lnadiv	bit 6
+-		 * enable_ant_fast_div		bit 7
+-		 */
+-		if ((ant_div_ctl1 >> 0x6) == 0x3)
++		if ((ant_div_ctl1 >> 0x6) == 0x3) {
+ 			pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
++			ath_info(common, "Enable LNA combining\n");
++		}
+ 	}
+ 
+ 	if (ath9k_hw_dfs_tested(ah))
+@@ -2610,6 +2611,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw
+ 	    ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+ 			pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
+ 
++	/*
++	 * Fast channel change across bands is available
++	 * only for AR9462 and AR9565.
++	 */
++	if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
++		pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH;
++
+ 	return 0;
+ }
+ 
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -247,6 +247,8 @@ enum ath9k_hw_caps {
+ 	ATH9K_HW_CAP_DFS			= BIT(16),
+ 	ATH9K_HW_WOW_DEVICE_CAPABLE		= BIT(17),
+ 	ATH9K_HW_CAP_PAPRD			= BIT(18),
++	ATH9K_HW_CAP_FCC_BAND_SWITCH		= BIT(19),
++	ATH9K_HW_CAP_BT_ANT_DIV			= BIT(20),
+ };
+ 
+ /*
+@@ -309,8 +311,11 @@ struct ath9k_ops_config {
+ 	u16 ani_poll_interval; /* ANI poll interval in ms */
+ 
+ 	/* Platform specific config */
++	u32 aspm_l1_fix;
+ 	u32 xlna_gpio;
++	u32 ant_ctrl_comm2g_switch_enable;
+ 	bool xatten_margin_cfg;
++	bool alt_mingainidx;
+ };
+ 
+ enum ath9k_int {
+@@ -716,11 +721,14 @@ struct ath_hw_ops {
+ 			struct ath_hw_antcomb_conf *antconf);
+ 	void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+ 			struct ath_hw_antcomb_conf *antconf);
+-	void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
+ 	void (*spectral_scan_config)(struct ath_hw *ah,
+ 				     struct ath_spec_scan *param);
+ 	void (*spectral_scan_trigger)(struct ath_hw *ah);
+ 	void (*spectral_scan_wait)(struct ath_hw *ah);
++
++#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
++	void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable);
++#endif
+ };
+ 
+ struct ath_nf_limits {
+@@ -765,7 +773,6 @@ struct ath_hw {
+ 	bool aspm_enabled;
+ 	bool is_monitoring;
+ 	bool need_an_top2_fixup;
+-	bool shared_chain_lnadiv;
+ 	u16 tx_trig_level;
+ 
+ 	u32 nf_regs[6];
+--- a/drivers/net/wireless/ath/ath9k/pci.c
++++ b/drivers/net/wireless/ath/ath9k/pci.c
+@@ -29,6 +29,60 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_i
+ 	{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
+ 	{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
+ 	{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
++
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 PCI_VENDOR_ID_AZWAVE,
++			 0x1C71),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 PCI_VENDOR_ID_FOXCONN,
++			 0xE01F),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 0x11AD, /* LITEON */
++			 0x6632),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 0x11AD, /* LITEON */
++			 0x6642),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 PCI_VENDOR_ID_QMI,
++			 0x0306),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 0x185F, /* WNC */
++			 0x309D),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 0x10CF, /* Fujitsu */
++			 0x147C),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 0x10CF, /* Fujitsu */
++			 0x147D),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002A,
++			 0x10CF, /* Fujitsu */
++			 0x1536),
++	  .driver_data = ATH9K_PCI_D3_L1_WAR },
++
++	/* AR9285 card for Asus */
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x002B,
++			 PCI_VENDOR_ID_AZWAVE,
++			 0x2C37),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++
+ 	{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+ 	{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
+ 	{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
+@@ -40,29 +94,106 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_i
+ 			 0x0032,
+ 			 PCI_VENDOR_ID_AZWAVE,
+ 			 0x2086),
+-	  .driver_data = ATH9K_PCI_CUS198 },
++	  .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
+ 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 			 0x0032,
+ 			 PCI_VENDOR_ID_AZWAVE,
+ 			 0x1237),
+-	  .driver_data = ATH9K_PCI_CUS198 },
++	  .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
+ 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 			 0x0032,
+ 			 PCI_VENDOR_ID_AZWAVE,
+ 			 0x2126),
+-	  .driver_data = ATH9K_PCI_CUS198 },
++	  .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_AZWAVE,
++			 0x126A),
++	  .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV },
+ 
+ 	/* PCI-E CUS230 */
+ 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 			 0x0032,
+ 			 PCI_VENDOR_ID_AZWAVE,
+ 			 0x2152),
+-	  .driver_data = ATH9K_PCI_CUS230 },
++	  .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV },
+ 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 			 0x0032,
+ 			 PCI_VENDOR_ID_FOXCONN,
+ 			 0xE075),
+-	  .driver_data = ATH9K_PCI_CUS230 },
++	  .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV },
++
++	/* WB225 */
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_ATHEROS,
++			 0x3119),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_ATHEROS,
++			 0x3122),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 0x185F, /* WNC */
++			 0x3119),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 0x185F, /* WNC */
++			 0x3027),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0x4105),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0x4106),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0x410D),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0x410E),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0x410F),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0xC706),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0xC680),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_SAMSUNG,
++			 0xC708),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_LENOVO,
++			 0x3218),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
++			 0x0032,
++			 PCI_VENDOR_ID_LENOVO,
++			 0x3219),
++	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
+ 
+ 	{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
+ 	{ PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */
+@@ -229,6 +360,22 @@ static void ath_pci_aspm_init(struct ath
+ 		return;
+ 	}
+ 
++	/*
++	 * 0x70c - Ack Frequency Register.
++	 *
++	 * Bits 27:29 - DEFAULT_L1_ENTRANCE_LATENCY.
++	 *
++	 * 000 : 1 us
++	 * 001 : 2 us
++	 * 010 : 4 us
++	 * 011 : 8 us
++	 * 100 : 16 us
++	 * 101 : 32 us
++	 * 110/111 : 64 us
++	 */
++	if (AR_SREV_9462(ah))
++		pci_read_config_dword(pdev, 0x70c, &ah->config.aspm_l1_fix);
++
+ 	pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm);
+ 	if (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1)) {
+ 		ah->aspm_enabled = true;
+--- a/drivers/net/wireless/ath/ath9k/phy.h
++++ b/drivers/net/wireless/ath/ath9k/phy.h
+@@ -48,4 +48,11 @@
+ #define AR_PHY_PLL_CONTROL 0x16180
+ #define AR_PHY_PLL_MODE 0x16184
+ 
++enum ath9k_ant_div_comb_lna_conf {
++	ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
++	ATH_ANT_DIV_COMB_LNA2,
++	ATH_ANT_DIV_COMB_LNA1,
++	ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
++};
++
+ #endif
+--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
++++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
+@@ -73,7 +73,6 @@
+ #include "iwl-prph.h"
+ 
+ /* A TimeUnit is 1024 microsecond */
+-#define TU_TO_JIFFIES(_tu)	(usecs_to_jiffies((_tu) * 1024))
+ #define MSEC_TO_TU(_msec)	(_msec*1000/1024)
+ 
+ /*
+@@ -191,8 +190,7 @@ static void iwl_mvm_te_handle_notif(stru
+ 		iwl_mvm_te_clear_data(mvm, te_data);
+ 	} else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
+ 		te_data->running = true;
+-		te_data->end_jiffies = jiffies +
+-			TU_TO_JIFFIES(te_data->duration);
++		te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration);
+ 
+ 		if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ 			set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+@@ -329,8 +327,7 @@ void iwl_mvm_protect_session(struct iwl_
+ 	lockdep_assert_held(&mvm->mutex);
+ 
+ 	if (te_data->running &&
+-	    time_after(te_data->end_jiffies,
+-		       jiffies + TU_TO_JIFFIES(min_duration))) {
++	    time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
+ 		IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
+ 			     jiffies_to_msecs(te_data->end_jiffies - jiffies));
+ 		return;
+--- a/include/linux/ieee80211.h
++++ b/include/linux/ieee80211.h
+@@ -2279,4 +2279,8 @@ static inline bool ieee80211_check_tim(c
+ 	return !!(tim->virtual_map[index] & mask);
+ }
+ 
++/* convert time units */
++#define TU_TO_JIFFIES(x)	(usecs_to_jiffies((x) * 1024))
++#define TU_TO_EXP_TIME(x)	(jiffies + TU_TO_JIFFIES(x))
++
+ #endif /* LINUX_IEEE80211_H */
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -210,7 +210,7 @@ static bool rc_no_data_or_no_ack_use_min
+ 		!ieee80211_is_data(fc);
+ }
+ 
+-static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
++static void rc_send_low_basicrate(s8 *idx, u32 basic_rates,
+ 				  struct ieee80211_supported_band *sband)
+ {
+ 	u8 i;
+@@ -272,28 +272,37 @@ static void __rate_control_send_low(stru
+ }
+ 
+ 
+-bool rate_control_send_low(struct ieee80211_sta *sta,
++bool rate_control_send_low(struct ieee80211_sta *pubsta,
+ 			   void *priv_sta,
+ 			   struct ieee80211_tx_rate_control *txrc)
+ {
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+ 	struct ieee80211_supported_band *sband = txrc->sband;
++	struct sta_info *sta;
+ 	int mcast_rate;
++	bool use_basicrate = false;
+ 
+-	if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
+-		__rate_control_send_low(txrc->hw, sband, sta, info);
++	if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
++		__rate_control_send_low(txrc->hw, sband, pubsta, info);
+ 
+-		if (!sta && txrc->bss) {
++		if (!pubsta && txrc->bss) {
+ 			mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
+ 			if (mcast_rate > 0) {
+ 				info->control.rates[0].idx = mcast_rate - 1;
+ 				return true;
+ 			}
++			use_basicrate = true;
++		} else if (pubsta) {
++			sta = container_of(pubsta, struct sta_info, sta);
++			if (ieee80211_vif_is_mesh(&sta->sdata->vif))
++				use_basicrate = true;
++		}
+ 
+-			rc_send_low_broadcast(&info->control.rates[0].idx,
++		if (use_basicrate)
++			rc_send_low_basicrate(&info->control.rates[0].idx,
+ 					      txrc->bss_conf->basic_rates,
+ 					      sband);
+-		}
++
+ 		return true;
+ 	}
+ 	return false;
+--- a/drivers/net/wireless/ath/ath9k/Kconfig
++++ b/drivers/net/wireless/ath/ath9k/Kconfig
+@@ -60,7 +60,7 @@ config ATH9K_AHB
+ 
+ config ATH9K_DEBUGFS
+ 	bool "Atheros ath9k debugging"
+-	depends on ATH9K
++	depends on ATH9K && DEBUG_FS
+ 	select MAC80211_DEBUGFS
+ 	depends on RELAY
+ 	---help---
+--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+@@ -269,13 +269,12 @@ static void ar9002_hw_configpcipowersave
+ 			if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+ 				val |= AR_WA_D3_L1_DISABLE;
+ 		} else {
+-			if (((AR_SREV_9285(ah) ||
+-			      AR_SREV_9271(ah) ||
+-			      AR_SREV_9287(ah)) &&
+-			     (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+-			    (AR_SREV_9280(ah) &&
+-			     (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+-				val |= AR_WA_D3_L1_DISABLE;
++			if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) {
++				if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
++					val |= AR_WA_D3_L1_DISABLE;
++			} else if (AR_SREV_9280(ah)) {
++				if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
++					val |= AR_WA_D3_L1_DISABLE;
+ 			}
+ 		}
+ 
+@@ -297,24 +296,18 @@ static void ar9002_hw_configpcipowersave
+ 	} else {
+ 		if (ah->config.pcie_waen) {
+ 			val = ah->config.pcie_waen;
+-			if (!power_off)
+-				val &= (~AR_WA_D3_L1_DISABLE);
++			val &= (~AR_WA_D3_L1_DISABLE);
+ 		} else {
+-			if (AR_SREV_9285(ah) ||
+-			    AR_SREV_9271(ah) ||
+-			    AR_SREV_9287(ah)) {
++			if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) {
+ 				val = AR9285_WA_DEFAULT;
+-				if (!power_off)
+-					val &= (~AR_WA_D3_L1_DISABLE);
+-			}
+-			else if (AR_SREV_9280(ah)) {
++				val &= (~AR_WA_D3_L1_DISABLE);
++			} else if (AR_SREV_9280(ah)) {
+ 				/*
+ 				 * For AR9280 chips, bit 22 of 0x4004
+ 				 * needs to be set.
+ 				 */
+ 				val = AR9280_WA_DEFAULT;
+-				if (!power_off)
+-					val &= (~AR_WA_D3_L1_DISABLE);
++				val &= (~AR_WA_D3_L1_DISABLE);
+ 			} else {
+ 				val = AR_WA_DEFAULT;
+ 			}
+--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+@@ -153,7 +153,7 @@ static void ar9003_hw_init_mode_regs(str
+ 		if (!ah->is_clk_25mhz)
+ 			INIT_INI_ARRAY(&ah->iniAdditional,
+ 				       ar9340_1p0_radio_core_40M);
+-	} else if (AR_SREV_9485_11(ah)) {
++	} else if (AR_SREV_9485_11_OR_LATER(ah)) {
+ 		/* mac */
+ 		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ 				ar9485_1_1_mac_core);
+@@ -424,7 +424,7 @@ static void ar9003_tx_gain_table_mode0(s
+ 	else if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9340Modes_lowest_ob_db_tx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9485_modes_lowest_ob_db_tx_gain_1_1);
+ 	else if (AR_SREV_9550(ah))
+@@ -458,7 +458,7 @@ static void ar9003_tx_gain_table_mode1(s
+ 	else if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9340Modes_high_ob_db_tx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9485Modes_high_ob_db_tx_gain_1_1);
+ 	else if (AR_SREV_9580(ah))
+@@ -492,7 +492,7 @@ static void ar9003_tx_gain_table_mode2(s
+ 	else if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9340Modes_low_ob_db_tx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9485Modes_low_ob_db_tx_gain_1_1);
+ 	else if (AR_SREV_9580(ah))
+@@ -517,7 +517,7 @@ static void ar9003_tx_gain_table_mode3(s
+ 	else if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9340Modes_high_power_tx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9485Modes_high_power_tx_gain_1_1);
+ 	else if (AR_SREV_9580(ah))
+@@ -552,7 +552,7 @@ static void ar9003_tx_gain_table_mode4(s
+ 
+ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
+ {
+-	if (AR_SREV_9485_11(ah))
++	if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9485Modes_green_ob_db_tx_gain_1_1);
+ 	else if (AR_SREV_9340(ah))
+@@ -571,7 +571,7 @@ static void ar9003_tx_gain_table_mode6(s
+ 	if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 			ar9485Modes_green_spur_ob_db_tx_gain_1_1);
+ 	else if (AR_SREV_9580(ah))
+@@ -611,7 +611,7 @@ static void ar9003_rx_gain_table_mode0(s
+ 	else if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 				ar9340Common_rx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 			       ar9485_common_rx_gain_1_1);
+ 	else if (AR_SREV_9550(ah)) {
+@@ -644,7 +644,7 @@ static void ar9003_rx_gain_table_mode1(s
+ 	else if (AR_SREV_9340(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 			ar9340Common_wo_xlna_rx_gain_table_1p0);
+-	else if (AR_SREV_9485_11(ah))
++	else if (AR_SREV_9485_11_OR_LATER(ah))
+ 		INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 			ar9485Common_wo_xlna_rx_gain_1_1);
+ 	else if (AR_SREV_9462_21(ah))
+@@ -745,16 +745,25 @@ static void ar9003_hw_init_mode_gain_reg
+ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
+ 					 bool power_off)
+ {
++	/*
++	 * Increase L1 Entry Latency. Some WB222 boards don't have
++	 * this change in eeprom/OTP.
++	 *
++	 */
++	if (AR_SREV_9462(ah)) {
++		u32 val = ah->config.aspm_l1_fix;
++		if ((val & 0xff000000) == 0x17000000) {
++			val &= 0x00ffffff;
++			val |= 0x27000000;
++			REG_WRITE(ah, 0x570c, val);
++		}
++	}
++
+ 	/* Nothing to do on restore for 11N */
+ 	if (!power_off /* !restore */) {
+ 		/* set bit 19 to allow forcing of pcie core into L1 state */
+ 		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+-
+-		/* Several PCIe massages to ensure proper behaviour */
+-		if (ah->config.pcie_waen)
+-			REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
+-		else
+-			REG_WRITE(ah, AR_WA, ah->WARegVal);
++		REG_WRITE(ah, AR_WA, ah->WARegVal);
+ 	}
+ 
+ 	/*
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -491,6 +491,7 @@ int ath9k_hw_process_rxdesc_edma(struct 
+ 	rxs->rs_rate = MS(rxsp->status1, AR_RxRate);
+ 	rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0;
+ 
++	rxs->rs_firstaggr = (rxsp->status11 & AR_RxFirstAggr) ? 1 : 0;
+ 	rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0;
+ 	rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
+ 	rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
+--- a/drivers/net/wireless/ath/ath9k/common.c
++++ b/drivers/net/wireless/ath/ath9k/common.c
+@@ -49,37 +49,40 @@ int ath9k_cmn_get_hw_crypto_keytype(stru
+ }
+ EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype);
+ 
+-static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan,
+-				 enum nl80211_channel_type channel_type)
++static u32 ath9k_get_extchanmode(struct cfg80211_chan_def *chandef)
+ {
+ 	u32 chanmode = 0;
+ 
+-	switch (chan->band) {
++	switch (chandef->chan->band) {
+ 	case IEEE80211_BAND_2GHZ:
+-		switch (channel_type) {
+-		case NL80211_CHAN_NO_HT:
+-		case NL80211_CHAN_HT20:
++		switch (chandef->width) {
++		case NL80211_CHAN_WIDTH_20_NOHT:
++		case NL80211_CHAN_WIDTH_20:
+ 			chanmode = CHANNEL_G_HT20;
+ 			break;
+-		case NL80211_CHAN_HT40PLUS:
+-			chanmode = CHANNEL_G_HT40PLUS;
++		case NL80211_CHAN_WIDTH_40:
++			if (chandef->center_freq1 > chandef->chan->center_freq)
++				chanmode = CHANNEL_G_HT40PLUS;
++			else
++				chanmode = CHANNEL_G_HT40MINUS;
+ 			break;
+-		case NL80211_CHAN_HT40MINUS:
+-			chanmode = CHANNEL_G_HT40MINUS;
++		default:
+ 			break;
+ 		}
+ 		break;
+ 	case IEEE80211_BAND_5GHZ:
+-		switch (channel_type) {
+-		case NL80211_CHAN_NO_HT:
+-		case NL80211_CHAN_HT20:
++		switch (chandef->width) {
++		case NL80211_CHAN_WIDTH_20_NOHT:
++		case NL80211_CHAN_WIDTH_20:
+ 			chanmode = CHANNEL_A_HT20;
+ 			break;
+-		case NL80211_CHAN_HT40PLUS:
+-			chanmode = CHANNEL_A_HT40PLUS;
++		case NL80211_CHAN_WIDTH_40:
++			if (chandef->center_freq1 > chandef->chan->center_freq)
++				chanmode = CHANNEL_A_HT40PLUS;
++			else
++				chanmode = CHANNEL_A_HT40MINUS;
+ 			break;
+-		case NL80211_CHAN_HT40MINUS:
+-			chanmode = CHANNEL_A_HT40MINUS;
++		default:
+ 			break;
+ 		}
+ 		break;
+@@ -94,13 +97,12 @@ static u32 ath9k_get_extchanmode(struct 
+  * Update internal channel flags.
+  */
+ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+-			       struct ieee80211_channel *chan,
+-			       enum nl80211_channel_type channel_type)
++			       struct cfg80211_chan_def *chandef)
+ {
+-	ichan->channel = chan->center_freq;
+-	ichan->chan = chan;
++	ichan->channel = chandef->chan->center_freq;
++	ichan->chan = chandef->chan;
+ 
+-	if (chan->band == IEEE80211_BAND_2GHZ) {
++	if (chandef->chan->band == IEEE80211_BAND_2GHZ) {
+ 		ichan->chanmode = CHANNEL_G;
+ 		ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
+ 	} else {
+@@ -108,8 +110,22 @@ void ath9k_cmn_update_ichannel(struct at
+ 		ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
+ 	}
+ 
+-	if (channel_type != NL80211_CHAN_NO_HT)
+-		ichan->chanmode = ath9k_get_extchanmode(chan, channel_type);
++	switch (chandef->width) {
++	case NL80211_CHAN_WIDTH_5:
++		ichan->channelFlags |= CHANNEL_QUARTER;
++		break;
++	case NL80211_CHAN_WIDTH_10:
++		ichan->channelFlags |= CHANNEL_HALF;
++		break;
++	case NL80211_CHAN_WIDTH_20_NOHT:
++		break;
++	case NL80211_CHAN_WIDTH_20:
++	case NL80211_CHAN_WIDTH_40:
++		ichan->chanmode = ath9k_get_extchanmode(chandef);
++		break;
++	default:
++		WARN_ON(1);
++	}
+ }
+ EXPORT_SYMBOL(ath9k_cmn_update_ichannel);
+ 
+@@ -125,8 +141,7 @@ struct ath9k_channel *ath9k_cmn_get_curc
+ 
+ 	chan_idx = curchan->hw_value;
+ 	channel = &ah->channels[chan_idx];
+-	ath9k_cmn_update_ichannel(channel, curchan,
+-				  cfg80211_get_chandef_type(&hw->conf.chandef));
++	ath9k_cmn_update_ichannel(channel, &hw->conf.chandef);
+ 
+ 	return channel;
+ }
+--- a/drivers/net/wireless/ath/ath9k/common.h
++++ b/drivers/net/wireless/ath/ath9k/common.h
+@@ -44,8 +44,7 @@
+ 
+ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
+ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+-			       struct ieee80211_channel *chan,
+-			       enum nl80211_channel_type channel_type);
++			       struct cfg80211_chan_def *chandef);
+ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
+ 					       struct ath_hw *ah);
+ int ath9k_cmn_count_streams(unsigned int chainmask, int max);
+--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
+@@ -115,10 +115,10 @@ static int hif_usb_send_regout(struct hi
+ 	cmd->skb = skb;
+ 	cmd->hif_dev = hif_dev;
+ 
+-	usb_fill_bulk_urb(urb, hif_dev->udev,
+-			 usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE),
++	usb_fill_int_urb(urb, hif_dev->udev,
++			 usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE),
+ 			 skb->data, skb->len,
+-			 hif_usb_regout_cb, cmd);
++			 hif_usb_regout_cb, cmd, 1);
+ 
+ 	usb_anchor_urb(urb, &hif_dev->regout_submitted);
+ 	ret = usb_submit_urb(urb, GFP_KERNEL);
+@@ -723,11 +723,11 @@ static void ath9k_hif_usb_reg_in_cb(stru
+ 			return;
+ 		}
+ 
+-		usb_fill_bulk_urb(urb, hif_dev->udev,
+-				 usb_rcvbulkpipe(hif_dev->udev,
++		usb_fill_int_urb(urb, hif_dev->udev,
++				 usb_rcvintpipe(hif_dev->udev,
+ 						 USB_REG_IN_PIPE),
+ 				 nskb->data, MAX_REG_IN_BUF_SIZE,
+-				 ath9k_hif_usb_reg_in_cb, nskb);
++				 ath9k_hif_usb_reg_in_cb, nskb, 1);
+ 	}
+ 
+ resubmit:
+@@ -909,11 +909,11 @@ static int ath9k_hif_usb_alloc_reg_in_ur
+ 			goto err_skb;
+ 		}
+ 
+-		usb_fill_bulk_urb(urb, hif_dev->udev,
+-				  usb_rcvbulkpipe(hif_dev->udev,
++		usb_fill_int_urb(urb, hif_dev->udev,
++				  usb_rcvintpipe(hif_dev->udev,
+ 						  USB_REG_IN_PIPE),
+ 				  skb->data, MAX_REG_IN_BUF_SIZE,
+-				  ath9k_hif_usb_reg_in_cb, skb);
++				  ath9k_hif_usb_reg_in_cb, skb, 1);
+ 
+ 		/* Anchor URB */
+ 		usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
+@@ -1031,9 +1031,7 @@ static int ath9k_hif_usb_download_fw(str
+ 
+ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
+ {
+-	struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
+-	struct usb_endpoint_descriptor *endp;
+-	int ret, idx;
++	int ret;
+ 
+ 	ret = ath9k_hif_usb_download_fw(hif_dev);
+ 	if (ret) {
+@@ -1043,20 +1041,6 @@ static int ath9k_hif_usb_dev_init(struct
+ 		return ret;
+ 	}
+ 
+-	/* On downloading the firmware to the target, the USB descriptor of EP4
+-	 * is 'patched' to change the type of the endpoint to Bulk. This will
+-	 * bring down CPU usage during the scan period.
+-	 */
+-	for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
+-		endp = &alt->endpoint[idx].desc;
+-		if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+-				== USB_ENDPOINT_XFER_INT) {
+-			endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
+-			endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
+-			endp->bInterval = 0;
+-		}
+-	}
+-
+ 	/* Alloc URBs */
+ 	ret = ath9k_hif_usb_alloc_urbs(hif_dev);
+ 	if (ret) {
+@@ -1268,7 +1252,7 @@ static void ath9k_hif_usb_reboot(struct 
+ 	if (!buf)
+ 		return;
+ 
+-	ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
++	ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, USB_REG_OUT_PIPE),
+ 			   buf, 4, NULL, HZ);
+ 	if (ret)
+ 		dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n");
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+@@ -1203,16 +1203,13 @@ static int ath9k_htc_config(struct ieee8
+ 
+ 	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) {
+ 		struct ieee80211_channel *curchan = hw->conf.chandef.chan;
+-		enum nl80211_channel_type channel_type =
+-			cfg80211_get_chandef_type(&hw->conf.chandef);
+ 		int pos = curchan->hw_value;
+ 
+ 		ath_dbg(common, CONFIG, "Set channel: %d MHz\n",
+ 			curchan->center_freq);
+ 
+ 		ath9k_cmn_update_ichannel(&priv->ah->channels[pos],
+-					  hw->conf.chandef.chan,
+-					  channel_type);
++					  &hw->conf.chandef);
+ 
+ 		if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
+ 			ath_err(common, "Unable to set channel\n");
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+@@ -448,6 +448,7 @@ static void ath9k_htc_tx_process(struct 
+ 	struct ieee80211_conf *cur_conf = &priv->hw->conf;
+ 	bool txok;
+ 	int slot;
++	int hdrlen, padsize;
+ 
+ 	slot = strip_drv_header(priv, skb);
+ 	if (slot < 0) {
+@@ -504,6 +505,15 @@ send_mac80211:
+ 
+ 	ath9k_htc_tx_clear_slot(priv, slot);
+ 
++	/* Remove padding before handing frame back to mac80211 */
++	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
++
++	padsize = hdrlen & 3;
++	if (padsize && skb->len > hdrlen + padsize) {
++		memmove(skb->data + padsize, skb->data, hdrlen);
++		skb_pull(skb, padsize);
++	}
++
+ 	/* Send status to mac80211 */
+ 	ieee80211_tx_status(priv->hw, skb);
+ }
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -41,7 +41,7 @@ void ath_tx_complete_poll_work(struct wo
+ 				txq->axq_tx_inprogress = true;
+ 			}
+ 		}
+-		ath_txq_unlock_complete(sc, txq);
++		ath_txq_unlock(sc, txq);
+ 	}
+ 
+ 	if (needreset) {
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -583,9 +583,9 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a
+ 	rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate);
+ 	rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+ 
++	rs->rs_firstaggr = (ads.ds_rxstatus8 & AR_RxFirstAggr) ? 1 : 0;
+ 	rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+-	rs->rs_moreaggr =
+-		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
++	rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+ 	rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+ 
+ 	/* directly mapped flags for ieee80211_rx_status */
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -140,6 +140,7 @@ struct ath_rx_status {
+ 	int8_t rs_rssi_ext1;
+ 	int8_t rs_rssi_ext2;
+ 	u8 rs_isaggr;
++	u8 rs_firstaggr;
+ 	u8 rs_moreaggr;
+ 	u8 rs_num_delims;
+ 	u8 rs_flags;
+@@ -569,6 +570,7 @@ struct ar5416_desc {
+ #define AR_RxAggr           0x00020000
+ #define AR_PostDelimCRCErr  0x00040000
+ #define AR_RxStatusRsvd71   0x3ff80000
++#define AR_RxFirstAggr      0x20000000
+ #define AR_DecryptBusyErr   0x40000000
+ #define AR_KeyMiss          0x80000000
+ 
+--- a/drivers/net/wireless/ath/ath9k/rc.c
++++ b/drivers/net/wireless/ath/ath9k/rc.c
+@@ -1324,8 +1324,8 @@ static void ath_rate_update(void *priv, 
+ 		ath_rc_init(sc, priv_sta);
+ 
+ 		ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
+-			"Operating HT Bandwidth changed to: %d\n",
+-			cfg80211_get_chandef_type(&sc->hw->conf.chandef));
++			"Operating Bandwidth changed to: %d\n",
++			sc->hw->conf.chandef.width);
+ 	}
+ }
+ 
+--- a/drivers/net/wireless/ath/ath9k/reg.h
++++ b/drivers/net/wireless/ath/ath9k/reg.h
+@@ -893,9 +893,9 @@
+ 
+ #define AR_SREV_9485(_ah) \
+ 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
+-#define AR_SREV_9485_11(_ah) \
+-	(AR_SREV_9485(_ah) && \
+-	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
++#define AR_SREV_9485_11_OR_LATER(_ah) \
++	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485) && \
++	 ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11))
+ #define AR_SREV_9485_OR_LATER(_ah) \
+ 	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
+ 
diff --git a/package/kernel/mac80211/patches/301-pending_work-rt2x00.patch b/package/kernel/mac80211/patches/301-pending_work-rt2x00.patch
index b4c0225686957a2af715fb931430868d4ade368a..0d8039185caa92529df45b4e238648a6f0dccd68 100644
--- a/package/kernel/mac80211/patches/301-pending_work-rt2x00.patch
+++ b/package/kernel/mac80211/patches/301-pending_work-rt2x00.patch
@@ -2354,7 +2354,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  	case RF3290:
  	case RF5360:
  	case RF5370:
-@@ -3442,17 +4487,25 @@ static int rt2800_init_registers(struct
+@@ -3442,17 +4487,25 @@ static int rt2800_init_registers(struct 
  		return ret;
  
  	rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
@@ -2388,7 +2388,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  	rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg);
  
  	rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
-@@ -3528,7 +4581,8 @@ static int rt2800_init_registers(struct
+@@ -3528,7 +4581,8 @@ static int rt2800_init_registers(struct 
  		if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
  		    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
  		    rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
@@ -2398,7 +2398,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  			if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
  				rt2800_register_write(rt2x00dev, TX_SW_CFG2,
  						      0x0000002c);
-@@ -3559,6 +4613,23 @@ static int rt2800_init_registers(struct
+@@ -3559,6 +4613,23 @@ static int rt2800_init_registers(struct 
  	} else if (rt2x00_rt(rt2x00dev, RT3572)) {
  		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
  		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -2422,7 +2422,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  	} else if (rt2x00_rt(rt2x00dev, RT5390) ||
  		   rt2x00_rt(rt2x00dev, RT5392) ||
  		   rt2x00_rt(rt2x00dev, RT5592)) {
-@@ -3786,14 +4857,8 @@ static int rt2800_init_registers(struct
+@@ -3786,14 +4857,8 @@ static int rt2800_init_registers(struct 
  	/*
  	 * Clear all beacons
  	 */
@@ -2448,7 +2448,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
  		value |= 0x20;
  	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
-@@ -4332,6 +5397,22 @@ static void rt2800_init_bbp_3572(struct
+@@ -4332,6 +5397,22 @@ static void rt2800_init_bbp_3572(struct 
  	rt2800_disable_unused_dac_adc(rt2x00dev);
  }
  
@@ -2471,7 +2471,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
  {
  	int ant, div_mode;
-@@ -4402,7 +5483,7 @@ static void rt2800_init_bbp_53xx(struct
+@@ -4402,7 +5483,7 @@ static void rt2800_init_bbp_53xx(struct 
  
  	rt2800_disable_unused_dac_adc(rt2x00dev);
  
@@ -2480,7 +2480,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  	div_mode = rt2x00_get_field16(eeprom,
  				      EEPROM_NIC_CONF1_ANT_DIVERSITY);
  	ant = (div_mode == 3) ? 1 : 0;
-@@ -4488,7 +5569,7 @@ static void rt2800_init_bbp_5592(struct
+@@ -4488,7 +5569,7 @@ static void rt2800_init_bbp_5592(struct 
  
  	rt2800_bbp4_mac_if_ctrl(rt2x00dev);
  
@@ -3212,7 +3212,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  		queue->priv_size = sizeof(struct queue_entry_priv_mmio);
  		break;
  
-@@ -1205,7 +1214,7 @@ static void rt2800pci_queue_init(struct
+@@ -1205,7 +1214,7 @@ static void rt2800pci_queue_init(struct 
  		queue->limit = 64;
  		queue->data_size = AGGREGATION_SIZE;
  		queue->desc_size = TXD_DESC_SIZE;
@@ -3221,7 +3221,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  		queue->priv_size = sizeof(struct queue_entry_priv_mmio);
  		break;
  
-@@ -1213,7 +1222,7 @@ static void rt2800pci_queue_init(struct
+@@ -1213,7 +1222,7 @@ static void rt2800pci_queue_init(struct 
  		queue->limit = 8;
  		queue->data_size = 0; /* No DMA required for beacons */
  		queue->desc_size = TXD_DESC_SIZE;
@@ -3232,7 +3232,7 @@ Contains the following changes from wireless-testing/master-2013-08-26:
  
 --- a/drivers/net/wireless/rt2x00/rt2800usb.c
 +++ b/drivers/net/wireless/rt2x00/rt2800usb.c
-@@ -854,13 +854,7 @@ static void rt2800usb_queue_init(struct
+@@ -854,13 +854,7 @@ static void rt2800usb_queue_init(struct 
  	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
  	unsigned short txwi_size, rxwi_size;
  
diff --git a/package/kernel/mac80211/patches/310-ap_scan.patch b/package/kernel/mac80211/patches/310-ap_scan.patch
index d7479f296563f9ffdc6ad53013c2d7fdad0633ad..e81dfc98cac1a43dc06e94d2af89de51b7ff9dc0 100644
--- a/package/kernel/mac80211/patches/310-ap_scan.patch
+++ b/package/kernel/mac80211/patches/310-ap_scan.patch
@@ -1,6 +1,6 @@
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -2092,7 +2092,7 @@ static int ieee80211_scan(struct wiphy *
+@@ -2102,7 +2102,7 @@ static int ieee80211_scan(struct wiphy *
  		 * the  frames sent while scanning on other channel will be
  		 * lost)
  		 */
diff --git a/package/kernel/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch b/package/kernel/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch
index b2a70733073afd52218ed62a502cc418928f2080..8ca791fcfa998784224f274c6e99677f70ebe9ef 100644
--- a/package/kernel/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch
+++ b/package/kernel/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch
@@ -8,7 +8,7 @@
  #include <asm/unaligned.h>
  
  #include "hw.h"
-@@ -518,8 +519,16 @@ static int ath9k_hw_init_macaddr(struct 
+@@ -517,8 +518,16 @@ static int ath9k_hw_init_macaddr(struct 
  		common->macaddr[2 * i] = eeval >> 8;
  		common->macaddr[2 * i + 1] = eeval & 0xff;
  	}
diff --git a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
index f6182dd31bfbdc268965807dc420c3eb6a385615..e5da942d08fc7ed50d31e4a8c4d38c2f4c3e7e45 100644
--- a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
+++ b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -755,6 +755,7 @@ static const struct ieee80211_iface_limi
+@@ -779,6 +779,7 @@ static const struct ieee80211_iface_limi
  #endif
  				 BIT(NL80211_IFTYPE_AP) |
  				 BIT(NL80211_IFTYPE_P2P_GO) },
diff --git a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
index f3a76ecea4af1e3babb1fd01db559d83da89a996..e50429f733d7fb1d9e1287911f3cfbce9030915f 100644
--- a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
+++ b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1746,6 +1746,53 @@ void ath9k_deinit_debug(struct ath_softc
+@@ -1871,6 +1871,53 @@ void ath9k_deinit_debug(struct ath_softc
  	}
  }
  
@@ -54,7 +54,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
  	struct ath_common *common = ath9k_hw_common(ah);
-@@ -1763,6 +1810,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1888,6 +1935,8 @@ int ath9k_init_debug(struct ath_hw *ah)
  
  	ath9k_dfs_init_debug(sc);
  
diff --git a/package/kernel/mac80211/patches/501-ath9k-eeprom_endianess.patch b/package/kernel/mac80211/patches/501-ath9k-eeprom_endianess.patch
index b98e8f50f02352df0758974225829a82a9d8c755..5779444578b511572c85f17d1e7b97a19f3437fd 100644
--- a/package/kernel/mac80211/patches/501-ath9k-eeprom_endianess.patch
+++ b/package/kernel/mac80211/patches/501-ath9k-eeprom_endianess.patch
@@ -71,7 +71,7 @@
  
 --- a/drivers/net/wireless/ath/ath9k/hw.h
 +++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -739,6 +739,7 @@ enum ath_cal_list {
+@@ -747,6 +747,7 @@ enum ath_cal_list {
  #define AH_USE_EEPROM   0x1
  #define AH_UNPLUGGED    0x2 /* The card has been physically removed. */
  #define AH_FASTCC       0x4
@@ -81,7 +81,7 @@
  	struct ath_ops reg_ops;
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -613,6 +613,8 @@ static int ath9k_init_softc(u16 devid, s
+@@ -631,6 +631,8 @@ static int ath9k_init_softc(u16 devid, s
  		ah->is_clk_25mhz = pdata->is_clk_25mhz;
  		ah->get_mac_revision = pdata->get_mac_revision;
  		ah->external_reset = pdata->external_reset;
diff --git a/package/kernel/mac80211/patches/502-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/502-ath9k_ahb_init.patch
index 25df3f952f7b7a847aae089096f0219ceb9461f6..15a40b282cd5f5731cc25cc4d4ea544910385c43 100644
--- a/package/kernel/mac80211/patches/502-ath9k_ahb_init.patch
+++ b/package/kernel/mac80211/patches/502-ath9k_ahb_init.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -1012,23 +1012,23 @@ static int __init ath9k_init(void)
+@@ -1036,23 +1036,23 @@ static int __init ath9k_init(void)
  		goto err_out;
  	}
  
diff --git a/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch b/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
index 647bde2ca0e998e0c4b435f40381a596a79af1c5..55a44b185b5d0f8946b5f8ef49805f5dabce8266 100644
--- a/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
+++ b/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/hw.c
 +++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2010,8 +2010,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2017,8 +2017,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
  		REG_WRITE(ah, AR_OBS, 8);
  
  	if (ah->config.rx_intr_mitigation) {
diff --git a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
index 87aaf3061c1417ab6669aa6ba2bf08dd6d961c41..a0bea054a6c1f57775cc56b4a1c25070abd00a36 100644
--- a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
+++ b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -697,6 +697,7 @@ struct ath_softc {
+@@ -701,6 +701,7 @@ struct ath_softc {
  	struct ieee80211_hw *hw;
  	struct device *dev;
  
@@ -8,7 +8,7 @@
  	struct survey_info *cur_survey;
  	struct survey_info survey[ATH9K_NUM_CHANNELS];
  
-@@ -901,6 +902,7 @@ struct fft_sample_ht20 {
+@@ -905,6 +906,7 @@ struct fft_sample_ht20 {
  	u8 data[SPECTRAL_HT20_NUM_BINS];
  } __packed;
  
@@ -18,7 +18,7 @@
  
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1793,6 +1793,50 @@ static const struct file_operations fops
+@@ -1918,6 +1918,50 @@ static const struct file_operations fops
  	.owner = THIS_MODULE
  };
  
@@ -69,7 +69,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
  	struct ath_common *common = ath9k_hw_common(ah);
-@@ -1812,6 +1856,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1937,6 +1981,8 @@ int ath9k_init_debug(struct ath_hw *ah)
  
  	debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
  			    &fops_eeprom);
@@ -80,7 +80,7 @@
  	debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1150,7 +1150,7 @@ int ath9k_spectral_scan_config(struct ie
+@@ -1146,7 +1146,7 @@ int ath9k_spectral_scan_config(struct ie
  	return 0;
  }
  
@@ -89,19 +89,18 @@
  {
  	struct ath_softc *sc = hw->priv;
  	struct ath_hw *ah = sc->sc_ah;
-@@ -1206,9 +1206,11 @@ static int ath9k_config(struct ieee80211
+@@ -1200,8 +1200,10 @@ static int ath9k_config(struct ieee80211
+ 
+ 	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
  		struct ieee80211_channel *curchan = hw->conf.chandef.chan;
- 		enum nl80211_channel_type channel_type =
- 			cfg80211_get_chandef_type(&conf->chandef);
 +		struct ath9k_channel *hchan;
  		int pos = curchan->hw_value;
  		int old_pos = -1;
- 		unsigned long flags;
 +		u32 oldflags;
+ 		unsigned long flags;
  
  		if (ah->curchan)
- 			old_pos = ah->curchan - &ah->channels[0];
-@@ -1244,7 +1246,23 @@ static int ath9k_config(struct ieee80211
+@@ -1238,7 +1240,23 @@ static int ath9k_config(struct ieee80211
  			memset(&sc->survey[pos], 0, sizeof(struct survey_info));
  		}
  
diff --git a/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
index 120fc4c1fc77795534467c0fc51f53e2eb9b9e40..074c3d8ebb7459ddd5a6b2af2c707e5ca64c18e0 100644
--- a/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
+++ b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/hw.c
 +++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -729,6 +729,7 @@ int ath9k_hw_init(struct ath_hw *ah)
+@@ -728,6 +728,7 @@ int ath9k_hw_init(struct ath_hw *ah)
  	case AR9300_DEVID_AR9462:
  	case AR9485_DEVID_AR1111:
  	case AR9300_DEVID_AR9565:
@@ -20,7 +20,7 @@
  
 --- a/drivers/net/wireless/ath/ath9k/pci.c
 +++ b/drivers/net/wireless/ath/ath9k/pci.c
-@@ -139,6 +139,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_i
+@@ -270,6 +270,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_i
  	{ PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E  AR9462 */
  	{ PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E  AR1111/AR9485 */
  	{ PCI_VDEVICE(ATHEROS, 0x0036) }, /* PCI-E  AR9565 */
diff --git a/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch b/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch
index 56e956ae66a238f4f67b5b312e5b66aebbf01780..dc848774d445f505d3f61e3c2b30d74386355830 100644
--- a/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch
+++ b/package/kernel/mac80211/patches/520-mac80211_cur_txpower.patch
@@ -1,6 +1,6 @@
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -1617,6 +1617,7 @@ struct ieee80211_hw {
+@@ -1622,6 +1622,7 @@ struct ieee80211_hw {
  	u8 max_tx_aggregation_subframes;
  	u8 offchannel_tx_hw_queue;
  	u8 radiotap_mcs_details;
@@ -10,7 +10,7 @@
  	u8 uapsd_queues;
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -2273,7 +2273,9 @@ static int ieee80211_get_tx_power(struct
+@@ -2283,7 +2283,9 @@ static int ieee80211_get_tx_power(struct
  	struct ieee80211_local *local = wiphy_priv(wiphy);
  	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
  
diff --git a/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch b/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch
index 9167903f1c2166e565e3b5e254c215e94cfd61dd..2aaee2f3933dbe50d81c4b0061e00f6e589f8dc6 100644
--- a/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch
+++ b/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1269,6 +1269,8 @@ int ath9k_config(struct ieee80211_hw *hw
+@@ -1263,6 +1263,8 @@ int ath9k_config(struct ieee80211_hw *hw
  			return -EINVAL;
  		}
  
@@ -9,7 +9,7 @@
  		/*
  		 * The most recent snapshot of channel->noisefloor for the old
  		 * channel is only available after the hardware reset. Copy it to
-@@ -1305,6 +1307,7 @@ int ath9k_config(struct ieee80211_hw *hw
+@@ -1299,6 +1301,7 @@ int ath9k_config(struct ieee80211_hw *hw
  		sc->config.txpowlimit = 2 * conf->power_level;
  		ath9k_cmn_update_txpow(ah, sc->curtxpow,
  				       sc->config.txpowlimit, &sc->curtxpow);
diff --git a/package/kernel/mac80211/patches/522-ath9k_per_chain_signal_strength.patch b/package/kernel/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
index b6075a8144869097e4ca21aabd982791ad86ea32..53d2be260c8795111cf924ba7b03aca4680c76b3 100644
--- a/package/kernel/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
+++ b/package/kernel/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
@@ -13,21 +13,21 @@
 +	int8_t rs_rssi_ctl[3];
 +	int8_t rs_rssi_ext[3];
  	u8 rs_isaggr;
+ 	u8 rs_firstaggr;
  	u8 rs_moreaggr;
- 	u8 rs_num_delims;
 --- a/drivers/net/wireless/ath/ath9k/recv.c
 +++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -948,6 +948,7 @@ static int ath9k_rx_skb_preprocess(struc
- 	struct ath_hw *ah = sc->sc_ah;
- 	struct ath_common *common = ath9k_hw_common(ah);
- 	bool discard_current = sc->rx.discard_next;
+@@ -892,6 +892,7 @@ static void ath9k_process_rssi(struct at
+ 	struct ath_hw *ah = common->ah;
+ 	int last_rssi;
+ 	int rssi = rx_stats->rs_rssi;
 +	int i, j;
  
- 	sc->rx.discard_next = rx_stats->rs_more;
- 	if (discard_current)
-@@ -977,6 +978,21 @@ static int ath9k_rx_skb_preprocess(struc
- 	if (rx_stats->rs_moreaggr)
- 		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ 	/*
+ 	 * RSSI is not available for subframes in an A-MPDU.
+@@ -910,6 +911,20 @@ static void ath9k_process_rssi(struct at
+ 		return;
+ 	}
  
 +	for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
 +		s8 rssi;
@@ -37,17 +37,16 @@
 +
 +		rssi = rx_stats->rs_rssi_ctl[i];
 +		if (rssi != ATH9K_RSSI_BAD) {
-+		    rx_status->chains |= BIT(j);
-+		    rx_status->chain_signal[j] = ah->noise + rssi;
++		    rxs->chains |= BIT(j);
++		    rxs->chain_signal[j] = ah->noise + rssi;
 +		}
 +		j++;
 +	}
 +
-+
- 	sc->rx.discard_next = false;
- 	return 0;
- }
-@@ -1086,7 +1102,7 @@ static int ath_process_fft(struct ath_so
+ 	/*
+ 	 * Update Beacon RSSI, this is used by ANI.
+ 	 */
+@@ -1000,7 +1015,7 @@ static int ath_process_fft(struct ath_so
  	fft_sample.tlv.length = __cpu_to_be16(length);
  
  	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
@@ -132,7 +131,7 @@
  	 * hardware stores this as 8 bit signed value.
 --- a/drivers/net/wireless/ath/ath9k/antenna.c
 +++ b/drivers/net/wireless/ath/ath9k/antenna.c
-@@ -546,14 +546,14 @@ void ath_ant_comb_scan(struct ath_softc 
+@@ -744,14 +744,14 @@ void ath_ant_comb_scan(struct ath_softc 
  	struct ath_ant_comb *antcomb = &sc->ant_comb;
  	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
  	int curr_main_set;
@@ -141,7 +140,7 @@
 +	int main_rssi = rs->rs_rssi_ctl[0];
 +	int alt_rssi = rs->rs_rssi_ctl[1];
  	int rx_ant_conf,  main_ant_conf;
- 	bool short_scan = false;
+ 	bool short_scan = false, ret;
  
 -	rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
 +	rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
@@ -150,4 +149,4 @@
 +	main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
  			 ATH_ANT_RX_MASK;
  
- 	/* Record packet only when both main_rssi and  alt_rssi is positive */
+ 	if (alt_rssi >= antcomb->low_rssi_thresh) {
diff --git a/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch
index 1e53de4ba0ddcef22e8f2c7590a51a5b69e30762..0e2baf95d5b2c25d3d360ab441271c4dbac09148 100644
--- a/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/523-mac80211_configure_antenna_gain.patch
@@ -1,6 +1,6 @@
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -999,6 +999,7 @@ enum ieee80211_smps_mode {
+@@ -1002,6 +1002,7 @@ enum ieee80211_smps_mode {
   *
   * @power_level: requested transmit power (in dBm), backward compatibility
   *	value only that is set to the minimum of all interfaces
@@ -8,7 +8,7 @@
   *
   * @chandef: the channel definition to tune to
   * @radar_enabled: whether radar detection is enabled
-@@ -1020,6 +1021,7 @@ struct ieee80211_conf {
+@@ -1023,6 +1024,7 @@ struct ieee80211_conf {
  	u32 flags;
  	int power_level, dynamic_ps_timeout;
  	int max_sleep_period;
@@ -18,7 +18,7 @@
  	u8 ps_dtim_period;
 --- a/net/mac80211/ieee80211_i.h
 +++ b/net/mac80211/ieee80211_i.h
-@@ -1126,6 +1126,7 @@ struct ieee80211_local {
+@@ -1130,6 +1130,7 @@ struct ieee80211_local {
  	int dynamic_ps_forced_timeout;
  
  	int user_power_level; /* in dBm, for all interfaces */
@@ -28,9 +28,9 @@
  
 --- a/include/uapi/linux/nl80211.h
 +++ b/include/uapi/linux/nl80211.h
-@@ -1736,6 +1736,8 @@ enum nl80211_attrs {
- 
- 	NL80211_ATTR_PEER_AID,
+@@ -1766,6 +1766,8 @@ enum nl80211_attrs {
+ 	NL80211_ATTR_CSA_C_OFF_BEACON,
+ 	NL80211_ATTR_CSA_C_OFF_PRESP,
  
 +	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
 +
@@ -39,15 +39,15 @@
  	__NL80211_ATTR_AFTER_LAST,
 --- a/net/wireless/nl80211.c
 +++ b/net/wireless/nl80211.c
-@@ -349,6 +349,7 @@ static const struct nla_policy nl80211_p
- 	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
- 				  .len = IEEE80211_MAX_DATA_LEN },
- 	[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
+@@ -354,6 +354,7 @@ static const struct nla_policy nl80211_p
+ 	[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
+ 	[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
+ 	[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
 +	[NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
  };
  
  /* policy for the key attributes */
-@@ -1993,6 +1994,22 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -2000,6 +2001,22 @@ static int nl80211_set_wiphy(struct sk_b
  			goto bad_res;
  	}
  
@@ -72,7 +72,7 @@
  		u32 tx_ant, rx_ant;
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -2283,6 +2283,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2293,6 +2293,19 @@ static int ieee80211_get_tx_power(struct
  	return 0;
  }
  
@@ -92,7 +92,7 @@
  static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
  				  const u8 *addr)
  {
-@@ -3474,6 +3487,7 @@ struct cfg80211_ops mac80211_config_ops 
+@@ -3656,6 +3669,7 @@ struct cfg80211_ops mac80211_config_ops 
  	.set_wiphy_params = ieee80211_set_wiphy_params,
  	.set_tx_power = ieee80211_set_tx_power,
  	.get_tx_power = ieee80211_get_tx_power,
@@ -102,7 +102,7 @@
  	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
 --- a/include/net/cfg80211.h
 +++ b/include/net/cfg80211.h
-@@ -1970,6 +1970,7 @@ struct cfg80211_update_ft_ies_params {
+@@ -1994,6 +1994,7 @@ struct cfg80211_update_ft_ies_params {
   *	(as advertised by the nl80211 feature flag.)
   * @get_tx_power: store the current TX power into the dbm variable;
   *	return 0 if successful
@@ -110,7 +110,7 @@
   *
   * @set_wds_peer: set the WDS peer for a WDS interface
   *
-@@ -2189,6 +2190,7 @@ struct cfg80211_ops {
+@@ -2215,6 +2216,7 @@ struct cfg80211_ops {
  				enum nl80211_tx_power_setting type, int mbm);
  	int	(*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
  				int *dbm);
diff --git a/package/kernel/mac80211/patches/524-ath9k_use_configured_antenna_gain.patch b/package/kernel/mac80211/patches/524-ath9k_use_configured_antenna_gain.patch
index ea28fa4bb148cea155dcb247b6f5fad4246b8741..dd1fec7ee1be18b636e7336cd1b1fc1a60308477 100644
--- a/package/kernel/mac80211/patches/524-ath9k_use_configured_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/524-ath9k_use_configured_antenna_gain.patch
@@ -10,7 +10,7 @@
  
 --- a/drivers/net/wireless/ath/ath9k/hw.c
 +++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2848,7 +2848,7 @@ void ath9k_hw_apply_txpower(struct ath_h
+@@ -2856,7 +2856,7 @@ void ath9k_hw_apply_txpower(struct ath_h
  	channel = chan->chan;
  	chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
  	new_pwr = min_t(int, chan_pwr, reg->power_limit);
@@ -21,7 +21,7 @@
  	if (ant_gain > max_gain)
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1303,7 +1303,10 @@ int ath9k_config(struct ieee80211_hw *hw
+@@ -1297,7 +1297,10 @@ int ath9k_config(struct ieee80211_hw *hw
  	}
  
  	if (changed & IEEE80211_CONF_CHANGE_POWER) {
diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
index 0257756f4d9f5296368f4202ca0a71baf7589635..a7cded7025e53c7f57ac895b533edad155fe867e 100644
--- a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
+++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
@@ -10,7 +10,7 @@
  #else
  static inline void ath_init_leds(struct ath_softc *sc)
  {
-@@ -693,6 +696,13 @@ enum spectral_mode {
+@@ -697,6 +700,13 @@ enum spectral_mode {
  	SPECTRAL_CHANSCAN,
  };
  
@@ -24,7 +24,7 @@
  struct ath_softc {
  	struct ieee80211_hw *hw;
  	struct device *dev;
-@@ -735,9 +745,8 @@ struct ath_softc {
+@@ -739,9 +749,8 @@ struct ath_softc {
  	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
  
  #ifdef CPTCFG_MAC80211_LEDS
@@ -162,7 +162,7 @@
  void ath_fill_led_pin(struct ath_softc *sc)
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -919,7 +919,7 @@ int ath9k_init_device(u16 devid, struct 
+@@ -943,7 +943,7 @@ int ath9k_init_device(u16 devid, struct 
  
  #ifdef CPTCFG_MAC80211_LEDS
  	/* must be initialized before ieee80211_register_hw */
@@ -173,7 +173,7 @@
  #endif
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1836,6 +1836,61 @@ static const struct file_operations fops
+@@ -1961,6 +1961,61 @@ static const struct file_operations fops
  	.llseek = default_llseek,
  };
  
@@ -235,7 +235,7 @@
  
  int ath9k_init_debug(struct ath_hw *ah)
  {
-@@ -1858,6 +1913,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1983,6 +2038,10 @@ int ath9k_init_debug(struct ath_hw *ah)
  			    &fops_eeprom);
  	debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
  			    sc, &fops_chanbw);
diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
index b069cb2cdbbc8cb3683d8e176dcd5fe45532e0f7..3409b69b95e75c3eb0685092bba30d86615aaf8e 100644
--- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
+++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1892,6 +1892,50 @@ static const struct file_operations fops
+@@ -2017,6 +2017,50 @@ static const struct file_operations fops
  #endif
  
  
@@ -51,7 +51,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
  	struct ath_common *common = ath9k_hw_common(ah);
-@@ -1917,6 +1961,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -2042,6 +2086,8 @@ int ath9k_init_debug(struct ath_hw *ah)
  	debugfs_create_file("gpio_led", S_IWUSR,
  			   sc->debug.debugfs_phy, sc, &fops_gpio_led);
  #endif
@@ -62,7 +62,7 @@
  	debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
 --- a/drivers/net/wireless/ath/ath9k/hw.h
 +++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -500,6 +500,12 @@ enum {
+@@ -505,6 +505,12 @@ enum {
  	ATH9K_RESET_COLD,
  };
  
@@ -75,7 +75,7 @@
  struct ath9k_hw_version {
  	u32 magic;
  	u16 devid;
-@@ -778,6 +784,8 @@ struct ath_hw {
+@@ -785,6 +791,8 @@ struct ath_hw {
  	u32 rfkill_polarity;
  	u32 ah_flags;
  
@@ -84,7 +84,7 @@
  	bool reset_power_on;
  	bool htc_reset_init;
  
-@@ -1028,6 +1036,7 @@ void ath9k_hw_set_sta_beacon_timers(stru
+@@ -1035,6 +1043,7 @@ void ath9k_hw_set_sta_beacon_timers(stru
  bool ath9k_hw_check_alive(struct ath_hw *ah);
  
  bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
@@ -94,7 +94,7 @@
  void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause);
 --- a/drivers/net/wireless/ath/ath9k/hw.c
 +++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1854,6 +1854,20 @@ fail:
+@@ -1861,6 +1861,20 @@ fail:
  	return -EINVAL;
  }
  
@@ -115,17 +115,17 @@
  int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
  		   struct ath9k_hw_cal_data *caldata, bool fastcc)
  {
-@@ -2056,6 +2070,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2063,6 +2077,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
  	}
  
  	ath9k_hw_apply_gpio_override(ah);
 +	ath9k_hw_update_diag(ah);
  
- 	if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv)
+ 	if (AR_SREV_9565(ah) && common->bt_ant_diversity)
  		REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -462,6 +462,11 @@ irqreturn_t ath_isr(int irq, void *dev)
+@@ -458,6 +458,11 @@ irqreturn_t ath_isr(int irq, void *dev)
  	ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */
  	status &= ah->imask;	/* discard unasked-for bits */
  
diff --git a/package/kernel/mac80211/patches/543-ath9k-allow-to-disable-bands-via-platform-data.patch b/package/kernel/mac80211/patches/543-ath9k-allow-to-disable-bands-via-platform-data.patch
index c5b90af68c306c9777aceac71eed32f77314893a..e59627c3d8544e253009e3d49be86f0c626d2490 100644
--- a/package/kernel/mac80211/patches/543-ath9k-allow-to-disable-bands-via-platform-data.patch
+++ b/package/kernel/mac80211/patches/543-ath9k-allow-to-disable-bands-via-platform-data.patch
@@ -12,7 +12,7 @@
  
 --- a/drivers/net/wireless/ath/ath9k/hw.c
 +++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2449,17 +2449,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw
+@@ -2456,17 +2456,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw
  	}
  
  	eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
@@ -48,7 +48,7 @@
  	    AR_SREV_9285(ah) ||
 --- a/drivers/net/wireless/ath/ath9k/hw.h
 +++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -948,6 +948,8 @@ struct ath_hw {
+@@ -955,6 +955,8 @@ struct ath_hw {
  	bool is_clk_25mhz;
  	int (*get_mac_revision)(void);
  	int (*external_reset)(void);
@@ -59,7 +59,7 @@
  };
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -613,6 +613,8 @@ static int ath9k_init_softc(u16 devid, s
+@@ -631,6 +631,8 @@ static int ath9k_init_softc(u16 devid, s
  		ah->is_clk_25mhz = pdata->is_clk_25mhz;
  		ah->get_mac_revision = pdata->get_mac_revision;
  		ah->external_reset = pdata->external_reset;
diff --git a/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
index b86724153aec58bd30dc12a9cc287beec5e54c74..be95fae8a027bbe4bb02b4041135c5d3e98e0e21 100644
--- a/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
+++ b/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
@@ -186,7 +186,7 @@
  obj-$(CPTCFG_RT2X00_LIB_MMIO)		+= rt2x00mmio.o
 --- a/drivers/net/wireless/rt2x00/rt2800pci.c
 +++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -90,25 +90,11 @@ static void rt2800pci_mcu_status(struct
+@@ -90,25 +90,11 @@ static void rt2800pci_mcu_status(struct 
  	rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
  }
  
diff --git a/package/kernel/mac80211/patches/605-rt2x00-pci-eeprom.patch b/package/kernel/mac80211/patches/605-rt2x00-pci-eeprom.patch
index 5e187c7e77588b6707df96500056add59402a481..325dba97c684c220421a7ab83254ffe619430ca9 100644
--- a/package/kernel/mac80211/patches/605-rt2x00-pci-eeprom.patch
+++ b/package/kernel/mac80211/patches/605-rt2x00-pci-eeprom.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/rt2x00/rt2800pci.c
 +++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -90,7 +90,7 @@ static void rt2800pci_mcu_status(struct
+@@ -90,7 +90,7 @@ static void rt2800pci_mcu_status(struct 
  	rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
  }
  
@@ -9,7 +9,7 @@
  {
  	memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
  	return 0;
-@@ -1097,8 +1097,9 @@ static int rt2800pci_read_eeprom(struct
+@@ -1097,8 +1097,9 @@ static int rt2800pci_read_eeprom(struct 
  {
  	int retval;
  
diff --git a/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch b/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch
index 122cd11932361a6d739d16cdd037381c87f95801..e2cd4d019816d144823eb73831e7f46a992bc6bd 100644
--- a/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch
+++ b/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch
@@ -33,7 +33,7 @@
  		rt2800_bbp_write(rt2x00dev, 86, 0);
  	}
  
-@@ -6086,6 +6086,12 @@ static void rt2800_init_rfcsr_3290(struc
+@@ -6093,6 +6093,12 @@ static void rt2800_init_rfcsr_3290(struc
  
  static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
  {
@@ -46,7 +46,7 @@
  	rt2800_rf_init_calibration(rt2x00dev, 30);
  
  	rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
-@@ -6121,15 +6127,30 @@ static void rt2800_init_rfcsr_3352(struc
+@@ -6128,15 +6134,30 @@ static void rt2800_init_rfcsr_3352(struc
  	rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
  	rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
  	rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
@@ -80,7 +80,7 @@
  	rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
  	rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
  	rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-@@ -6137,15 +6158,20 @@ static void rt2800_init_rfcsr_3352(struc
+@@ -6144,15 +6165,20 @@ static void rt2800_init_rfcsr_3352(struc
  	rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
  	rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
  	rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
@@ -110,7 +110,7 @@
  	rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
  	rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
  	rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-@@ -6996,6 +7022,7 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7003,6 +7029,7 @@ static int rt2800_init_eeprom(struct rt2
  	 * RT53xx: defined in "EEPROM_CHIP_ID" field
  	 */
  	if (rt2x00_rt(rt2x00dev, RT3290) ||
@@ -118,7 +118,7 @@
  	    rt2x00_rt(rt2x00dev, RT5390) ||
  	    rt2x00_rt(rt2x00dev, RT5392))
  		rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
-@@ -7086,7 +7113,8 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7093,7 +7120,8 @@ static int rt2800_init_eeprom(struct rt2
  	/*
  	 * Detect if this device has Bluetooth co-existence.
  	 */
@@ -128,7 +128,7 @@
  		__set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
  
  	/*
-@@ -7115,6 +7143,22 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7122,6 +7150,22 @@ static int rt2800_init_eeprom(struct rt2
  					EIRP_MAX_TX_POWER_LIMIT)
  		__set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
  
diff --git a/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch b/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch
index d3a7c96d8ecce9d41c5030b155d5331f5a250ffa..4fc1e0a01b15ce46d9166a7f83e7ba1de1fd312a 100644
--- a/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch
+++ b/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/rt2x00/rt2800lib.c
 +++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -7501,6 +7501,27 @@ static const struct rf_channel rf_vals_3
+@@ -7508,6 +7508,27 @@ static const struct rf_channel rf_vals_3
  	{173, 0x61, 0, 9},
  };
  
@@ -28,7 +28,7 @@
  static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
  {
  	struct hw_mode_spec *spec = &rt2x00dev->spec;
-@@ -7581,7 +7602,6 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7588,7 +7609,6 @@ static int rt2800_probe_hw_mode(struct r
  		   rt2x00_rf(rt2x00dev, RF3022) ||
  		   rt2x00_rf(rt2x00dev, RF3290) ||
  		   rt2x00_rf(rt2x00dev, RF3320) ||
@@ -36,7 +36,7 @@
  		   rt2x00_rf(rt2x00dev, RF5360) ||
  		   rt2x00_rf(rt2x00dev, RF5370) ||
  		   rt2x00_rf(rt2x00dev, RF5372) ||
-@@ -7589,6 +7609,12 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7596,6 +7616,12 @@ static int rt2800_probe_hw_mode(struct r
  		   rt2x00_rf(rt2x00dev, RF5392)) {
  		spec->num_channels = 14;
  		spec->channels = rf_vals_3x;
@@ -49,7 +49,7 @@
  	} else if (rt2x00_rf(rt2x00dev, RF3052)) {
  		spec->supported_bands |= SUPPORT_BAND_5GHZ;
  		spec->num_channels = ARRAY_SIZE(rf_vals_3x);
-@@ -7761,6 +7787,19 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -7768,6 +7794,19 @@ static int rt2800_probe_rt(struct rt2x00
  	return 0;
  }
  
@@ -69,7 +69,7 @@
  int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
  {
  	int retval;
-@@ -7790,6 +7829,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -7797,6 +7836,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
  	rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
  
  	/*
diff --git a/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch b/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch
index 48093516d5ebd02b0138db9e074c4e42b9bb9e23..1110394e8cca7fbbcb87deeaccb9bdb8b7dd7133 100644
--- a/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch
+++ b/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch
@@ -8,7 +8,7 @@
  
  #include "rt2x00.h"
  #include "rt2800lib.h"
-@@ -7789,13 +7790,14 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -7796,13 +7797,14 @@ static int rt2800_probe_rt(struct rt2x00
  
  int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev)
  {
diff --git a/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch b/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch
index 0ee98df5dbb541113587cef48f974dedb42f6abb..223d46a8e341434e5acbd1664a55b0294c4b9de0 100644
--- a/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch
+++ b/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch
@@ -52,7 +52,7 @@
  		rt2800_bbp_read(rt2x00dev, 49, &bbp);
  		rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0);
  		rt2800_bbp_write(rt2x00dev, 49, bbp);
-@@ -4259,6 +4271,7 @@ void rt2800_vco_calibration(struct rt2x0
+@@ -4266,6 +4278,7 @@ void rt2800_vco_calibration(struct rt2x0
  		break;
  	case RF3053:
  	case RF3290:
@@ -60,7 +60,7 @@
  	case RF5360:
  	case RF5370:
  	case RF5372:
-@@ -4630,6 +4643,8 @@ static int rt2800_init_registers(struct
+@@ -4637,6 +4650,8 @@ static int rt2800_init_registers(struct 
  		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
  		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
  		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -69,7 +69,7 @@
  	} else {
  		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
  		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-@@ -5271,9 +5286,13 @@ static void rt2800_init_bbp_3352(struct
+@@ -5278,9 +5293,13 @@ static void rt2800_init_bbp_3352(struct 
  
  	rt2800_bbp_write(rt2x00dev, 82, 0x62);
  
@@ -86,7 +86,7 @@
  
  	rt2800_bbp_write(rt2x00dev, 86, 0x38);
  
-@@ -5287,9 +5306,13 @@ static void rt2800_init_bbp_3352(struct
+@@ -5294,9 +5313,13 @@ static void rt2800_init_bbp_3352(struct 
  
  	rt2800_bbp_write(rt2x00dev, 104, 0x92);
  
@@ -103,7 +103,7 @@
  
  	rt2800_bbp_write(rt2x00dev, 120, 0x50);
  
-@@ -5314,6 +5337,13 @@ static void rt2800_init_bbp_3352(struct
+@@ -5321,6 +5344,13 @@ static void rt2800_init_bbp_3352(struct 
  	rt2800_bbp_write(rt2x00dev, 143, 0xa2);
  
  	rt2800_bbp_write(rt2x00dev, 148, 0xc8);
@@ -117,7 +117,7 @@
  }
  
  static void rt2800_init_bbp_3390(struct rt2x00_dev *rt2x00dev)
-@@ -5614,6 +5644,7 @@ static void rt2800_init_bbp(struct rt2x0
+@@ -5621,6 +5651,7 @@ static void rt2800_init_bbp(struct rt2x0
  		rt2800_init_bbp_3290(rt2x00dev);
  		break;
  	case RT3352:
@@ -125,7 +125,7 @@
  		rt2800_init_bbp_3352(rt2x00dev);
  		break;
  	case RT3390:
-@@ -6424,6 +6455,76 @@ static void rt2800_init_rfcsr_3593(struc
+@@ -6431,6 +6462,76 @@ static void rt2800_init_rfcsr_3593(struc
  	/* TODO: enable stream mode support */
  }
  
@@ -202,7 +202,7 @@
  static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
  {
  	rt2800_rf_init_calibration(rt2x00dev, 2);
-@@ -6655,6 +6756,9 @@ static void rt2800_init_rfcsr(struct rt2
+@@ -6662,6 +6763,9 @@ static void rt2800_init_rfcsr(struct rt2
  	case RT3593:
  		rt2800_init_rfcsr_3593(rt2x00dev);
  		break;
@@ -212,7 +212,7 @@
  	case RT5390:
  		rt2800_init_rfcsr_5390(rt2x00dev);
  		break;
-@@ -6894,6 +6998,12 @@ static int rt2800_validate_eeprom(struct
+@@ -6901,6 +7005,12 @@ static int rt2800_validate_eeprom(struct
  		rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
  		rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
  		rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
@@ -225,7 +225,7 @@
  	} else if (rt2x00_rt(rt2x00dev, RT2860) ||
  		   rt2x00_rt(rt2x00dev, RT2872)) {
  		/*
-@@ -7027,6 +7137,8 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7034,6 +7144,8 @@ static int rt2800_init_eeprom(struct rt2
  	    rt2x00_rt(rt2x00dev, RT5390) ||
  	    rt2x00_rt(rt2x00dev, RT5392))
  		rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
@@ -234,7 +234,7 @@
  	else
  		rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
  
-@@ -7044,6 +7156,7 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7051,6 +7163,7 @@ static int rt2800_init_eeprom(struct rt2
  	case RF3290:
  	case RF3320:
  	case RF3322:
@@ -242,7 +242,7 @@
  	case RF5360:
  	case RF5370:
  	case RF5372:
-@@ -7610,7 +7723,8 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7617,7 +7730,8 @@ static int rt2800_probe_hw_mode(struct r
  		   rt2x00_rf(rt2x00dev, RF5392)) {
  		spec->num_channels = 14;
  		spec->channels = rf_vals_3x;
@@ -252,7 +252,7 @@
  		spec->num_channels = 14;
  		if (spec->clk_is_20mhz)
  			spec->channels = rf_vals_xtal20mhz_3x;
-@@ -7735,6 +7849,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7742,6 +7856,7 @@ static int rt2800_probe_hw_mode(struct r
  	case RF3052:
  	case RF3053:
  	case RF3290:
@@ -260,7 +260,7 @@
  	case RF5360:
  	case RF5370:
  	case RF5372:
-@@ -7773,6 +7888,7 @@ static int rt2800_probe_rt(struct rt2x00
+@@ -7780,6 +7895,7 @@ static int rt2800_probe_rt(struct rt2x00
  	case RT3390:
  	case RT3572:
  	case RT3593:
diff --git a/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch b/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch
index 0787cc352f696edda3bba511712df53ea6a47c66..05d5f119a8072158669524a7fdbf403efae09fd9 100644
--- a/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch
+++ b/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch
@@ -8,7 +8,7 @@
  
  #include "rt2x00.h"
  #include "rt2800lib.h"
-@@ -7245,6 +7246,17 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7252,6 +7253,17 @@ static int rt2800_init_eeprom(struct rt2
  	rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
  	rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);