PKG_NAME:=mac80211
-PKG_VERSION:=2012-09-07
-PKG_RELEASE:=3
+PKG_VERSION:=2012-12-06
+PKG_RELEASE:=1
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
-PKG_MD5SUM:=59e0a114ee4b755a6e47cb6cd0f32ebc
+PKG_MD5SUM:=1b2cf615a72ea5f4839796afe43c47b7
PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
--- a/config.mk
+++ b/config.mk
-@@ -353,7 +353,8 @@ export CONFIG_IPW2200_QOS=y
+@@ -354,7 +354,8 @@ export CONFIG_IPW2200_QOS=y
# % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
endif #CONFIG_WIRELESS_EXT
# Sonics Silicon Backplane
export CONFIG_SSB_SPROM=y
-@@ -366,7 +367,7 @@ endif #CONFIG_PCMCIA
+@@ -367,7 +368,7 @@ endif #CONFIG_PCMCIA
# export CONFIG_SSB_DEBUG=y
export CONFIG_SSB_DRIVER_PCICORE=y
export CONFIG_B43_SSB=y
-endif #CONFIG_SSB
+endif #__CONFIG_SSB
- export CONFIG_BCMA=m
- export CONFIG_BCMA_BLOCKIO=y
-
+ # export CONFIG_BCMA=m
+ # export CONFIG_BCMA_BLOCKIO=y
+++ /dev/null
---- a/include/linux/compat-3.5.h
-+++ b/include/linux/compat-3.5.h
-@@ -8,6 +8,8 @@
-
- #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0))
-
-+#ifndef TCA_CODEL_MAX
-+
- /*
- * This backports:
- *
-@@ -135,6 +137,7 @@ static inline int compat_vga_switcheroo_
-
- #define SIZE_MAX (~(size_t)0)
-
-+#endif /* TCA_CODEL_MAX */
-
- #include <linux/pkt_sched.h>
-
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
-@@ -813,7 +813,6 @@ static void table_flush_by_iface(struct
+@@ -813,7 +813,6 @@ static void table_flush_by_iface(struct
struct hlist_node *p;
int i;
---- a/drivers/net/wireless/ath/ath5k/base.c
-+++ b/drivers/net/wireless/ath/ath5k/base.c
-@@ -325,6 +325,8 @@ ath5k_setup_channels(struct ath5k_hw *ah
- if (!ath5k_is_standard_channel(ch, band))
- continue;
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -5090,7 +5090,8 @@ static int rt2800_probe_hw_mode(struct r
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_AMPDU_AGGREGATION |
+- IEEE80211_HW_REPORTS_TX_ACK_STATUS;
++ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
++ IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL;
-+ channels[count].max_power = AR5K_TUNE_MAX_TXPOWER/2;
-+
- count++;
+ /*
+ * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -392,10 +392,9 @@ void rt2x00lib_txdone(struct queue_entry
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+ tx_info->status.ampdu_len = 1;
+ tx_info->status.ampdu_ack_len = success ? 1 : 0;
+- /*
+- * TODO: Need to tear down BA session here
+- * if not successful.
+- */
++
++ if (!success)
++ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
}
+ if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1369,6 +1369,10 @@ struct ieee80211_tx_control {
+ * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any
+ * P2P Interface. This will be honoured even if more than one interface
+ * is supported.
++ *
++ * @IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL: On this hardware TX BA session
++ * should be tear down once BAR frame will not be acked.
++ *
+ */
+ enum ieee80211_hw_flags {
+ IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
+@@ -1397,6 +1401,7 @@ enum ieee80211_hw_flags {
+ IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
+ IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24,
+ IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25,
++ IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL = 1<<26,
+ };
+
+ /**
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -203,6 +203,8 @@ static void ieee80211_send_addba_resp(st
sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -EINVAL;
-@@ -869,7 +871,7 @@ void ieee80211_process_addba_resp(struct
-
- } else {
- ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
-- true);
-+ false);
- }
-
- out:
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
-@@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
+@@ -65,11 +65,11 @@ static ssize_t sta_flags_read(struct fil
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
int res = scnprintf(buf, sizeof(buf),
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -201,6 +201,20 @@ static void __ieee80211_sta_join_ibss(st
+ bss_change |= BSS_CHANGED_BASIC_RATES;
+ bss_change |= BSS_CHANGED_HT;
+ bss_change |= BSS_CHANGED_IBSS;
++
++ /*
++ * In 5 GHz/802.11a, we can always use short slot time.
++ * (IEEE 802.11-2012 18.3.8.7)
++ *
++ * In 2.4GHz, we must always use long slots in IBSS for compatibility
++ * reasons.
++ * (IEEE 802.11-2012 19.4.5)
++ *
++ * HT follows these specifications (IEEE 802.11-2012 20.3.18)
++ */
++ sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ;
++ bss_change |= BSS_CHANGED_ERP_SLOT;
++
+ sdata->vif.bss_conf.ibss_joined = true;
+ sdata->vif.bss_conf.ibss_creator = creator;
+ ieee80211_bss_info_change_notify(sdata, bss_change);
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -420,7 +420,6 @@ int ieee80211_do_open(struct wireless_de
+@@ -510,7 +510,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;
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
-@@ -575,30 +574,8 @@ int ieee80211_do_open(struct wireless_de
+@@ -665,30 +664,8 @@ int ieee80211_do_open(struct wireless_de
set_bit(SDATA_STATE_RUNNING, &sdata->state);
/*
* set_multicast_list will be invoked by the networking core
-@@ -849,7 +826,7 @@ static void ieee80211_do_stop(struct iee
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- if (info->control.vif == &sdata->vif) {
- __skb_unlink(skb, &local->pending[i]);
-- dev_kfree_skb_irq(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- }
- }
- }
-@@ -997,6 +974,72 @@ static void ieee80211_if_setup(struct ne
+@@ -1072,6 +1049,72 @@ static void ieee80211_if_setup(struct ne
dev->destructor = free_netdev;
}
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
-@@ -1101,6 +1144,9 @@ static void ieee80211_iface_work(struct
+@@ -1176,6 +1219,9 @@ static void ieee80211_iface_work(struct
break;
ieee80211_mesh_rx_queued_mgmt(sdata, skb);
break;
break;
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2279,6 +2279,7 @@ ieee80211_rx_h_action(struct ieee80211_r
+@@ -378,9 +378,6 @@ ieee80211_rx_monitor(struct ieee80211_lo
+ * the SKB because it has a bad FCS/PLCP checksum.
+ */
+
+- /* room for the radiotap header based on driver features */
+- needed_headroom = ieee80211_rx_radiotap_space(local, status);
+-
+ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+ present_fcs_len = FCS_LEN;
+
+@@ -399,6 +396,9 @@ ieee80211_rx_monitor(struct ieee80211_lo
+ return remove_monitor_info(local, origskb);
+ }
+
++ /* room for the radiotap header based on driver features */
++ needed_headroom = ieee80211_rx_radiotap_space(local, status);
++
+ if (should_drop_frame(origskb, present_fcs_len)) {
+ /* only need to expand headroom if necessary */
+ skb = origskb;
+@@ -2333,7 +2333,8 @@ ieee80211_rx_h_action(struct ieee80211_r
+ if (len < IEEE80211_MIN_ACTION_SIZE)
+ return RX_DROP_UNUSABLE;
+
+- if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
++ if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
++ mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED)
+ return RX_DROP_UNUSABLE;
+
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+@@ -2349,6 +2350,7 @@ ieee80211_rx_h_action(struct ieee80211_r
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_ADHOC)
break;
-@@ -2496,14 +2497,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
+@@ -2625,14 +2627,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
break;
case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
-@@ -2827,10 +2829,16 @@ static int prepare_for_handlers(struct i
+@@ -2957,10 +2960,16 @@ static int prepare_for_handlers(struct i
}
break;
case NL80211_IFTYPE_WDS:
WLAN_STA_BLOCK_BA,
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
-@@ -34,7 +34,7 @@ void ieee80211_tx_status_irqsafe(struct
- skb_queue_len(&local->skb_queue_unreliable);
- while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
- (skb = skb_dequeue(&local->skb_queue_unreliable))) {
-- dev_kfree_skb_irq(skb);
-+ ieee80211_free_txskb(hw, skb);
- tmp--;
- I802_DEBUG_INC(local->tx_status_drop);
- }
-@@ -159,7 +159,7 @@ static void ieee80211_handle_filtered_fr
- "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
- skb_queue_len(&sta->tx_filtered[ac]),
- !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- }
-
- static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
-@@ -324,6 +324,75 @@ static void ieee80211_add_tx_radiotap_he
-
- }
-
-+static void ieee80211_report_used_skb(struct ieee80211_local *local,
-+ struct sk_buff *skb, bool dropped)
-+{
-+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+ struct ieee80211_hdr *hdr = (void *)skb->data;
-+ bool acked = info->flags & IEEE80211_TX_STAT_ACK;
-+
-+ if (dropped)
-+ acked = false;
-+
-+ if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
-+ struct ieee80211_sub_if_data *sdata = NULL;
-+ struct ieee80211_sub_if_data *iter_sdata;
-+ u64 cookie = (unsigned long)skb;
-+
-+ rcu_read_lock();
-+
-+ if (skb->dev) {
-+ list_for_each_entry_rcu(iter_sdata, &local->interfaces,
-+ list) {
-+ if (!iter_sdata->dev)
-+ continue;
-+
-+ if (skb->dev == iter_sdata->dev) {
-+ sdata = iter_sdata;
-+ break;
-+ }
-+ }
-+ } else {
-+ sdata = rcu_dereference(local->p2p_sdata);
-+ }
-+
-+ if (!sdata)
-+ skb->dev = NULL;
-+ else if (ieee80211_is_nullfunc(hdr->frame_control) ||
-+ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-+ cfg80211_probe_status(sdata->dev, hdr->addr1,
-+ cookie, acked, GFP_ATOMIC);
-+ } else {
-+ cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
-+ skb->len, acked, GFP_ATOMIC);
-+ }
-+
-+ rcu_read_unlock();
-+ }
-+
-+ if (unlikely(info->ack_frame_id)) {
-+ struct sk_buff *ack_skb;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&local->ack_status_lock, flags);
-+ ack_skb = idr_find(&local->ack_status_frames,
-+ info->ack_frame_id);
-+ if (ack_skb)
-+ idr_remove(&local->ack_status_frames,
-+ info->ack_frame_id);
-+ spin_unlock_irqrestore(&local->ack_status_lock, flags);
-+
-+ if (ack_skb) {
-+ if (!dropped) {
-+ /* consumes ack_skb */
-+ skb_complete_wifi_ack(ack_skb, acked);
-+ } else {
-+ dev_kfree_skb_any(ack_skb);
-+ }
-+ }
-+ }
-+}
-+
- /*
- * Use a static threshold for now, best value to be determined
- * by testing ...
-@@ -515,50 +584,7 @@ void ieee80211_tx_status(struct ieee8021
- msecs_to_jiffies(10));
- }
-
-- if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
-- u64 cookie = (unsigned long)skb;
-- acked = info->flags & IEEE80211_TX_STAT_ACK;
--
-- if (ieee80211_is_nullfunc(hdr->frame_control) ||
-- ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-- cfg80211_probe_status(skb->dev, hdr->addr1,
-- cookie, acked, GFP_ATOMIC);
-- } else if (skb->dev) {
-- cfg80211_mgmt_tx_status(
-- skb->dev->ieee80211_ptr, cookie, skb->data,
-- skb->len, acked, GFP_ATOMIC);
-- } else {
-- struct ieee80211_sub_if_data *p2p_sdata;
--
-- rcu_read_lock();
--
-- p2p_sdata = rcu_dereference(local->p2p_sdata);
-- if (p2p_sdata) {
-- cfg80211_mgmt_tx_status(
-- &p2p_sdata->wdev, cookie, skb->data,
-- skb->len, acked, GFP_ATOMIC);
-- }
-- rcu_read_unlock();
-- }
-- }
--
-- if (unlikely(info->ack_frame_id)) {
-- struct sk_buff *ack_skb;
-- unsigned long flags;
--
-- spin_lock_irqsave(&local->ack_status_lock, flags);
-- ack_skb = idr_find(&local->ack_status_frames,
-- info->ack_frame_id);
-- if (ack_skb)
-- idr_remove(&local->ack_status_frames,
-- info->ack_frame_id);
-- spin_unlock_irqrestore(&local->ack_status_lock, flags);
--
-- /* consumes ack_skb */
-- if (ack_skb)
-- skb_complete_wifi_ack(ack_skb,
-- info->flags & IEEE80211_TX_STAT_ACK);
-- }
-+ ieee80211_report_used_skb(local, skb, false);
-
- /* this was a transmitted frame, but now we want to reuse it */
- skb_orphan(skb);
-@@ -634,25 +660,17 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
- void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
- {
- struct ieee80211_local *local = hw_to_local(hw);
-- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
--
-- if (unlikely(info->ack_frame_id)) {
-- struct sk_buff *ack_skb;
-- unsigned long flags;
--
-- spin_lock_irqsave(&local->ack_status_lock, flags);
-- ack_skb = idr_find(&local->ack_status_frames,
-- info->ack_frame_id);
-- if (ack_skb)
-- idr_remove(&local->ack_status_frames,
-- info->ack_frame_id);
-- spin_unlock_irqrestore(&local->ack_status_lock, flags);
--
-- /* consumes ack_skb */
-- if (ack_skb)
-- dev_kfree_skb_any(ack_skb);
-- }
-
-+ ieee80211_report_used_skb(local, skb, true);
- dev_kfree_skb_any(skb);
- }
- EXPORT_SYMBOL(ieee80211_free_txskb);
-+
-+void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
-+ struct sk_buff_head *skbs)
-+{
-+ struct sk_buff *skb;
-+
-+ while ((skb = __skb_dequeue(skbs)))
-+ ieee80211_free_txskb(hw, skb);
-+}
---- a/drivers/net/wireless/p54/main.c
-+++ b/drivers/net/wireless/p54/main.c
-@@ -139,6 +139,7 @@ static int p54_beacon_format_ie_tim(stru
- static int p54_beacon_update(struct p54_common *priv,
- struct ieee80211_vif *vif)
- {
-+ struct ieee80211_tx_control control = { };
- struct sk_buff *beacon;
- int ret;
-
-@@ -158,7 +159,7 @@ static int p54_beacon_update(struct p54_
- * to cancel the old beacon template by hand, instead the firmware
- * will release the previous one through the feedback mechanism.
- */
-- p54_tx_80211(priv->hw, NULL, beacon);
-+ p54_tx_80211(priv->hw, &control, beacon);
- priv->tsf_high32 = 0;
- priv->tsf_low32 = 0;
-
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -352,6 +352,9 @@ static void reg_regdb_search(struct work
- struct reg_regdb_search_request *request;
- const struct ieee80211_regdomain *curdom, *regdom;
- int i, r;
-+ bool set_reg = false;
-+
-+ mutex_lock(&cfg80211_mutex);
-
- mutex_lock(®_regdb_search_mutex);
- while (!list_empty(®_regdb_search_list)) {
-@@ -367,9 +370,7 @@ static void reg_regdb_search(struct work
- r = reg_copy_regd(®dom, curdom);
- if (r)
- break;
-- mutex_lock(&cfg80211_mutex);
-- set_regdom(regdom);
-- mutex_unlock(&cfg80211_mutex);
-+ set_reg = true;
- break;
- }
- }
-@@ -377,6 +378,11 @@ static void reg_regdb_search(struct work
- kfree(request);
- }
- mutex_unlock(®_regdb_search_mutex);
-+
-+ if (set_reg)
-+ set_regdom(regdom);
-+
-+ mutex_unlock(&cfg80211_mutex);
- }
-
- static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -424,8 +424,8 @@ u32 ath_calcrxfilter(struct ath_softc *s
- rfilt |= ATH9K_RX_FILTER_COMP_BAR;
-
- if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
-- /* The following may also be needed for other older chips */
-- if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
-+ /* This is needed for older chips */
-+ if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
- rfilt |= ATH9K_RX_FILTER_PROM;
- rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
- }
---- a/net/mac80211/mlme.c
-+++ b/net/mac80211/mlme.c
-@@ -818,23 +818,71 @@ void ieee80211_sta_process_chanswitch(st
- }
-
- static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
-- u16 capab_info, u8 *pwr_constr_elem,
-- u8 pwr_constr_elem_len)
-+ struct ieee80211_channel *channel,
-+ const u8 *country_ie, u8 country_ie_len,
-+ const u8 *pwr_constr_elem)
- {
-- struct ieee80211_conf *conf = &sdata->local->hw.conf;
-+ struct ieee80211_country_ie_triplet *triplet;
-+ int chan = ieee80211_frequency_to_channel(channel->center_freq);
-+ int i, chan_pwr, chan_increment, new_ap_level;
-+ bool have_chan_pwr = false;
-
-- if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
-+ /* Invalid IE */
-+ if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
- return;
-
-- /* Power constraint IE length should be 1 octet */
-- if (pwr_constr_elem_len != 1)
-- return;
-+ triplet = (void *)(country_ie + 3);
-+ country_ie_len -= 3;
-
-- if ((*pwr_constr_elem <= conf->channel->max_reg_power) &&
-- (*pwr_constr_elem != sdata->local->power_constr_level)) {
-- sdata->local->power_constr_level = *pwr_constr_elem;
-- ieee80211_hw_config(sdata->local, 0);
-+ switch (channel->band) {
-+ default:
-+ WARN_ON_ONCE(1);
-+ /* fall through */
-+ case IEEE80211_BAND_2GHZ:
-+ case IEEE80211_BAND_60GHZ:
-+ chan_increment = 1;
-+ break;
-+ case IEEE80211_BAND_5GHZ:
-+ chan_increment = 4;
-+ break;
- }
-+
-+ /* find channel */
-+ while (country_ie_len >= 3) {
-+ u8 first_channel = triplet->chans.first_channel;
-+
-+ if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID)
-+ goto next;
-+
-+ for (i = 0; i < triplet->chans.num_channels; i++) {
-+ if (first_channel + i * chan_increment == chan) {
-+ have_chan_pwr = true;
-+ chan_pwr = triplet->chans.max_power;
-+ break;
-+ }
-+ }
-+ if (have_chan_pwr)
-+ break;
-+
-+ next:
-+ triplet++;
-+ country_ie_len -= 3;
-+ }
-+
-+ if (!have_chan_pwr)
-+ return;
-+
-+ new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
-+
-+ if (sdata->local->ap_power_level == new_ap_level)
-+ return;
-+
-+ sdata_info(sdata,
-+ "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
-+ new_ap_level, chan_pwr, *pwr_constr_elem,
-+ sdata->u.mgd.bssid);
-+ sdata->local->ap_power_level = new_ap_level;
-+ ieee80211_hw_config(sdata->local, 0);
- }
-
- void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
-@@ -1390,7 +1438,7 @@ static void ieee80211_set_disassoc(struc
- sta = sta_info_get(sdata, ifmgd->bssid);
- if (sta) {
- set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-- ieee80211_sta_tear_down_BA_sessions(sta, tx);
-+ ieee80211_sta_tear_down_BA_sessions(sta, false);
- }
- mutex_unlock(&local->sta_mtx);
-
-@@ -1438,7 +1486,7 @@ static void ieee80211_set_disassoc(struc
- memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
- memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
-
-- local->power_constr_level = 0;
-+ local->ap_power_level = 0;
-
- del_timer_sync(&local->dynamic_ps_timer);
- cancel_work_sync(&local->dynamic_ps_enable_work);
-@@ -2530,15 +2578,13 @@ static void ieee80211_rx_mgmt_beacon(str
- bssid, true);
- }
-
-- /* Note: country IE parsing is done for us by cfg80211 */
-- if (elems.country_elem) {
-- /* TODO: IBSS also needs this */
-- if (elems.pwr_constr_elem)
-- ieee80211_handle_pwr_constr(sdata,
-- le16_to_cpu(mgmt->u.probe_resp.capab_info),
-- elems.pwr_constr_elem,
-- elems.pwr_constr_elem_len);
-- }
-+ if (elems.country_elem && elems.pwr_constr_elem &&
-+ mgmt->u.probe_resp.capab_info &
-+ cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
-+ ieee80211_handle_pwr_constr(sdata, local->oper_channel,
-+ elems.country_elem,
-+ elems.country_elem_len,
-+ elems.pwr_constr_elem);
-
- ieee80211_bss_info_change_notify(sdata, changed);
- }
-@@ -3526,6 +3572,7 @@ int ieee80211_mgd_deauth(struct ieee8021
- {
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- u8 frame_buf[DEAUTH_DISASSOC_LEN];
-+ bool tx = !req->local_state_change;
-
- mutex_lock(&ifmgd->mtx);
-
-@@ -3542,12 +3589,12 @@ int ieee80211_mgd_deauth(struct ieee8021
- if (ifmgd->associated &&
- ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
- ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
-- req->reason_code, true, frame_buf);
-+ req->reason_code, tx, frame_buf);
- } else {
- drv_mgd_prepare_tx(sdata->local, sdata);
- ieee80211_send_deauth_disassoc(sdata, req->bssid,
- IEEE80211_STYPE_DEAUTH,
-- req->reason_code, true,
-+ req->reason_code, tx,
- frame_buf);
- }
-
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -585,7 +585,7 @@ static bool sta_info_cleanup_expire_buff
- */
- if (!skb)
- break;
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- }
-
- /*
-@@ -614,7 +614,7 @@ static bool sta_info_cleanup_expire_buff
- local->total_ps_buffered--;
- ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
- sta->sta.addr);
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- }
-
- /*
-@@ -674,7 +674,7 @@ int __must_check __sta_info_destroy(stru
- * will be sufficient.
- */
- set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-- ieee80211_sta_tear_down_BA_sessions(sta, true);
-+ ieee80211_sta_tear_down_BA_sessions(sta, false);
-
- ret = sta_info_hash_del(local, sta);
- if (ret)
-@@ -730,8 +730,8 @@ int __must_check __sta_info_destroy(stru
-
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
-- __skb_queue_purge(&sta->ps_tx_buf[ac]);
-- __skb_queue_purge(&sta->tx_filtered[ac]);
-+ ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
-+ ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
- }
-
- #ifdef CONFIG_MAC80211_MESH
-@@ -765,7 +765,7 @@ int __must_check __sta_info_destroy(stru
- tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
- if (!tid_tx)
- continue;
-- __skb_queue_purge(&tid_tx->pending);
-+ ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
- kfree(tid_tx);
- }
-
---- a/drivers/net/wireless/ath/ath5k/phy.c
-+++ b/drivers/net/wireless/ath/ath5k/phy.c
-@@ -1977,11 +1977,13 @@ ath5k_hw_set_spur_mitigation_filter(stru
- spur_delta_phase = (spur_offset << 18) / 25;
- spur_freq_sigma_delta = (spur_delta_phase >> 10);
- symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2;
-+ break;
- case AR5K_BWMODE_5MHZ:
- /* Both sample_freq and chip_freq are 10MHz (?) */
- spur_delta_phase = (spur_offset << 19) / 25;
- spur_freq_sigma_delta = (spur_delta_phase >> 10);
- symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
-+ break;
- default:
- if (channel->band == IEEE80211_BAND_5GHZ) {
- /* Both sample_freq and chip_freq are 40MHz */
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1062,7 +1062,7 @@ struct ieee80211_local {
- bool disable_dynamic_ps;
-
- int user_power_level; /* in dBm */
-- int power_constr_level; /* in dBm */
-+ int ap_power_level; /* in dBm */
-
- enum ieee80211_smps_mode smps_mode;
-
-@@ -1170,7 +1170,6 @@ struct ieee802_11_elems {
- u8 prep_len;
- u8 perr_len;
- u8 country_elem_len;
-- u8 pwr_constr_elem_len;
- u8 quiet_elem_len;
- u8 num_of_quiet_elem; /* can be more the one */
- u8 timeout_int_len;
-@@ -1318,6 +1317,8 @@ netdev_tx_t ieee80211_monitor_start_xmit
- struct net_device *dev);
- netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-+void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
-+ struct sk_buff_head *skbs);
-
- /* HT */
- void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ie
- int queue = info->hw_queue;
-
- if (WARN_ON(!info->control.vif)) {
-- kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- return;
- }
-
-@@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struc
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- if (WARN_ON(!info->control.vif)) {
-- kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- continue;
- }
-
-@@ -792,8 +792,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start
- elems->country_elem_len = elen;
- break;
- case WLAN_EID_PWR_CONSTRAINT:
-+ if (elen != 1) {
-+ elem_parse_failed = true;
-+ break;
-+ }
- elems->pwr_constr_elem = pos;
-- elems->pwr_constr_elem_len = elen;
- break;
- case WLAN_EID_TIMEOUT_INTERVAL:
- elems->timeout_int = pos;
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -154,13 +154,11 @@ int ieee80211_hw_config(struct ieee80211
-
- if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
- test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
-- test_bit(SCAN_HW_SCANNING, &local->scanning))
-+ test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-+ !local->ap_power_level)
- power = chan->max_power;
- else
-- power = local->power_constr_level ?
-- min(chan->max_power,
-- (chan->max_reg_power - local->power_constr_level)) :
-- chan->max_power;
-+ power = min(chan->max_power, local->ap_power_level);
-
- if (local->user_power_level >= 0)
- power = min(power, local->user_power_level);
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -1218,6 +1218,7 @@ struct cfg80211_deauth_request {
- const u8 *ie;
- size_t ie_len;
- u16 reason_code;
-+ bool local_state_change;
- };
-
- /**
---- a/net/wireless/mlme.c
-+++ b/net/wireless/mlme.c
-@@ -457,20 +457,14 @@ int __cfg80211_mlme_deauth(struct cfg802
- .reason_code = reason,
- .ie = ie,
- .ie_len = ie_len,
-+ .local_state_change = local_state_change,
- };
-
- ASSERT_WDEV_LOCK(wdev);
-
-- if (local_state_change) {
-- if (wdev->current_bss &&
-- ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
-- cfg80211_unhold_bss(wdev->current_bss);
-- cfg80211_put_bss(&wdev->current_bss->pub);
-- wdev->current_bss = NULL;
-- }
--
-+ if (local_state_change && (!wdev->current_bss ||
-+ !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
- return 0;
-- }
-
- return rdev->ops->deauth(&rdev->wiphy, dev, &req);
- }
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -386,7 +386,7 @@ static void ath_tx_complete_aggr(struct
- u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first;
- u32 ba[WME_BA_BMP_SIZE >> 5];
- int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
-- bool rc_update = true;
-+ bool rc_update = true, isba;
- struct ieee80211_tx_rate rates[4];
- struct ath_frame_info *fi;
- int nframes;
-@@ -430,13 +430,17 @@ static void ath_tx_complete_aggr(struct
- tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
- tid = ATH_AN_2_TID(an, tidno);
- seq_first = tid->seq_start;
-+ isba = ts->ts_flags & ATH9K_TX_BA;
-
- /*
- * The hardware occasionally sends a tx status for the wrong TID.
- * In this case, the BA status cannot be considered valid and all
- * subframes need to be retransmitted
-+ *
-+ * Only BlockAcks have a TID and therefore normal Acks cannot be
-+ * checked
- */
-- if (tidno != ts->tid)
-+ if (isba && tidno != ts->tid)
- txok = false;
-
- isaggr = bf_isaggr(bf);
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -2563,6 +2563,9 @@ static void ieee80211_mgmt_frame_registe
- else
- local->probe_req_reg--;
-
-+ if (!local->open_count)
-+ break;
-+
- ieee80211_queue_work(&local->hw, &local->reconfig_filter);
- break;
- default:
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -354,7 +354,7 @@ static void purge_old_ps_buffers(struct
- total += skb_queue_len(&sta->ps_tx_buf[ac]);
- if (skb) {
- purged++;
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- break;
+@@ -502,7 +502,11 @@ void ieee80211_tx_status(struct ieee8021
+ IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+ IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+
+- ieee80211_set_bar_pending(sta, tid, ssn);
++ if (local->hw.flags &
++ IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL)
++ ieee80211_stop_tx_ba_session(&sta->sta, tid);
++ else
++ ieee80211_set_bar_pending(sta, tid, ssn);
}
}
-@@ -466,7 +466,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
- ps_dbg(tx->sdata,
- "STA %pM TX buffer for AC %d full - dropping oldest frame\n",
- sta->sta.addr, ac);
-- dev_kfree_skb(old);
-+ ieee80211_free_txskb(&local->hw, old);
- } else
- tx->local->total_ps_buffered++;
-
-@@ -1103,7 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct
- spin_unlock(&tx->sta->lock);
-
- if (purge_skb)
-- dev_kfree_skb(purge_skb);
-+ ieee80211_free_txskb(&tx->local->hw, purge_skb);
- }
-
- /* reset session timer */
-@@ -1214,7 +1214,7 @@ static bool ieee80211_tx_frags(struct ie
- #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (WARN_ON_ONCE(q >= local->hw.queues)) {
- __skb_unlink(skb, skbs);
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- continue;
- }
- #endif
-@@ -1356,9 +1356,9 @@ static int invoke_tx_handlers(struct iee
- if (unlikely(res == TX_DROP)) {
- I802_DEBUG_INC(tx->local->tx_handlers_drop);
- if (tx->skb)
-- dev_kfree_skb(tx->skb);
-+ ieee80211_free_txskb(&tx->local->hw, tx->skb);
- else
-- __skb_queue_purge(&tx->skbs);
-+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
- return -1;
- } else if (unlikely(res == TX_QUEUED)) {
- I802_DEBUG_INC(tx->local->tx_handlers_queued);
-@@ -1393,7 +1393,7 @@ static bool ieee80211_tx(struct ieee8021
- res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
-
- if (unlikely(res_prepare == TX_DROP)) {
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- goto out;
- } else if (unlikely(res_prepare == TX_QUEUED)) {
- goto out;
-@@ -1465,7 +1465,7 @@ void ieee80211_xmit(struct ieee80211_sub
- headroom = max_t(int, 0, headroom);
-
- if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
-- dev_kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- rcu_read_unlock();
- return;
- }
-@@ -2056,8 +2056,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
- head_need += IEEE80211_ENCRYPT_HEADROOM;
- head_need += local->tx_headroom;
- head_need = max_t(int, 0, head_need);
-- if (ieee80211_skb_resize(sdata, skb, head_need, true))
-- goto fail;
-+ if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
-+ ieee80211_free_txskb(&local->hw, skb);
-+ return NETDEV_TX_OK;
-+ }
- }
-
- if (encaps_data) {
-@@ -2124,10 +2126,13 @@ netdev_tx_t ieee80211_subif_start_xmit(s
- */
- void ieee80211_clear_tx_pending(struct ieee80211_local *local)
- {
-+ struct sk_buff *skb;
- int i;
-
-- for (i = 0; i < local->hw.queues; i++)
-- skb_queue_purge(&local->pending[i]);
-+ for (i = 0; i < local->hw.queues; i++) {
-+ while ((skb = skb_dequeue(&local->pending[i])) != NULL)
-+ ieee80211_free_txskb(&local->hw, skb);
-+ }
- }
-
- /*
-@@ -2190,7 +2195,7 @@ void ieee80211_tx_pending(unsigned long
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- if (WARN_ON(!info->control.vif)) {
-- kfree_skb(skb);
-+ ieee80211_free_txskb(&local->hw, skb);
- continue;
- }
+--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+@@ -534,98 +534,98 @@ static const u32 ar9300_2p2_baseband_cor
+
+ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+- {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+- {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+- {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
++ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
++ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
++ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+- {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+- {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+- {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+- {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+- {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+- {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+- {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+- {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+- {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+- {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+- {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+- {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+- {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+- {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+- {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+- {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+- {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+- {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+- {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+- {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+- {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+- {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+- {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+- {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+- {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+- {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+- {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+- {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+- {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+- {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+- {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+- {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+- {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+- {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+- {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+- {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+- {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+- {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+- {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+- {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+- {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+- {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+- {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+- {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+- {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+- {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+- {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+- {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+- {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+- {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+- {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+- {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+- {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+- {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+- {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+- {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+- {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+- {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
++ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
++ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
++ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
++ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
++ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
++ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
++ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
++ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
++ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
++ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
++ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
++ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
++ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
++ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
++ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
++ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
++ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
++ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
++ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
++ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
++ {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
++ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
++ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
++ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
++ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
++ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
++ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
++ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
++ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
++ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
++ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
++ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
++ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
++ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
++ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
++ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
++ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
++ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
++ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
++ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
++ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
++ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
++ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
++ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
++ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
++ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
++ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
++ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
++ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
++ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
++ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
++ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+- {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+- {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+- {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+- {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+- {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+- {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+- {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+- {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+- {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+- {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+- {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+- {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+- {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+- {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+- {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
++ {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
++ {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
++ {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
++ {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
++ {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
++ {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
++ {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
++ {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
++ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
++ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+- {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+- {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+- {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
++ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
++ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
++ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -242,7 +242,7 @@ struct ath_rx_stats {
+
+ struct ath_stats {
+ struct ath_interrupt_stats istats;
+- struct ath_tx_stats txstats[IEEE80211_NUM_ACS];
++ struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
+ struct ath_rx_stats rxstats;
+ struct ath_dfs_stats dfs_stats;
+ u32 reset[__RESET_TYPE_MAX];
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1796,8 +1796,6 @@ static int ieee80211_scan(struct wiphy *
- * beaconing hasn't been configured yet
+@@ -1916,7 +1916,7 @@ static int ieee80211_scan(struct wiphy *
+ * the frames sent while scanning on other channel will be
+ * lost)
*/
- case NL80211_IFTYPE_AP:
-- if (sdata->u.ap.beacon)
-- return -EOPNOTSUPP;
- break;
- default:
- return -EOPNOTSUPP;
+- if (sdata->u.ap.beacon &&
++ if (0 && sdata->u.ap.beacon &&
+ (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
+ !(req->flags & NL80211_SCAN_FLAG_AP)))
+ return -EOPNOTSUPP;
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
-@@ -8,7 +8,7 @@ obj-$(CONFIG_ATH_COMMON) += ath.o
+@@ -9,7 +9,7 @@ obj-$(CONFIG_ATH_COMMON) += ath.o
ath-objs := main.o \
regd.o \
hw.o \
ccflags-y += -D__CHECK_ENDIAN__
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
-@@ -280,13 +280,6 @@ void _ath_dbg(struct ath_common *common,
+@@ -281,13 +281,6 @@ void _ath_dbg(struct ath_common *common,
#endif /* CONFIG_ATH_DEBUG */
/** Returns string describing opmode, or NULL if unknown mode. */
#include <asm/unaligned.h>
#include "hw.h"
-@@ -523,8 +524,16 @@ static int ath9k_hw_init_macaddr(struct
+@@ -524,8 +525,16 @@ static int ath9k_hw_init_macaddr(struct
common->macaddr[2 * i] = eeval >> 8;
common->macaddr[2 * i + 1] = eeval & 0xff;
}
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
-@@ -1796,6 +1796,8 @@ void regulatory_hint_11d(struct wiphy *w
+@@ -1805,6 +1805,8 @@ void regulatory_hint_11d(struct wiphy *w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request;
mutex_lock(®_mutex);
if (unlikely(!last_request))
-@@ -2030,6 +2032,8 @@ static void restore_regulatory_settings(
+@@ -2039,6 +2041,8 @@ static void restore_regulatory_settings(
void regulatory_hint_disconnect(void)
{
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -667,6 +667,7 @@ static const struct ieee80211_iface_limi
- #ifdef CONFIG_MAC80211_MESH
- BIT(NL80211_IFTYPE_MESH_POINT) |
+@@ -678,6 +678,7 @@ static const struct ieee80211_iface_limi
#endif
-+ BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
};
+
+ static const struct ieee80211_iface_combination if_comb = {
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-@@ -89,13 +89,8 @@ ath5k_add_interface(struct ieee80211_hw
+@@ -89,13 +89,8 @@ ath5k_add_interface(struct ieee80211_hw
goto end;
}
intval /= ATH_BCBUF; /* staggered multi-bss beacons */
if (intval < 15)
ATH5K_WARN(ah, "intval %u is too low, min 15\n",
-@@ -2427,6 +2427,7 @@ static const struct ieee80211_iface_limi
- #ifdef CONFIG_MAC80211_MESH
+@@ -2428,6 +2428,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
-+ BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) },
++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
};
+ static const struct ieee80211_iface_combination if_comb = {
+++ /dev/null
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -792,17 +792,11 @@ int ieee80211_register_hw(struct ieee802
- */
- for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
- const struct ieee80211_iface_combination *c;
-- int j;
-
- c = &hw->wiphy->iface_combinations[i];
-
- if (c->num_different_channels > 1)
- return -EINVAL;
--
-- for (j = 0; j < c->n_limits; j++)
-- if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
-- c->limits[j].max > 1)
-- return -EINVAL;
- }
-
- #ifndef CONFIG_MAC80211_MESH
*/
static bool
ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
-@@ -82,6 +83,19 @@ ath5k_pci_eeprom_read(struct ath_common
+@@ -82,6 +83,19 @@ ath5k_pci_eeprom_read(struct ath_common
struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
u32 status, timeout;
/* debugfs: queues etc */
-@@ -904,6 +987,9 @@ ath5k_debug_init_device(struct ath5k_hw
+@@ -904,6 +987,9 @@ ath5k_debug_init_device(struct ath5k_hw
debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
&fops_beacon);
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1532,6 +1532,53 @@ static const struct file_operations fops
-
- #endif
+@@ -1718,6 +1718,53 @@ void ath9k_get_et_stats(struct ieee80211
+ WARN_ON(i != ATH9K_SSTATS_LEN);
+ }
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1603,5 +1650,8 @@ int ath9k_init_debug(struct ath_hw *ah)
- debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
+@@ -1735,6 +1782,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+
+ ath9k_dfs_init_debug(sc);
+ debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_eeprom);
-+
- return 0;
- }
+ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dma);
+ debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
ath_err(common, "Reading Magic # failed\n");
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -705,6 +705,7 @@ enum ath_cal_list {
+@@ -704,6 +704,7 @@ enum ath_cal_list {
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
#define AH_FASTCC 0x4
struct ath_ops reg_ops;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -537,6 +537,8 @@ static int ath9k_init_softc(u16 devid, s
+@@ -541,6 +541,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;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -926,23 +926,23 @@ static int __init ath9k_init(void)
+@@ -936,23 +936,23 @@ static int __init ath9k_init(void)
goto err_out;
}
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1949,8 +1949,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -1962,8 +1962,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
REG_WRITE(ah, AR_OBS, 8);
if (ah->config.rx_intr_mitigation) {
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -659,6 +659,7 @@ struct ath_softc {
+@@ -679,6 +679,7 @@ struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
struct survey_info *cur_survey;
struct survey_info survey[ATH9K_NUM_CHANNELS];
-@@ -734,6 +735,7 @@ struct ath_softc {
+@@ -751,6 +752,7 @@ struct ath_softc {
#endif
};
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1579,6 +1579,50 @@ static const struct file_operations fops
+@@ -1765,6 +1765,50 @@ static const struct file_operations fops
.owner = THIS_MODULE
};
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1653,5 +1697,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1784,6 +1828,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+
debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_eeprom);
-
+ debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_chanbw);
-+
- return 0;
- }
+ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dma);
+ 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
-@@ -1127,7 +1127,7 @@ static void ath9k_disable_ps(struct ath_
+@@ -1075,7 +1075,7 @@ static void ath9k_disable_ps(struct ath_
ath_dbg(common, PS, "PowerSave disabled\n");
}
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
-@@ -1181,9 +1181,11 @@ static int ath9k_config(struct ieee80211
+@@ -1129,9 +1129,11 @@ static int ath9k_config(struct ieee80211
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
struct ieee80211_channel *curchan = hw->conf.channel;
if (ah->curchan)
old_pos = ah->curchan - &ah->channels[0];
-@@ -1226,7 +1228,23 @@ static int ath9k_config(struct ieee80211
+@@ -1174,7 +1176,23 @@ static int ath9k_config(struct ieee80211
memset(&sc->survey[pos], 0, sizeof(struct survey_info));
}
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -964,6 +964,7 @@ static const struct net_device_ops ieee8
+@@ -1039,6 +1039,7 @@ static const struct net_device_ops ieee8
static void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1372,6 +1372,7 @@ struct ieee80211_hw {
+@@ -1508,6 +1508,7 @@ struct ieee80211_hw {
u8 max_tx_aggregation_subframes;
u8 offchannel_tx_hw_queue;
u8 radiotap_mcs_details;
+ s8 cur_power_level;
+ u16 radiotap_vht_details;
netdev_features_t netdev_features;
};
-
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1967,7 +1967,7 @@ static int ieee80211_get_tx_power(struct
- {
+@@ -2096,7 +2096,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);
-- *dbm = local->hw.conf.power_level;
-+ *dbm = local->hw.cur_power_level;
-
- return 0;
- }
+- if (!local->use_chanctx)
++ if (local->hw.cur_power_level)
++ *dbm = local->hw.cur_power_level;
++ else if (!local->use_chanctx)
+ *dbm = local->hw.conf.power_level;
+ else
+ *dbm = sdata->vif.bss_conf.txpower;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -165,6 +165,7 @@ int ieee80211_hw_config(struct ieee80211
+@@ -167,6 +167,7 @@ static u32 ieee80211_hw_conf_chan(struct
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1251,6 +1251,8 @@ int ath9k_config(struct ieee80211_hw *hw
+@@ -1199,6 +1199,8 @@ int ath9k_config(struct ieee80211_hw *hw
return -EINVAL;
}
/*
* The most recent snapshot of channel->noisefloor for the old
* channel is only available after the hardware reset. Copy it to
-@@ -1265,6 +1267,7 @@ int ath9k_config(struct ieee80211_hw *hw
+@@ -1213,6 +1215,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);
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -729,6 +729,9 @@ enum mac80211_rx_flags {
+@@ -816,6 +816,9 @@ enum mac80211_rx_flags {
* @signal: signal strength when receiving this frame, either in dBm, in dB or
* unspecified depending on the hardware capabilities flags
* @IEEE80211_HW_SIGNAL_*
+ * @chain_signal: per-chain signal strength, same format as @signal
* @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates or MCS index if
- * HT rates are use (RX_FLAG_HT)
-@@ -749,6 +752,8 @@ struct ieee80211_rx_status {
+ * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
+@@ -847,6 +850,8 @@ struct ieee80211_rx_status {
u8 band;
u8 antenna;
s8 signal;
+ u8 chains;
+ s8 chain_signal[4];
u8 ampdu_delimiter_crc;
- };
-
+ u8 vendor_radiotap_align;
+ u8 vendor_radiotap_oui[3];
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
-@@ -325,6 +325,11 @@ struct sta_info {
- unsigned long rx_dropped;
+@@ -329,6 +329,11 @@ struct sta_info {
int last_signal;
struct ewma avg_signal;
+ int last_ack_signal;
+
+ u8 chains;
+ s8 chain_signal_last[4];
+ struct ewma chain_signal_avg[4];
+
/* Plus 1 for non-QoS frames */
- __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1];
+ __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -1271,6 +1271,7 @@ ieee80211_rx_h_sta_process(struct ieee80
+@@ -1375,6 +1375,7 @@ ieee80211_rx_h_sta_process(struct ieee80
struct sk_buff *skb = rx->skb;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (!sta)
return RX_CONTINUE;
-@@ -1315,6 +1316,19 @@ ieee80211_rx_h_sta_process(struct ieee80
+@@ -1425,6 +1426,19 @@ ieee80211_rx_h_sta_process(struct ieee80
ewma_add(&sta->avg_signal, -status->signal);
}
* exchange sequence.
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -254,6 +254,8 @@ struct sta_info *sta_info_alloc(struct i
+@@ -324,6 +324,8 @@ struct sta_info *sta_info_alloc(struct i
do_posix_clock_monotonic_gettime(&uptime);
sta->last_connected = uptime.tv_sec;
ewma_init(&sta->avg_signal, 1024, 8);
kfree(sta);
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -549,6 +549,8 @@ struct station_parameters {
+@@ -653,6 +653,8 @@ struct station_parameters {
* @STATION_INFO_STA_FLAGS: @sta_flags filled
* @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled
* @STATION_INFO_T_OFFSET: @t_offset filled
*/
enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0,
-@@ -572,6 +574,8 @@ enum station_info_flags {
+@@ -676,6 +678,8 @@ enum station_info_flags {
STATION_INFO_STA_FLAGS = 1<<18,
STATION_INFO_BEACON_LOSS_COUNT = 1<<19,
STATION_INFO_T_OFFSET = 1<<20,
};
/**
-@@ -655,6 +659,9 @@ struct sta_bss_parameters {
+@@ -769,6 +773,9 @@ struct sta_bss_parameters {
* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
* @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
* @txrate: current unicast bitrate from this station
* @rxrate: current unicast bitrate to this station
* @rx_packets: packets received from this station
-@@ -687,6 +694,11 @@ struct station_info {
+@@ -801,6 +808,11 @@ struct station_info {
u8 plink_state;
s8 signal;
s8 signal_avg;
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -458,12 +458,12 @@ int ath9k_hw_process_rxdesc_edma(struct
+@@ -475,12 +475,12 @@ int ath9k_hw_process_rxdesc_edma(struct
/* XXX: Keycache */
rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -997,12 +997,12 @@ void ath_debug_stat_rx(struct ath_softc
+@@ -939,12 +939,12 @@ void ath_debug_stat_rx(struct ath_softc
#ifdef CONFIG_ATH9K_MAC_DEBUG
spin_lock(&sc->debug.samp_lock);
RX_SAMP_DBG(jiffies) = jiffies;
RX_SAMP_DBG(antenna) = rs->rs_antenna;
RX_SAMP_DBG(rssi) = rs->rs_rssi;
RX_SAMP_DBG(rate) = rs->rs_rate;
---- a/include/linux/nl80211.h
-+++ b/include/linux/nl80211.h
-@@ -1760,6 +1760,8 @@ enum nl80211_sta_bss_param {
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -1834,6 +1834,8 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
* @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
* @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
-@@ -1784,6 +1786,8 @@ enum nl80211_sta_info {
+@@ -1858,6 +1860,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_STA_FLAGS,
NL80211_STA_INFO_BEACON_LOSS,
NL80211_STA_INFO_T_OFFSET,
__NL80211_STA_INFO_AFTER_LAST,
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -2769,6 +2769,32 @@ nla_put_failure:
- return false;
+@@ -2910,6 +2910,32 @@ static bool nl80211_put_sta_rate(struct
+ return true;
}
+static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
+ return true;
+}
+
- static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
+ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
int flags,
struct cfg80211_registered_device *rdev,
-@@ -2830,6 +2856,18 @@ static int nl80211_send_station(struct s
+@@ -2971,6 +2997,18 @@ static int nl80211_send_station(struct s
default:
break;
}
NL80211_STA_INFO_TX_BITRATE))
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -367,6 +367,7 @@ static void sta_set_sinfo(struct sta_inf
+@@ -435,6 +435,7 @@ static void sta_set_sinfo(struct sta_inf
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct timespec uptime;
sinfo->generation = sdata->local->sta_generation;
-@@ -406,6 +407,17 @@ static void sta_set_sinfo(struct sta_inf
+@@ -474,6 +475,17 @@ static void sta_set_sinfo(struct sta_inf
sinfo->signal = (s8)sta->last_signal;
sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
}
+ }
sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
-
+ sta_set_rate_info_rx(sta, &sinfo->rxrate);
--- a/drivers/net/wireless/ath/ath9k/dfs.c
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -164,8 +164,8 @@ void ath9k_dfs_process_phyerr(struct ath
* hardware stores this as 8 bit signed value.
--- a/drivers/net/wireless/ath/ath9k/antenna.c
+++ b/drivers/net/wireless/ath/ath9k/antenna.c
-@@ -529,14 +529,14 @@ void ath_ant_comb_scan(struct ath_softc
+@@ -546,14 +546,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;
+++ /dev/null
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -908,8 +908,7 @@ static void handle_channel(struct wiphy
-
- chan->beacon_found = false;
- chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
-- chan->max_antenna_gain = min(chan->orig_mag,
-- (int) MBI_TO_DBI(power_rule->max_antenna_gain));
-+ chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
- chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
- if (chan->orig_mpwr) {
- /*
--- /dev/null
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -955,6 +955,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
++ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
+ *
+ * @channel: the channel to tune to
+ * @channel_type: the channel (HT) type
+@@ -976,6 +977,7 @@ struct ieee80211_conf {
+ u32 flags;
+ int power_level, dynamic_ps_timeout;
+ int max_sleep_period;
++ int max_antenna_gain;
+
+ u16 listen_interval;
+ u8 ps_dtim_period;
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1132,6 +1132,7 @@ struct ieee80211_local {
+ bool disable_dynamic_ps;
+
+ int user_power_level; /* in dBm, for all interfaces */
++ int user_antenna_gain; /* in dBi */
+
+ enum ieee80211_smps_mode smps_mode;
+
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -1580,6 +1580,8 @@ enum nl80211_attrs {
+ NL80211_ATTR_P2P_CTWINDOW,
+ NL80211_ATTR_P2P_OPPPS,
+
++ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
++
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -365,6 +365,7 @@ static const struct nla_policy nl80211_p
+ [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
+ [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
++ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
+ };
+
+ /* policy for the key attributes */
+@@ -1652,6 +1653,22 @@ static int nl80211_set_wiphy(struct sk_b
+ goto bad_res;
+ }
+
++ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
++ int idx, dbi = 0;
++
++ if (!rdev->ops->set_antenna_gain) {
++ result = -EOPNOTSUPP;
++ goto bad_res;
++ }
++
++ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
++ dbi = nla_get_u32(info->attrs[idx]);
++
++ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
++ if (result)
++ goto bad_res;
++ }
++
+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
+ info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
+ u32 tx_ant, rx_ant;
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2118,6 +2118,19 @@ static int ieee80211_get_tx_power(struct
+ return 0;
+ }
+
++static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
++{
++ struct ieee80211_local *local = wiphy_priv(wiphy);
++
++ if (dbi < 0)
++ return -EINVAL;
++
++ local->user_antenna_gain = dbi;
++ ieee80211_hw_config(local, 0);
++
++ return 0;
++}
++
+ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *addr)
+ {
+@@ -3241,6 +3254,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,
++ .set_antenna_gain = ieee80211_set_antenna_gain,
+ .set_wds_peer = ieee80211_set_wds_peer,
+ .rfkill_poll = ieee80211_rfkill_poll,
+ CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1693,6 +1693,7 @@ struct cfg80211_gtk_rekey_data {
+ * (as advertised by the nl80211 feature flag.)
+ * @get_tx_power: store the current TX power into the dbm variable;
+ * return 0 if successful
++ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
+ *
+ * @set_wds_peer: set the WDS peer for a WDS interface
+ *
+@@ -1893,6 +1894,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);
++ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
+
+ int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *addr);
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -102,7 +102,7 @@ static u32 ieee80211_hw_conf_chan(struct
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_channel *chan;
+ u32 changed = 0;
+- int power;
++ int power, ant_gain, max_power;
+ enum nl80211_channel_type channel_type;
+ u32 offchannel_flag;
+ bool scanning = false;
+@@ -165,8 +165,21 @@ static u32 ieee80211_hw_conf_chan(struct
+ }
+ rcu_read_unlock();
+
+- if (local->hw.conf.power_level != power) {
++ max_power = chan->max_reg_power;
++ ant_gain = chan->max_antenna_gain;
++ if (local->user_antenna_gain > 0) {
++ if (local->user_antenna_gain > ant_gain) {
++ max_power -= local->user_antenna_gain - ant_gain;
++ ant_gain = 0;
++ } else
++ ant_gain -= local->user_antenna_gain;
++ }
++
++ power = min(chan->max_power, max_power);
++ if (local->hw.conf.power_level != power ||
++ local->hw.conf.max_antenna_gain != ant_gain) {
+ changed |= IEEE80211_CONF_CHANGE_POWER;
++ local->hw.conf.max_antenna_gain = ant_gain;
+ local->hw.cur_power_level = power;
+ local->hw.conf.power_level = power;
+ }
+@@ -646,6 +659,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+ IEEE80211_RADIOTAP_MCS_HAVE_BW;
+ local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
++ local->user_antenna_gain = 0;
+ local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+ wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -73,6 +73,7 @@ struct ath_regulatory {
+ u16 max_power_level;
+ u16 current_rd;
+ int16_t power_limit;
++ int16_t max_antenna_gain;
+ struct reg_dmn_pair_mapping *regpair;
+ };
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2836,7 +2836,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);
+- max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
++ max_gain = chan_pwr - new_pwr + reg->max_antenna_gain * 2;
+
+ ant_gain = get_antenna_gain(ah, chan);
+ if (ant_gain > max_gain)
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1211,7 +1211,10 @@ int ath9k_config(struct ieee80211_hw *hw
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
++ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
++
+ ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
++ reg->max_antenna_gain = conf->max_antenna_gain;
+ sc->config.txpowlimit = 2 * conf->power_level;
+ ath9k_cmn_update_txpow(ah, sc->curtxpow,
+ sc->config.txpowlimit, &sc->curtxpow);
+++ /dev/null
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -851,6 +851,7 @@ enum ieee80211_smps_mode {
- * the CONF_PS flag is set.
- *
- * @power_level: requested transmit power (in dBm)
-+ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
- *
- * @channel: the channel to tune to
- * @channel_type: the channel (HT) type
-@@ -870,6 +871,7 @@ struct ieee80211_conf {
- u32 flags;
- int power_level, dynamic_ps_timeout;
- int max_sleep_period;
-+ int max_antenna_gain;
-
- u16 listen_interval;
- u8 ps_dtim_period;
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -101,7 +101,7 @@ int ieee80211_hw_config(struct ieee80211
- {
- struct ieee80211_channel *chan;
- int ret = 0;
-- int power;
-+ int power, ant_gain, max_power;
- enum nl80211_channel_type channel_type;
- u32 offchannel_flag;
-
-@@ -152,19 +152,31 @@ int ieee80211_hw_config(struct ieee80211
- changed |= IEEE80211_CONF_CHANGE_SMPS;
- }
-
-- if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
-- test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
-- test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-- !local->ap_power_level)
-- power = chan->max_power;
-- else
-- power = min(chan->max_power, local->ap_power_level);
-+ max_power = chan->max_reg_power;
-+ if (!test_bit(SCAN_SW_SCANNING, &local->scanning) &&
-+ !test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) &&
-+ !test_bit(SCAN_HW_SCANNING, &local->scanning) &&
-+ local->ap_power_level)
-+ max_power = min(max_power, local->ap_power_level);
-+
-+ ant_gain = chan->max_antenna_gain;
-+ if (local->user_antenna_gain > 0) {
-+ if (local->user_antenna_gain > ant_gain) {
-+ max_power -= local->user_antenna_gain - ant_gain;
-+ ant_gain = 0;
-+ } else
-+ ant_gain -= local->user_antenna_gain;
-+ }
-+
-+ power = min(chan->max_power, max_power);
-
- if (local->user_power_level >= 0)
- power = min(power, local->user_power_level);
-
-- if (local->hw.conf.power_level != power) {
-+ if (local->hw.conf.power_level != power ||
-+ local->hw.conf.max_antenna_gain != ant_gain) {
- changed |= IEEE80211_CONF_CHANGE_POWER;
-+ local->hw.conf.max_antenna_gain = ant_gain;
- local->hw.cur_power_level = power;
- local->hw.conf.power_level = power;
- }
-@@ -620,6 +632,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
- IEEE80211_RADIOTAP_MCS_HAVE_GI |
- IEEE80211_RADIOTAP_MCS_HAVE_BW;
- local->user_power_level = -1;
-+ local->user_antenna_gain = -1;
- wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
-
- INIT_LIST_HEAD(&local->interfaces);
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1063,6 +1063,7 @@ struct ieee80211_local {
-
- int user_power_level; /* in dBm */
- int ap_power_level; /* in dBm */
-+ int user_antenna_gain; /* in dBi */
-
- enum ieee80211_smps_mode smps_mode;
-
---- a/include/linux/nl80211.h
-+++ b/include/linux/nl80211.h
-@@ -1517,6 +1517,8 @@ enum nl80211_attrs {
-
- NL80211_ATTR_USER_REG_HINT_TYPE,
-
-+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
-+
- /* add attributes here, update the policy in nl80211.c */
-
- __NL80211_ATTR_AFTER_LAST,
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -355,6 +355,7 @@ static const struct nla_policy nl80211_p
- [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
- [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
- [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
-+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
- };
-
- /* policy for the key attributes */
-@@ -1603,6 +1604,22 @@ static int nl80211_set_wiphy(struct sk_b
- if (result)
- goto bad_res;
- }
-+
-+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
-+ int idx, dbi = 0;
-+
-+ if (!rdev->ops->set_antenna_gain) {
-+ result = -EOPNOTSUPP;
-+ goto bad_res;
-+ }
-+
-+ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
-+ dbi = nla_get_u32(info->attrs[idx]);
-+
-+ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
-+ if (result)
-+ goto bad_res;
-+ }
-
- if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
- info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1984,6 +1984,19 @@ static int ieee80211_get_tx_power(struct
- return 0;
- }
-
-+static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
-+{
-+ struct ieee80211_local *local = wiphy_priv(wiphy);
-+
-+ if (dbi < 0)
-+ return -EINVAL;
-+
-+ local->user_antenna_gain = dbi;
-+ ieee80211_hw_config(local, 0);
-+
-+ return 0;
-+}
-+
- static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
- const u8 *addr)
- {
-@@ -3085,6 +3098,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,
-+ .set_antenna_gain = ieee80211_set_antenna_gain,
- .set_wds_peer = ieee80211_set_wds_peer,
- .rfkill_poll = ieee80211_rfkill_poll,
- CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -1552,6 +1552,7 @@ struct cfg80211_gtk_rekey_data {
- * the power passed is in mBm, to get dBm use MBM_TO_DBM().
- * @get_tx_power: store the current TX power into the dbm variable;
- * return 0 if successful
-+ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
- *
- * @set_wds_peer: set the WDS peer for a WDS interface
- *
-@@ -1751,6 +1752,7 @@ struct cfg80211_ops {
- int (*set_tx_power)(struct wiphy *wiphy,
- enum nl80211_tx_power_setting type, int mbm);
- int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
-+ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
-
- int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
- const u8 *addr);
+++ /dev/null
---- a/drivers/net/wireless/ath/ath.h
-+++ b/drivers/net/wireless/ath/ath.h
-@@ -73,6 +73,7 @@ struct ath_regulatory {
- u16 max_power_level;
- u16 current_rd;
- int16_t power_limit;
-+ int16_t max_antenna_gain;
- struct reg_dmn_pair_mapping *regpair;
- };
-
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2828,7 +2828,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);
-- max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
-+ max_gain = chan_pwr - new_pwr + reg->max_antenna_gain * 2;
-
- ant_gain = get_antenna_gain(ah, chan);
- if (ant_gain > max_gain)
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1263,7 +1263,10 @@ int ath9k_config(struct ieee80211_hw *hw
- }
-
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
-+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
-+
- ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
-+ reg->max_antenna_gain = conf->max_antenna_gain;
- sc->config.txpowlimit = 2 * conf->power_level;
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->config.txpowlimit, &sc->curtxpow);
+++ /dev/null
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -901,7 +901,7 @@ static void handle_channel(struct wiphy
- map_regdom_flags(reg_rule->flags) | bw_flags;
- chan->max_antenna_gain = chan->orig_mag =
- (int) MBI_TO_DBI(power_rule->max_antenna_gain);
-- chan->max_power = chan->orig_mpwr =
-+ chan->max_reg_power = chan->max_power = chan->orig_mpwr =
- (int) MBM_TO_DBM(power_rule->max_eirp);
- return;
- }
-@@ -1323,7 +1323,8 @@ static void handle_channel_custom(struct
-
- chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
- chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
-- chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
-+ chan->max_reg_power = chan->max_power =
-+ (int) MBM_TO_DBM(power_rule->max_eirp);
- }
-
- static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band,
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -556,6 +556,9 @@ struct ath9k_wow_pattern {
+ void ath_init_leds(struct ath_softc *sc);
+ void ath_deinit_leds(struct ath_softc *sc);
+ void ath_fill_led_pin(struct ath_softc *sc);
++int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
++ const char *trigger, bool active_low);
++
+ #else
+ static inline void ath_init_leds(struct ath_softc *sc)
+ {
+@@ -675,6 +678,13 @@ struct ath9k_vif_iter_data {
+ int nadhocs; /* number of adhoc vifs */
+ };
+
++struct ath_led {
++ struct list_head list;
++ struct ath_softc *sc;
++ const struct gpio_led *gpio;
++ struct led_classdev cdev;
++};
++
+ struct ath_softc {
+ struct ieee80211_hw *hw;
+ struct device *dev;
+@@ -716,9 +726,8 @@ struct ath_softc {
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
+
+ #ifdef CONFIG_MAC80211_LEDS
+- bool led_registered;
+- char led_name[32];
+- struct led_classdev led_cdev;
++ const char *led_default_trigger;
++ struct list_head leds;
+ #endif
+
+ struct ath9k_hw_cal_data caldata;
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -24,40 +24,102 @@
+ static void ath_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+ {
+- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
+- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
++ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
++ struct ath_softc *sc = led->sc;
++
++ ath9k_ps_wakeup(sc);
++ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
++ (brightness != LED_OFF) ^ led->gpio->active_low);
++ ath9k_ps_restore(sc);
++}
++
++static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
++{
++ const struct gpio_led *gpio = led->gpio;
++ int ret;
++
++ led->cdev.name = gpio->name;
++ led->cdev.default_trigger = gpio->default_trigger;
++ led->cdev.brightness_set = ath_led_brightness;
++
++ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
++ if (ret < 0)
++ return ret;
++
++ led->sc = sc;
++ list_add(&led->list, &sc->leds);
++
++ /* Configure gpio for output */
++ ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++
++ /* LED off */
++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
++
++ return 0;
++}
++
++int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
++ const char *trigger, bool active_low)
++{
++ struct ath_led *led;
++ struct gpio_led *gpio;
++ char *_name;
++ int ret;
++
++ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
++ GFP_KERNEL);
++ if (!led)
++ return -ENOMEM;
++
++ led->gpio = gpio = (struct gpio_led *) (led + 1);
++ _name = (char *) (led->gpio + 1);
++
++ strcpy(_name, name);
++ gpio->name = _name;
++ gpio->gpio = gpio_num;
++ gpio->active_low = active_low;
++ gpio->default_trigger = trigger;
++
++ ret = ath_add_led(sc, led);
++ if (unlikely(ret < 0))
++ kfree(led);
++
++ return ret;
+ }
+
+ void ath_deinit_leds(struct ath_softc *sc)
+ {
+- if (!sc->led_registered)
+- return;
++ struct ath_led *led;
+
+- ath_led_brightness(&sc->led_cdev, LED_OFF);
+- led_classdev_unregister(&sc->led_cdev);
++ while (!list_empty(&sc->leds)) {
++ led = list_first_entry(&sc->leds, struct ath_led, list);
++ list_del(&led->list);
++ ath_led_brightness(&led->cdev, LED_OFF);
++ led_classdev_unregister(&led->cdev);
++ kfree(led);
++ }
+ }
+
+ void ath_init_leds(struct ath_softc *sc)
+ {
+- int ret;
++ char led_name[32];
++ const char *trigger;
++
++ INIT_LIST_HEAD(&sc->leds);
+
+ if (AR_SREV_9100(sc->sc_ah))
+ return;
+
+- if (!led_blink)
+- sc->led_cdev.default_trigger =
+- ieee80211_get_radio_led_name(sc->hw);
+-
+- snprintf(sc->led_name, sizeof(sc->led_name),
+- "ath9k-%s", wiphy_name(sc->hw->wiphy));
+- sc->led_cdev.name = sc->led_name;
+- sc->led_cdev.brightness_set = ath_led_brightness;
++ snprintf(led_name, sizeof(led_name), "ath9k-%s",
++ wiphy_name(sc->hw->wiphy));
+
+- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
+- if (ret < 0)
+- return;
++ if (led_blink)
++ trigger = sc->led_default_trigger;
++ else
++ trigger = ieee80211_get_radio_led_name(sc->hw);
+
+- sc->led_registered = true;
++ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
+ }
+
+ 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
+@@ -821,7 +821,7 @@ int ath9k_init_device(u16 devid, struct
+
+ #ifdef CONFIG_MAC80211_LEDS
+ /* must be initialized before ieee80211_register_hw */
+- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
++ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
+ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
+ ARRAY_SIZE(ath9k_tpt_blink));
+ #endif
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1197,6 +1197,61 @@ static const struct file_operations fops
+ .llseek = default_llseek,
+ };
+
++#ifdef CONFIG_MAC80211_LEDS
++
++static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32], *str, *name, *c;
++ ssize_t len;
++ unsigned int gpio;
++ bool active_low = false;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, ubuf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ name = strchr(buf, ',');
++ if (!name)
++ return -EINVAL;
++
++ *(name++) = 0;
++ if (!*name)
++ return -EINVAL;
++
++ c = strchr(name, '\n');
++ if (c)
++ *c = 0;
++
++ str = buf;
++ if (*str == '!') {
++ str++;
++ active_low = true;
++ }
++
++ if (kstrtouint(str, 0, &gpio) < 0)
++ return -EINVAL;
++
++ if (gpio >= sc->sc_ah->caps.num_gpio_pins)
++ return -EINVAL;
++
++ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
++ return -EINVAL;
++
++ return count;
++}
++
++static const struct file_operations fops_gpio_led = {
++ .write = write_file_gpio_led,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++#endif
++
+ #ifdef CONFIG_ATH9K_MAC_DEBUG
+
+ void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
+@@ -1830,6 +1885,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);
++#ifdef CONFIG_MAC80211_LEDS
++ debugfs_create_file("gpio_led", S_IWUSR,
++ sc->debug.debugfs_phy, sc, &fops_gpio_led);
++#endif
+ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dma);
+ debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
-@@ -534,108 +534,108 @@ static const u32 ar9300_2p2_baseband_cor
-
- static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
-- {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
-- {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
-- {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
-+ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-- {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-- {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
-- {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
-- {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
-- {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
-- {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
-- {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
-- {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
-- {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
-- {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
-- {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
-- {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
-- {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
-- {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
-- {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
-- {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
-- {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
-- {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
-- {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
-- {0x0000a54c, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83},
-- {0x0000a550, 0x5e0a4431, 0x5e0a4431, 0x4a001c84, 0x4a001c84},
-- {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
-- {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
-- {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
-- {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
-- {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
-- {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
-- {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
-- {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
-- {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
-- {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202},
-- {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400},
-- {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402},
-- {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404},
-- {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603},
-- {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02},
-- {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04},
-- {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20},
-- {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20},
-- {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22},
-- {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24},
-- {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640},
-- {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660},
-- {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861},
-- {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81},
-- {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83},
-- {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84},
-- {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3},
-- {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5},
-- {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9},
-- {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb},
-- {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-- {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-- {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-- {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-- {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-- {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-- {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
-+ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
-+ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-+ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
-+ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
-+ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
-+ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
-+ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
-+ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
-+ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
-+ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
-+ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
-+ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
-+ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
-+ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
-+ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
-+ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
-+ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
-+ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
-+ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
-+ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
-+ {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-+ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
-+ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
-+ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
-+ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
-+ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
-+ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-+ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-+ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
-+ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
-+ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
-+ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
-+ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
-+ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
-+ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
-+ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
-+ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
-+ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
-+ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
-+ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
-+ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
-+ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
-+ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
-+ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
-+ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
-+ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
-+ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
-+ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
-+ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
-+ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
-+ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
-+ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
-+ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-+ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-+ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-+ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-+ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-+ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-+ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-- {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
-- {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
-- {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
-- {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
-- {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
-- {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
-- {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
-- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
-- {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
-- {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
-- {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
-- {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
-- {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
-- {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
-- {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
-- {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
-- {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
-+ {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-+ {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-+ {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-+ {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-+ {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-+ {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-+ {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-+ {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-+ {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-+ {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-+ {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-+ {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-+ {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-+ {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-+ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-- {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
-- {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
-- {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
-+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-- {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-- {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
-- {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-- {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-- {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
-- {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-- {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-- {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
-- {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-+ {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-+ {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
-+ {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
-+ {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-+ {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
-+ {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
-+ {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
-+ {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
-+ {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
- };
-
- static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
--- /dev/null
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -33,6 +33,9 @@ struct ath9k_platform_data {
+ bool is_clk_25mhz;
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
++
++ int num_leds;
++ const struct gpio_led *leds;
+ };
+
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -14,6 +14,7 @@
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
++#include <linux/ath9k_platform.h>
+ #include "ath9k.h"
+
+ /********************************/
+@@ -88,6 +89,24 @@ int ath_create_gpio_led(struct ath_softc
+ return ret;
+ }
+
++static int ath_create_platform_led(struct ath_softc *sc,
++ const struct gpio_led *gpio)
++{
++ struct ath_led *led;
++ int ret;
++
++ led = kzalloc(sizeof(*led), GFP_KERNEL);
++ if (!led)
++ return -ENOMEM;
++
++ led->gpio = gpio;
++ ret = ath_add_led(sc, led);
++ if (ret < 0)
++ kfree(led);
++
++ return ret;
++}
++
+ void ath_deinit_leds(struct ath_softc *sc)
+ {
+ struct ath_led *led;
+@@ -103,8 +122,10 @@ void ath_deinit_leds(struct ath_softc *s
+
+ void ath_init_leds(struct ath_softc *sc)
+ {
++ struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ char led_name[32];
+ const char *trigger;
++ int i;
+
+ INIT_LIST_HEAD(&sc->leds);
+
+@@ -120,6 +141,12 @@ void ath_init_leds(struct ath_softc *sc)
+ trigger = ieee80211_get_radio_led_name(sc->hw);
+
+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
++
++ if (!pdata)
++ return;
++
++ for (i = 0; i < pdata->num_leds; i++)
++ ath_create_platform_led(sc, &pdata->leds[i]);
+ }
+
+ void ath_fill_led_pin(struct ath_softc *sc)
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -538,6 +538,9 @@ struct ath9k_wow_pattern {
- #ifdef CONFIG_MAC80211_LEDS
- void ath_init_leds(struct ath_softc *sc);
- void ath_deinit_leds(struct ath_softc *sc);
-+int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
-+ const char *trigger, bool active_low);
-+
- #else
- static inline void ath_init_leds(struct ath_softc *sc)
- {
-@@ -655,6 +658,13 @@ struct ath9k_vif_iter_data {
- int nadhocs; /* number of adhoc vifs */
- };
-
-+struct ath_led {
-+ struct list_head list;
-+ struct ath_softc *sc;
-+ const struct gpio_led *gpio;
-+ struct led_classdev cdev;
-+};
-+
- struct ath_softc {
- struct ieee80211_hw *hw;
- struct device *dev;
-@@ -696,9 +706,8 @@ struct ath_softc {
- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-
- #ifdef CONFIG_MAC80211_LEDS
-- bool led_registered;
-- char led_name[32];
-- struct led_classdev led_cdev;
-+ const char *led_default_trigger;
-+ struct list_head leds;
- #endif
-
- struct ath9k_hw_cal_data caldata;
---- a/drivers/net/wireless/ath/ath9k/gpio.c
-+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -24,22 +24,89 @@
- static void ath_led_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
- {
-- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
-+ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
-+ struct ath_softc *sc = led->sc;
-+
-+ ath9k_ps_wakeup(sc);
-+ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
-+ (brightness != LED_OFF) ^ led->gpio->active_low);
-+ ath9k_ps_restore(sc);
-+}
-+
-+static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
-+{
-+ const struct gpio_led *gpio = led->gpio;
-+ int ret;
-+
-+ led->cdev.name = gpio->name;
-+ led->cdev.default_trigger = gpio->default_trigger;
-+ led->cdev.brightness_set = ath_led_brightness;
-+
-+ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ led->sc = sc;
-+ list_add(&led->list, &sc->leds);
-+
-+ /* Configure gpio for output */
-+ ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
-+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-+
-+ /* LED off */
-+ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
-+
-+ return 0;
-+}
-+
-+int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
-+ const char *trigger, bool active_low)
-+{
-+ struct ath_led *led;
-+ struct gpio_led *gpio;
-+ char *_name;
-+ int ret;
-+
-+ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
-+ GFP_KERNEL);
-+ if (!led)
-+ return -ENOMEM;
-+
-+ led->gpio = gpio = (struct gpio_led *) (led + 1);
-+ _name = (char *) (led->gpio + 1);
-+
-+ strcpy(_name, name);
-+ gpio->name = _name;
-+ gpio->gpio = gpio_num;
-+ gpio->active_low = active_low;
-+ gpio->default_trigger = trigger;
-+
-+ ret = ath_add_led(sc, led);
-+ if (unlikely(ret < 0))
-+ kfree(led);
-+
-+ return ret;
- }
-
- void ath_deinit_leds(struct ath_softc *sc)
- {
-- if (!sc->led_registered)
-- return;
-+ struct ath_led *led;
-
-- ath_led_brightness(&sc->led_cdev, LED_OFF);
-- led_classdev_unregister(&sc->led_cdev);
-+ while (!list_empty(&sc->leds)) {
-+ led = list_first_entry(&sc->leds, struct ath_led, list);
-+ list_del(&led->list);
-+ ath_led_brightness(&led->cdev, LED_OFF);
-+ led_classdev_unregister(&led->cdev);
-+ kfree(led);
-+ }
- }
-
- void ath_init_leds(struct ath_softc *sc)
- {
-- int ret;
-+ char led_name[32];
-+ const char *trigger;
-+
-+ INIT_LIST_HEAD(&sc->leds);
-
- if (AR_SREV_9100(sc->sc_ah))
- return;
-@@ -57,26 +124,15 @@ void ath_init_leds(struct ath_softc *sc)
- sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
- }
-
-- /* Configure gpio 1 for output */
-- ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
-- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-- /* LED off, active low */
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
--
-- if (!led_blink)
-- sc->led_cdev.default_trigger =
-- ieee80211_get_radio_led_name(sc->hw);
--
-- snprintf(sc->led_name, sizeof(sc->led_name),
-- "ath9k-%s", wiphy_name(sc->hw->wiphy));
-- sc->led_cdev.name = sc->led_name;
-- sc->led_cdev.brightness_set = ath_led_brightness;
-+ snprintf(led_name, sizeof(led_name), "ath9k-%s",
-+ wiphy_name(sc->hw->wiphy));
-
-- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
-- if (ret < 0)
-- return;
-+ if (led_blink)
-+ trigger = sc->led_default_trigger;
-+ else
-+ trigger = ieee80211_get_radio_led_name(sc->hw);
-
-- sc->led_registered = true;
-+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
- }
- #endif
-
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -811,7 +811,7 @@ int ath9k_init_device(u16 devid, struct
-
- #ifdef CONFIG_MAC80211_LEDS
- /* must be initialized before ieee80211_register_hw */
-- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
-+ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
- IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
- ARRAY_SIZE(ath9k_tpt_blink));
- #endif
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1255,6 +1255,61 @@ static const struct file_operations fops
- .llseek = default_llseek,
- };
-
-+#ifdef CONFIG_MAC80211_LEDS
-+
-+static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct ath_softc *sc = file->private_data;
-+ char buf[32], *str, *name, *c;
-+ ssize_t len;
-+ unsigned int gpio;
-+ bool active_low = false;
-+
-+ len = min(count, sizeof(buf) - 1);
-+ if (copy_from_user(buf, ubuf, len))
-+ return -EFAULT;
-+
-+ buf[len] = '\0';
-+ name = strchr(buf, ',');
-+ if (!name)
-+ return -EINVAL;
-+
-+ *(name++) = 0;
-+ if (!*name)
-+ return -EINVAL;
-+
-+ c = strchr(name, '\n');
-+ if (c)
-+ *c = 0;
-+
-+ str = buf;
-+ if (*str == '!') {
-+ str++;
-+ active_low = true;
-+ }
-+
-+ if (kstrtouint(str, 0, &gpio) < 0)
-+ return -EINVAL;
-+
-+ if (gpio >= sc->sc_ah->caps.num_gpio_pins)
-+ return -EINVAL;
-+
-+ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
-+ return -EINVAL;
-+
-+ return count;
-+}
-+
-+static const struct file_operations fops_gpio_led = {
-+ .write = write_file_gpio_led,
-+ .open = simple_open,
-+ .owner = THIS_MODULE,
-+ .llseek = default_llseek,
-+};
-+
-+#endif
-+
- #ifdef CONFIG_ATH9K_MAC_DEBUG
-
- void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
-@@ -1688,6 +1743,11 @@ int ath9k_init_debug(struct ath_hw *ah)
- &fops_samps);
- #endif
-
-+#ifdef CONFIG_MAC80211_LEDS
-+ debugfs_create_file("gpio_led", S_IWUSR,
-+ sc->debug.debugfs_phy, sc, &fops_gpio_led);
-+#endif
-+
- debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
-
--- /dev/null
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -761,6 +761,8 @@ struct ieee80211_sub_if_data {
+
+ /* bitmap of allowed (non-MCS) rate indexes for rate control */
+ u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
++
++ bool rc_has_mcs_mask[IEEE80211_NUM_BANDS];
+ u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
+
+ union {
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2291,9 +2291,20 @@ static int ieee80211_set_bitrate_mask(st
+ }
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
++ struct ieee80211_supported_band *sband = wiphy->bands[i];
++
+ sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
+ memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
+ sizeof(mask->control[i].mcs));
++
++ sdata->rc_has_mcs_mask[i] = false;
++ if (!sband)
++ continue;
++
++ if (memcmp(sdata->rc_rateidx_mcs_mask[i],
++ sband->ht_cap.mcs.rx_mask,
++ sizeof(sband->ht_cap.mcs.rx_mask)) != 0)
++ sdata->rc_has_mcs_mask[i] = true;
+ }
+
+ return 0;
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -3968,7 +3968,7 @@ void ieee80211_send_bar(struct ieee80211
+ * (deprecated; this will be removed once drivers get updated to use
+ * rate_idx_mask)
+ * @rate_idx_mask: user-requested (legacy) rate mask
+- * @rate_idx_mcs_mask: user-requested MCS rate mask
++ * @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use)
+ * @bss: whether this frame is sent out in AP or IBSS mode
+ */
+ struct ieee80211_tx_rate_control {
+@@ -3980,7 +3980,7 @@ struct ieee80211_tx_rate_control {
+ bool rts, short_preamble;
+ u8 max_rate_idx;
+ u32 rate_idx_mask;
+- u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
++ u8 *rate_idx_mcs_mask;
+ bool bss;
+ };
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -636,9 +636,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
+ txrc.max_rate_idx = -1;
+ else
+ txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+- memcpy(txrc.rate_idx_mcs_mask,
+- tx->sdata->rc_rateidx_mcs_mask[info->band],
+- sizeof(txrc.rate_idx_mcs_mask));
++
++ if (tx->sdata->rc_has_mcs_mask[info->band])
++ txrc.rate_idx_mcs_mask =
++ tx->sdata->rc_rateidx_mcs_mask[info->band];
++
+ txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
+ tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+ tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
+@@ -2502,8 +2504,6 @@ struct sk_buff *ieee80211_beacon_get_tim
+ txrc.max_rate_idx = -1;
+ else
+ txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+- memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
+- sizeof(txrc.rate_idx_mcs_mask));
+ txrc.bss = true;
+ rate_control_get_rate(sdata, NULL, &txrc);
+
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -460,9 +460,12 @@ void rate_control_get_rate(struct ieee80
+ * the common case.
+ */
+ mask = sdata->rc_rateidx_mask[info->band];
+- memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
+- sizeof(mcs_mask));
+- if (mask != (1 << txrc->sband->n_bitrates) - 1) {
++ if (mask != (1 << txrc->sband->n_bitrates) - 1 || txrc->rate_idx_mcs_mask) {
++ if (txrc->rate_idx_mcs_mask)
++ memcpy(mcs_mask, txrc->rate_idx_mcs_mask, sizeof(mcs_mask));
++ else
++ memset(mcs_mask, 0xff, sizeof(mcs_mask));
++
+ if (sta) {
+ /* Filter out rates that the STA does not support */
+ mask &= sta->sta.supp_rates[info->band];
+++ /dev/null
---- a/include/linux/ath9k_platform.h
-+++ b/include/linux/ath9k_platform.h
-@@ -33,6 +33,9 @@ struct ath9k_platform_data {
- bool is_clk_25mhz;
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
-+
-+ int num_leds;
-+ const struct gpio_led *leds;
- };
-
- #endif /* _LINUX_ATH9K_PLATFORM_H */
---- a/drivers/net/wireless/ath/ath9k/gpio.c
-+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -14,6 +14,7 @@
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-+#include <linux/ath9k_platform.h>
- #include "ath9k.h"
-
- /********************************/
-@@ -88,6 +89,24 @@ int ath_create_gpio_led(struct ath_softc
- return ret;
- }
-
-+static int ath_create_platform_led(struct ath_softc *sc,
-+ const struct gpio_led *gpio)
-+{
-+ struct ath_led *led;
-+ int ret;
-+
-+ led = kzalloc(sizeof(*led), GFP_KERNEL);
-+ if (!led)
-+ return -ENOMEM;
-+
-+ led->gpio = gpio;
-+ ret = ath_add_led(sc, led);
-+ if (ret < 0)
-+ kfree(led);
-+
-+ return ret;
-+}
-+
- void ath_deinit_leds(struct ath_softc *sc)
- {
- struct ath_led *led;
-@@ -103,8 +122,10 @@ void ath_deinit_leds(struct ath_softc *s
-
- void ath_init_leds(struct ath_softc *sc)
- {
-+ struct ath9k_platform_data *pdata = sc->dev->platform_data;
- char led_name[32];
- const char *trigger;
-+ int i;
-
- INIT_LIST_HEAD(&sc->leds);
-
-@@ -133,6 +154,12 @@ void ath_init_leds(struct ath_softc *sc)
- trigger = ieee80211_get_radio_led_name(sc->hw);
-
- ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
-+
-+ if (!pdata)
-+ return;
-+
-+ for (i = 0; i < pdata->num_leds; i++)
-+ ath_create_platform_led(sc, &pdata->leds[i]);
- }
- #endif
-
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -241,21 +241,19 @@ static bool ar9003_hw_get_isr(struct ath
+
+ *masked = isr & ATH9K_INT_COMMON;
+
+- if (ah->config.rx_intr_mitigation)
++ if (ah->config.rx_intr_mitigation) {
+ if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+ *masked |= ATH9K_INT_RXLP;
+-
+- if (ah->config.tx_intr_mitigation)
+- if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
+- *masked |= ATH9K_INT_TX;
+-
+- if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
++ } else if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
+ *masked |= ATH9K_INT_RXLP;
+
+ if (isr & AR_ISR_HP_RXOK)
+ *masked |= ATH9K_INT_RXHP;
+
+- if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
++ if (ah->config.tx_intr_mitigation) {
++ if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
++ *masked |= ATH9K_INT_TX;
++ } else if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
+ *masked |= ATH9K_INT_TX;
+
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ani.h
++++ b/drivers/net/wireless/ath/ath9k/ani.h
+@@ -51,7 +51,7 @@
+ #define ATH9K_ANI_PERIOD 300
+
+ /* in ms */
+-#define ATH9K_ANI_POLLINTERVAL 1000
++#define ATH9K_ANI_POLLINTERVAL 100
+
+ #define HAL_NOISE_IMMUNE_MAX 4
+ #define HAL_SPUR_IMMUNE_MAX 7
+++ /dev/null
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -715,6 +715,8 @@ struct ieee80211_sub_if_data {
-
- /* bitmap of allowed (non-MCS) rate indexes for rate control */
- u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
-+
-+ bool rc_has_mcs_mask[IEEE80211_NUM_BANDS];
- u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
-
- union {
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -2160,9 +2160,20 @@ static int ieee80211_set_bitrate_mask(st
- }
-
- for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
-+ struct ieee80211_supported_band *sband = wiphy->bands[i];
-+
- sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
- memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
- sizeof(mask->control[i].mcs));
-+
-+ sdata->rc_has_mcs_mask[i] = false;
-+ if (!sband)
-+ continue;
-+
-+ if (memcmp(sdata->rc_rateidx_mcs_mask[i],
-+ sband->ht_cap.mcs.rx_mask,
-+ sizeof(sband->ht_cap.mcs.rx_mask)) != 0)
-+ sdata->rc_has_mcs_mask[i] = true;
- }
-
- return 0;
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -3721,7 +3721,7 @@ void ieee80211_send_bar(struct ieee80211
- * (deprecated; this will be removed once drivers get updated to use
- * rate_idx_mask)
- * @rate_idx_mask: user-requested (legacy) rate mask
-- * @rate_idx_mcs_mask: user-requested MCS rate mask
-+ * @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use)
- * @bss: whether this frame is sent out in AP or IBSS mode
- */
- struct ieee80211_tx_rate_control {
-@@ -3733,7 +3733,7 @@ struct ieee80211_tx_rate_control {
- bool rts, short_preamble;
- u8 max_rate_idx;
- u32 rate_idx_mask;
-- u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
-+ u8 *rate_idx_mcs_mask;
- bool bss;
- };
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -631,9 +631,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
- txrc.max_rate_idx = -1;
- else
- txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
-- memcpy(txrc.rate_idx_mcs_mask,
-- tx->sdata->rc_rateidx_mcs_mask[info->band],
-- sizeof(txrc.rate_idx_mcs_mask));
-+
-+ if (tx->sdata->rc_has_mcs_mask[info->band])
-+ txrc.rate_idx_mcs_mask =
-+ tx->sdata->rc_rateidx_mcs_mask[info->band];
-+
- txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
- tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
- tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
-@@ -2452,8 +2454,6 @@ struct sk_buff *ieee80211_beacon_get_tim
- txrc.max_rate_idx = -1;
- else
- txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
-- memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
-- sizeof(txrc.rate_idx_mcs_mask));
- txrc.bss = true;
- rate_control_get_rate(sdata, NULL, &txrc);
-
---- a/net/mac80211/rate.c
-+++ b/net/mac80211/rate.c
-@@ -461,9 +461,12 @@ void rate_control_get_rate(struct ieee80
- * the common case.
- */
- mask = sdata->rc_rateidx_mask[info->band];
-- memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
-- sizeof(mcs_mask));
-- if (mask != (1 << txrc->sband->n_bitrates) - 1) {
-+ if (mask != (1 << txrc->sband->n_bitrates) - 1 || txrc->rate_idx_mcs_mask) {
-+ if (txrc->rate_idx_mcs_mask)
-+ memcpy(mcs_mask, txrc->rate_idx_mcs_mask, sizeof(mcs_mask));
-+ else
-+ memset(mcs_mask, 0xff, sizeof(mcs_mask));
-+
- if (sta) {
- /* Filter out rates that the STA does not support */
- mask &= sta->sta.supp_rates[info->band];
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -240,21 +240,19 @@ static bool ar9003_hw_get_isr(struct ath
-
- *masked = isr & ATH9K_INT_COMMON;
-
-- if (ah->config.rx_intr_mitigation)
-+ if (ah->config.rx_intr_mitigation) {
- if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
- *masked |= ATH9K_INT_RXLP;
--
-- if (ah->config.tx_intr_mitigation)
-- if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
-- *masked |= ATH9K_INT_TX;
--
-- if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
-+ } else if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
- *masked |= ATH9K_INT_RXLP;
-
- if (isr & AR_ISR_HP_RXOK)
- *masked |= ATH9K_INT_RXHP;
-
-- if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
-+ if (ah->config.tx_intr_mitigation) {
-+ if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
-+ *masked |= ATH9K_INT_TX;
-+ } else if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
- *masked |= ATH9K_INT_TX;
-
- if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+@@ -778,11 +778,11 @@ static const u32 ar9300Common_rx_gain_ta
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+- {0x0000a080, 0x1a1a1a1a},
+- {0x0000a084, 0x1a1a1a1a},
+- {0x0000a088, 0x1a1a1a1a},
+- {0x0000a08c, 0x1a1a1a1a},
+- {0x0000a090, 0x171a1a1a},
++ {0x0000a080, 0x22222229},
++ {0x0000a084, 0x1d1d1d1d},
++ {0x0000a088, 0x1d1d1d1d},
++ {0x0000a08c, 0x1d1d1d1d},
++ {0x0000a090, 0x171d1d1d},
+ {0x0000a094, 0x11111717},
+ {0x0000a098, 0x00030311},
+ {0x0000a09c, 0x00000000},
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -689,7 +689,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
+ {
+ #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
+ struct ath_common *common = ath9k_hw_common(ah);
+- u32 mac_status, last_mac_status = 0;
++ u32 mac_status = 0, last_mac_status = 0;
+ int i;
+
+ /* Enable access to the DMA observation bus */
+@@ -719,6 +719,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
+ }
+
+ if (i == 0) {
++ if (!AR_SREV_9300_20_OR_LATER(ah) &&
++ (mac_status & 0x700) == 0) {
++ /*
++ * DMA is idle but the MAC is still stuck
++ * processing events
++ */
++ *reset = true;
++ return true;
++ }
++
+ ath_err(common,
+ "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
+ AH_RX_STOP_DMA_TIMEOUT / 1000,
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1864,6 +1864,50 @@ static const struct file_operations fops
+ };
+
+
++static ssize_t read_file_diag(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;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "0x%08lx\n", ah->diag);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_diag(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ struct ath_hw *ah = sc->sc_ah;
++ unsigned long diag;
++ char buf[32];
++ ssize_t len;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ if (strict_strtoul(buf, 0, &diag))
++ return -EINVAL;
++
++ ah->diag = diag;
++ ath9k_hw_update_diag(ah);
++
++ return count;
++}
++
++static const struct file_operations fops_diag = {
++ .read = read_file_diag,
++ .write = write_file_diag,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+ struct ath_common *common = ath9k_hw_common(ah);
+@@ -1889,6 +1933,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
++ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++ sc, &fops_diag);
+ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dma);
+ 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
+@@ -497,6 +497,12 @@ enum {
+ ATH9K_RESET_COLD,
+ };
+
++enum {
++ ATH_DIAG_DISABLE_RX,
++ ATH_DIAG_DISABLE_TX,
++ ATH_DIAG_TRIGGER_ERROR,
++};
++
+ struct ath9k_hw_version {
+ u32 magic;
+ u16 devid;
+@@ -741,6 +747,8 @@ struct ath_hw {
+ u32 rfkill_polarity;
+ u32 ah_flags;
+
++ unsigned long diag;
++
+ bool reset_power_on;
+ bool htc_reset_init;
+
+@@ -1007,6 +1015,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);
++void ath9k_hw_update_diag(struct ath_hw *ah);
+
+ #ifdef CONFIG_ATH9K_DEBUGFS
+ 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
+@@ -1762,6 +1762,20 @@ fail:
+ return -EINVAL;
+ }
+
++void ath9k_hw_update_diag(struct ath_hw *ah)
++{
++ if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag))
++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
++ else
++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
++
++ if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag))
++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
++ else
++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
++}
++EXPORT_SYMBOL(ath9k_hw_update_diag);
++
+ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+ struct ath9k_hw_cal_data *caldata, bool fastcc)
+ {
+@@ -2039,6 +2053,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)
+ 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
+@@ -470,6 +470,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 */
+
++ if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) {
++ status |= ATH9K_INT_FATAL;
++ clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag);
++ }
++
+ /*
+ * If there are no status bits set, then this interrupt was not
+ * for me (should have been caught above).
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -1085,6 +1085,10 @@ static bool ar9003_hw_ani_control(struct
+ * is_on == 0 means MRC CCK is OFF (more noise imm)
+ */
+ bool is_on = param ? 1 : 0;
++
++ if (ah->caps.rx_chainmask == 1)
++ break;
++
+ 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,
--- /dev/null
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -31,6 +31,9 @@ struct ath9k_platform_data {
+
+ bool endian_check;
+ bool is_clk_25mhz;
++ bool disable_2ghz;
++ bool disable_5ghz;
++
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2429,17 +2429,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw
+ }
+
+ eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
+- if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
+- ath_err(common,
+- "no band has been marked as supported in EEPROM\n");
+- return -EINVAL;
++
++ if (eeval & AR5416_OPFLAGS_11A) {
++ if (ah->disable_5ghz)
++ ath_warn(common, "disabling 5GHz band\n");
++ else
++ pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
+ }
+
+- if (eeval & AR5416_OPFLAGS_11A)
+- pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
++ if (eeval & AR5416_OPFLAGS_11G) {
++ if (ah->disable_2ghz)
++ ath_warn(common, "disabling 2GHz band\n");
++ else
++ pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
++ }
+
+- if (eeval & AR5416_OPFLAGS_11G)
+- pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
++ if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
++ ath_err(common, "both bands are disabled\n");
++ return -EINVAL;
++ }
+
+ if (AR_SREV_9485(ah) ||
+ AR_SREV_9285(ah) ||
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -929,6 +929,8 @@ struct ath_hw {
+ bool is_clk_25mhz;
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
++ bool disable_2ghz;
++ bool disable_5ghz;
+ };
+
+ struct ath_bus_ops {
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -541,6 +541,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;
++ ah->disable_2ghz = pdata->disable_2ghz;
++ ah->disable_5ghz = pdata->disable_5ghz;
+ if (!pdata->endian_check)
+ ah->ah_flags |= AH_NO_EEP_SWAP;
+ }
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ani.h
-+++ b/drivers/net/wireless/ath/ath9k/ani.h
-@@ -51,7 +51,7 @@
- #define ATH9K_ANI_PERIOD 300
-
- /* in ms */
--#define ATH9K_ANI_POLLINTERVAL 1000
-+#define ATH9K_ANI_POLLINTERVAL 100
-
- #define HAL_NOISE_IMMUNE_MAX 4
- #define HAL_SPUR_IMMUNE_MAX 7
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
-@@ -778,11 +778,11 @@ static const u32 ar9300Common_rx_gain_ta
- {0x0000a074, 0x00000000},
- {0x0000a078, 0x00000000},
- {0x0000a07c, 0x00000000},
-- {0x0000a080, 0x1a1a1a1a},
-- {0x0000a084, 0x1a1a1a1a},
-- {0x0000a088, 0x1a1a1a1a},
-- {0x0000a08c, 0x1a1a1a1a},
-- {0x0000a090, 0x171a1a1a},
-+ {0x0000a080, 0x22222229},
-+ {0x0000a084, 0x1d1d1d1d},
-+ {0x0000a088, 0x1d1d1d1d},
-+ {0x0000a08c, 0x1d1d1d1d},
-+ {0x0000a090, 0x171d1d1d},
- {0x0000a094, 0x11111717},
- {0x0000a098, 0x00030311},
- {0x0000a09c, 0x00000000},
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1087,6 +1087,7 @@ static void ath9k_remove_interface(struc
- ath9k_calculate_summary_state(hw, NULL);
-
- mutex_unlock(&sc->mutex);
-+ ath9k_config(hw, IEEE80211_CONF_CHANGE_IDLE);
- ath9k_ps_restore(sc);
- }
-
-@@ -1139,7 +1140,8 @@ int ath9k_config(struct ieee80211_hw *hw
- mutex_lock(&sc->mutex);
-
- if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-- sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
-+ sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE) &&
-+ !sc->nvifs;
- if (sc->ps_idle) {
- ath_cancel_work(sc);
- ath9k_stop_btcoex(sc);
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/mac.c
-+++ b/drivers/net/wireless/ath/ath9k/mac.c
-@@ -689,7 +689,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
- {
- #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
- struct ath_common *common = ath9k_hw_common(ah);
-- u32 mac_status, last_mac_status = 0;
-+ u32 mac_status = 0, last_mac_status = 0;
- int i;
-
- /* Enable access to the DMA observation bus */
-@@ -719,6 +719,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
- }
-
- if (i == 0) {
-+ if (!AR_SREV_9300_20_OR_LATER(ah) &&
-+ (mac_status & 0x700) == 0) {
-+ /*
-+ * DMA is idle but the MAC is still stuck
-+ * processing events
-+ */
-+ *reset = true;
-+ return true;
-+ }
-+
- ath_err(common,
- "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
- AH_RX_STOP_DMA_TIMEOUT / 1000,
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1678,6 +1678,50 @@ static const struct file_operations fops
- };
-
-
-+static ssize_t read_file_diag(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;
-+ char buf[32];
-+ unsigned int len;
-+
-+ len = sprintf(buf, "0x%08lx\n", ah->diag);
-+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+}
-+
-+static ssize_t write_file_diag(struct file *file, const char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct ath_softc *sc = file->private_data;
-+ struct ath_hw *ah = sc->sc_ah;
-+ unsigned long diag;
-+ char buf[32];
-+ ssize_t len;
-+
-+ len = min(count, sizeof(buf) - 1);
-+ if (copy_from_user(buf, user_buf, len))
-+ return -EFAULT;
-+
-+ buf[len] = '\0';
-+ if (strict_strtoul(buf, 0, &diag))
-+ return -EINVAL;
-+
-+ ah->diag = diag;
-+ ath9k_hw_update_diag(ah);
-+
-+ return count;
-+}
-+
-+static const struct file_operations fops_diag = {
-+ .read = read_file_diag,
-+ .write = write_file_diag,
-+ .open = simple_open,
-+ .owner = THIS_MODULE,
-+ .llseek = default_llseek,
-+};
-+
-+
- int ath9k_init_debug(struct ath_hw *ah)
- {
- struct ath_common *common = ath9k_hw_common(ah);
-@@ -1760,5 +1804,8 @@ int ath9k_init_debug(struct ath_hw *ah)
- debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- sc, &fops_chanbw);
-
-+ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-+ sc, &fops_diag);
-+
- return 0;
- }
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -498,6 +498,12 @@ enum {
- ATH9K_RESET_COLD,
- };
-
-+enum {
-+ ATH_DIAG_DISABLE_RX,
-+ ATH_DIAG_DISABLE_TX,
-+ ATH_DIAG_TRIGGER_ERROR,
-+};
-+
- struct ath9k_hw_version {
- u32 magic;
- u16 devid;
-@@ -741,6 +747,8 @@ struct ath_hw {
- u32 rfkill_polarity;
- u32 ah_flags;
-
-+ unsigned long diag;
-+
- bool htc_reset_init;
-
- enum nl80211_iftype opmode;
-@@ -1007,6 +1015,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);
-+void ath9k_hw_update_diag(struct ath_hw *ah);
-
- #ifdef CONFIG_ATH9K_DEBUGFS
- 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
-@@ -1749,6 +1749,20 @@ fail:
- return -EINVAL;
- }
-
-+void ath9k_hw_update_diag(struct ath_hw *ah)
-+{
-+ if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag))
-+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-+ else
-+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-+
-+ if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag))
-+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
-+ else
-+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
-+}
-+EXPORT_SYMBOL(ath9k_hw_update_diag);
-+
- int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
- struct ath9k_hw_cal_data *caldata, bool fastcc)
- {
-@@ -2026,6 +2040,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
- }
-
- ath9k_hw_apply_gpio_override(ah);
-+ ath9k_hw_update_diag(ah);
-
- return 0;
- }
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -476,6 +476,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 */
-
-+ if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) {
-+ status |= ATH9K_INT_FATAL;
-+ clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag);
-+ }
-+
- /*
- * If there are no status bits set, then this interrupt was not
- * for me (should have been caught above).
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1767,6 +1767,8 @@ int ath9k_init_debug(struct ath_hw *ah)
- sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
- debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_disable_ani);
-+ debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-+ &sc->sc_ah->config.enable_paprd);
- debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- sc, &fops_regidx);
- debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2521,10 +2521,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw
- pCap->rx_status_len = sizeof(struct ar9003_rxs);
- pCap->tx_desc_len = sizeof(struct ar9003_txc);
- pCap->txs_len = sizeof(struct ar9003_txs);
-- if (!ah->config.paprd_disable &&
-- ah->eep_ops->get_eeprom(ah, EEP_PAPRD) &&
-- !AR_SREV_9462(ah))
-- pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
- } else {
- pCap->tx_desc_len = sizeof(struct ath_desc);
- if (AR_SREV_9280_20(ah))
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -236,7 +236,6 @@ enum ath9k_hw_caps {
- ATH9K_HW_CAP_LDPC = BIT(6),
- ATH9K_HW_CAP_FASTCLOCK = BIT(7),
- ATH9K_HW_CAP_SGI_20 = BIT(8),
-- ATH9K_HW_CAP_PAPRD = BIT(9),
- ATH9K_HW_CAP_ANT_DIV_COMB = BIT(10),
- ATH9K_HW_CAP_2GHZ = BIT(11),
- ATH9K_HW_CAP_5GHZ = BIT(12),
-@@ -287,12 +286,12 @@ struct ath9k_ops_config {
- u8 pcie_clock_req;
- u32 pcie_waen;
- u8 analog_shiftreg;
-- u8 paprd_disable;
- u32 ofdm_trig_low;
- u32 ofdm_trig_high;
- u32 cck_trig_high;
- u32 cck_trig_low;
- u32 enable_ani;
-+ u32 enable_paprd;
- int serialize_regmode;
- bool rx_intr_mitigation;
- bool tx_intr_mitigation;
---- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-@@ -2982,6 +2982,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(st
- case EEP_RX_MASK:
- return pBase->txrxMask & 0xf;
- case EEP_PAPRD:
-+ if (AR_SREV_9462(ah))
-+ return false;
-+ if (!ah->config.enable_paprd);
-+ return false;
- return !!(pBase->featureEnable & BIT(5));
- case EEP_CHAIN_MASK_REDUCE:
- return (pBase->miscConfiguration >> 0x3) & 0x1;
---- a/drivers/net/wireless/ath/ath9k/link.c
-+++ b/drivers/net/wireless/ath/ath9k/link.c
-@@ -423,7 +423,7 @@ set_timer:
- cal_interval = min(cal_interval, (u32)short_cal_interval);
-
- mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
-+ if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD) && ah->caldata) {
- if (!ah->caldata->paprd_done)
- ieee80211_queue_work(sc->hw, &sc->paprd_work);
- else if (!ah->paprd_table_write_done)
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -66,8 +66,7 @@ static void ath_tx_update_baw(struct ath
- static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
- struct ath_txq *txq,
- struct ath_atx_tid *tid,
-- struct sk_buff *skb,
-- bool dequeue);
-+ struct sk_buff *skb);
-
- enum {
- MCS_HT20,
-@@ -176,7 +175,15 @@ static void ath_tx_flush_tid(struct ath_
- fi = get_frame_info(skb);
- bf = fi->bf;
-
-- if (bf && fi->retries) {
-+ if (!bf) {
-+ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
-+ if (!bf) {
-+ ieee80211_free_txskb(sc->hw, skb);
-+ continue;
-+ }
-+ }
-+
-+ if (fi->retries) {
- list_add_tail(&bf->list, &bf_head);
- ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
-@@ -789,10 +796,13 @@ static enum ATH_AGGR_STATUS ath_tx_form_
- fi = get_frame_info(skb);
- bf = fi->bf;
- if (!fi->bf)
-- bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);
-+ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
-
-- if (!bf)
-+ if (!bf) {
-+ __skb_unlink(skb, &tid->buf_q);
-+ ieee80211_free_txskb(sc->hw, skb);
- continue;
-+ }
-
- bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
- seqno = bf->bf_state.seqno;
-@@ -1735,9 +1745,11 @@ static void ath_tx_send_ampdu(struct ath
- return;
- }
-
-- bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
-- if (!bf)
-+ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
-+ if (!bf) {
-+ ieee80211_free_txskb(sc->hw, skb);
- return;
-+ }
-
- bf->bf_state.bf_type = BUF_AMPDU;
- INIT_LIST_HEAD(&bf_head);
-@@ -1761,11 +1773,6 @@ static void ath_tx_send_normal(struct at
- struct ath_buf *bf;
-
- bf = fi->bf;
-- if (!bf)
-- bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
--
-- if (!bf)
-- return;
-
- INIT_LIST_HEAD(&bf_head);
- list_add_tail(&bf->list, &bf_head);
-@@ -1839,8 +1846,7 @@ u8 ath_txchainmask_reduction(struct ath_
- static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
- struct ath_txq *txq,
- struct ath_atx_tid *tid,
-- struct sk_buff *skb,
-- bool dequeue)
-+ struct sk_buff *skb)
- {
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_frame_info *fi = get_frame_info(skb);
-@@ -1852,7 +1858,7 @@ static struct ath_buf *ath_tx_setup_buff
- bf = ath_tx_get_buffer(sc);
- if (!bf) {
- ath_dbg(common, XMIT, "TX buffers are full\n");
-- goto error;
-+ return NULL;
- }
-
- ATH_TXBUF_RESET(bf);
-@@ -1881,18 +1887,12 @@ static struct ath_buf *ath_tx_setup_buff
- ath_err(ath9k_hw_common(sc->sc_ah),
- "dma_mapping_error() on TX\n");
- ath_tx_return_buffer(sc, bf);
-- goto error;
-+ return NULL;
- }
-
- fi->bf = bf;
-
- return bf;
--
--error:
-- if (dequeue)
-- __skb_unlink(skb, &tid->buf_q);
-- dev_kfree_skb_any(skb);
-- return NULL;
- }
-
- /* FIXME: tx power */
-@@ -1921,9 +1921,14 @@ static void ath_tx_start_dma(struct ath_
- */
- ath_tx_send_ampdu(sc, tid, skb, txctl);
- } else {
-- bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
-- if (!bf)
-+ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
-+ if (!bf) {
-+ if (txctl->paprd)
-+ dev_kfree_skb_any(skb);
-+ else
-+ ieee80211_free_txskb(sc->hw, skb);
- return;
-+ }
-
- bf->bf_state.bfs_paprd = txctl->paprd;
-
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -775,7 +775,7 @@ static void ath9k_tx(struct ieee80211_hw
-
- return;
- exit:
-- dev_kfree_skb_any(skb);
-+ ieee80211_free_txskb(hw, skb);
- }
-
- static void ath9k_stop(struct ieee80211_hw *hw)
---- a/drivers/net/wireless/ath/ath9k/beacon.c
-+++ b/drivers/net/wireless/ath/ath9k/beacon.c
-@@ -120,7 +120,7 @@ static void ath9k_tx_cabq(struct ieee802
-
- if (ath_tx_start(hw, skb, &txctl) != 0) {
- ath_dbg(common, XMIT, "CABQ TX failed\n");
-- dev_kfree_skb_any(skb);
-+ ieee80211_free_txskb(hw, skb);
- }
- }
-
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1035,6 +1035,10 @@ static bool ar9003_hw_ani_control(struct
- * is_on == 0 means MRC CCK is OFF (more noise imm)
- */
- bool is_on = param ? 1 : 0;
-+
-+ if (ah->caps.rx_chainmask == 1)
-+ break;
-+
- 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,
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -312,6 +312,7 @@ static struct ath_buf *ath_tx_get_buffer
- }
-
- bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
-+ bf->bf_next = NULL;
- list_del(&bf->list);
-
- spin_unlock_bh(&sc->tx.txbuflock);
-@@ -1778,6 +1779,7 @@ static void ath_tx_send_normal(struct at
- list_add_tail(&bf->list, &bf_head);
- bf->bf_state.bf_type = 0;
-
-+ bf->bf_next = NULL;
- bf->bf_lastbf = bf;
- ath_tx_fill_desc(sc, bf, txq, fi->framelen);
- ath_tx_txqaddbuf(sc, txq, &bf_head, false);
+++ /dev/null
---- a/include/linux/ath9k_platform.h
-+++ b/include/linux/ath9k_platform.h
-@@ -31,6 +31,9 @@ struct ath9k_platform_data {
-
- bool endian_check;
- bool is_clk_25mhz;
-+ bool disable_2ghz;
-+ bool disable_5ghz;
-+
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
-
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2413,17 +2413,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw
- }
-
- eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
-- if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
-- ath_err(common,
-- "no band has been marked as supported in EEPROM\n");
-- return -EINVAL;
-+
-+ if (eeval & AR5416_OPFLAGS_11A) {
-+ if (ah->disable_5ghz)
-+ ath_warn(common, "disabling 5GHz band\n");
-+ else
-+ pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
- }
-
-- if (eeval & AR5416_OPFLAGS_11A)
-- pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
-+ if (eeval & AR5416_OPFLAGS_11G) {
-+ if (ah->disable_2ghz)
-+ ath_warn(common, "disabling 2GHz band\n");
-+ else
-+ pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
-+ }
-
-- if (eeval & AR5416_OPFLAGS_11G)
-- pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
-+ if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
-+ ath_err(common, "both bands are disabled\n");
-+ return -EINVAL;
-+ }
-
- if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah))
- chip_chainmask = 1;
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -927,6 +927,8 @@ struct ath_hw {
- bool is_clk_25mhz;
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
-+ bool disable_2ghz;
-+ bool disable_5ghz;
- };
-
- struct ath_bus_ops {
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -537,6 +537,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;
-+ ah->disable_2ghz = pdata->disable_2ghz;
-+ ah->disable_5ghz = pdata->disable_5ghz;
- if (!pdata->endian_check)
- ah->ah_flags |= AH_NO_EEP_SWAP;
- }
+}
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -560,6 +560,7 @@ struct rt2x00lib_ops {
+@@ -561,6 +561,7 @@ struct rt2x00lib_ops {
const u8 *data, const size_t len);
int (*load_firmware) (struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
/*
* Capabilities
-@@ -976,6 +978,11 @@ struct rt2x00_dev {
+@@ -990,6 +992,11 @@ struct rt2x00_dev {
const struct firmware *fw;
/*
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -89,20 +89,10 @@ static void rt2800pci_mcu_status(struct
+@@ -89,20 +89,10 @@ static void rt2800pci_mcu_status(struct
rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
-
- iounmap(base_addr);
--}
++ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
+ }
-#else
-static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
-{
-+ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
- }
+-}
-#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
#ifdef CONFIG_PCI
.get_entry_state = rt2800pci_get_entry_state,
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
-@@ -1163,6 +1163,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
+@@ -1206,6 +1206,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
/*
* Initialize work.
*/
-@@ -1287,6 +1291,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
+@@ -1330,6 +1334,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
*/
if (rt2x00dev->drv_data)
kfree(rt2x00dev->drv_data);
--- a/config.mk
+++ b/config.mk
-@@ -624,6 +624,7 @@ export CONFIG_RT2X00=y
+@@ -630,6 +630,7 @@ export CONFIG_RT2X00=y
export CONFIG_RT2X00_LIB=m
export CONFIG_RT2800_LIB=m
export CONFIG_RT2X00_LIB_FIRMWARE=y
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -89,7 +89,7 @@ static void rt2800pci_mcu_status(struct
+@@ -89,7 +89,7 @@ static void rt2800pci_mcu_status(struct
rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
num_rates += 4;
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -425,6 +425,7 @@ struct hw_mode_spec {
+@@ -426,6 +426,7 @@ struct hw_mode_spec {
unsigned int supported_bands;
#define SUPPORT_BAND_2GHZ 0x00000001
#define SUPPORT_BAND_5GHZ 0x00000002
{
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -1280,6 +1280,7 @@ static inline void rt2x00debug_dump_fram
+@@ -1294,6 +1294,7 @@ static inline void rt2x00debug_dump_fram
*/
u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
--- /dev/null
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -2250,15 +2250,18 @@ static void rt2800_config_channel(struct
+ /*
+ * Change BBP settings
+ */
++ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
++ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
++ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
++
+ if (rt2x00_rt(rt2x00dev, RT3352)) {
+ rt2800_bbp_write(rt2x00dev, 27, 0x0);
+ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 27, 0x20);
+ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
++ rt2800_bbp_write(rt2x00dev, 86, 0x38);
++ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
+ } else {
+- rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+- rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+- rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 86, 0);
+ }
+
+@@ -3890,6 +3893,7 @@ static int rt2800_init_rfcsr(struct rt2x
+ * Init RF calibration.
+ */
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392)) {
+ rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
+@@ -4076,6 +4080,10 @@ static int rt2800_init_rfcsr(struct rt2x
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+ return 0;
+ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
++ int tx0_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX0,
++ &rt2x00dev->cap_flags);
++ int tx1_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX1,
++ &rt2x00dev->cap_flags);
+ rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
+@@ -4109,15 +4117,30 @@ static int rt2800_init_rfcsr(struct rt2x
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+- rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
++ rfcsr = 0x01;
++ if (!tx0_int_pa)
++ rt2x00_set_field8(&rfcsr, RFCSR34_TX0_EXT_PA, 1);
++ if (!tx1_int_pa)
++ rt2x00_set_field8(&rfcsr, RFCSR34_TX1_EXT_PA, 1);
++ rt2800_rfcsr_write(rt2x00dev, 34, rfcsr );
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
+- rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
+- rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
++ rfcsr = 0x52;
++ if (tx0_int_pa) {
++ rt2x00_set_field8(&rfcsr, RFCSR41_BIT1, 1);
++ rt2x00_set_field8(&rfcsr, RFCSR41_BIT4, 1);
++ }
++ rt2800_rfcsr_write(rt2x00dev, 41, rfcsr);
++ rfcsr = 0x52;
++ if (tx1_int_pa) {
++ rt2x00_set_field8(&rfcsr, RFCSR42_BIT1, 1);
++ rt2x00_set_field8(&rfcsr, RFCSR42_BIT4, 1);
++ }
++ rt2800_rfcsr_write(rt2x00dev, 42, rfcsr);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
+@@ -4125,15 +4148,20 @@ static int rt2800_init_rfcsr(struct rt2x
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
+ rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
+- rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
+- rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
+- rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
+- rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
+- rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
+- rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
+- rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
+- rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
+- rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
++ rfcsr = 0x2d;
++ if (!tx0_int_pa)
++ rt2x00_set_field8(&rfcsr, RFCSR50_TX0_EXT_PA, 1);
++ if (!tx1_int_pa)
++ rt2x00_set_field8(&rfcsr, RFCSR50_TX1_EXT_PA, 1);
++ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
++ rt2800_rfcsr_write(rt2x00dev, 51, (tx0_int_pa ? 0x7f : 0x52));
++ rt2800_rfcsr_write(rt2x00dev, 52, (tx0_int_pa ? 0x00 : 0xc0));
++ rt2800_rfcsr_write(rt2x00dev, 53, (tx0_int_pa ? 0x52 : 0xd2));
++ rt2800_rfcsr_write(rt2x00dev, 54, (tx0_int_pa ? 0x1b : 0xc0));
++ rt2800_rfcsr_write(rt2x00dev, 55, (tx1_int_pa ? 0x7f : 0x52));
++ rt2800_rfcsr_write(rt2x00dev, 56, (tx1_int_pa ? 0x00 : 0xc0));
++ rt2800_rfcsr_write(rt2x00dev, 57, (tx0_int_pa ? 0x52 : 0x49));
++ rt2800_rfcsr_write(rt2x00dev, 58, (tx1_int_pa ? 0x1b : 0xc0));
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
+@@ -4894,7 +4922,8 @@ static int rt2800_init_eeprom(struct rt2
+ /*
+ * Detect if this device has Bluetooth co-existence.
+ */
+- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
++ if (!rt2x00_rt(rt2x00dev, RT3352) &&
++ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
+ __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
+
+ /*
+@@ -4923,6 +4952,22 @@ static int rt2800_init_eeprom(struct rt2
+ EIRP_MAX_TX_POWER_LIMIT)
+ __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
+
++ /*
++ * Detect if device uses internal or external PA
++ */
++ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
++
++ if (rt2x00_rt(rt2x00dev, RT3352)) {
++ if (!rt2x00_get_field16(eeprom,
++ EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352))
++ __set_bit(CAPABILITY_INTERNAL_PA_TX0,
++ &rt2x00dev->cap_flags);
++ if (!rt2x00_get_field16(eeprom,
++ EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352))
++ __set_bit(CAPABILITY_INTERNAL_PA_TX1,
++ &rt2x00dev->cap_flags);
++ }
++
+ return 0;
+ }
+
+--- a/drivers/net/wireless/rt2x00/rt2800.h
++++ b/drivers/net/wireless/rt2x00/rt2800.h
+@@ -2117,6 +2117,12 @@ struct mac_iveiv_entry {
+ #define RFCSR31_RX_CALIB FIELD8(0x7f)
+
+ /*
++ * RFCSR 34:
++ */
++#define RFCSR34_TX0_EXT_PA FIELD8(0x04)
++#define RFCSR34_TX1_EXT_PA FIELD8(0x08)
++
++/*
+ * RFCSR 38:
+ */
+ #define RFCSR38_RX_LO1_EN FIELD8(0x20)
+@@ -2127,6 +2133,18 @@ struct mac_iveiv_entry {
+ #define RFCSR39_RX_LO2_EN FIELD8(0x80)
+
+ /*
++ * RFCSR 41:
++ */
++#define RFCSR41_BIT1 FIELD8(0x01)
++#define RFCSR41_BIT4 FIELD8(0x08)
++
++/*
++ * RFCSR 42:
++ */
++#define RFCSR42_BIT1 FIELD8(0x01)
++#define RFCSR42_BIT4 FIELD8(0x08)
++
++/*
+ * RFCSR 49:
+ */
+ #define RFCSR49_TX FIELD8(0x3f)
+@@ -2135,6 +2153,8 @@ struct mac_iveiv_entry {
+ * RFCSR 50:
+ */
+ #define RFCSR50_TX FIELD8(0x3f)
++#define RFCSR50_TX0_EXT_PA FIELD8(0x02)
++#define RFCSR50_TX1_EXT_PA FIELD8(0x10)
+
+ /*
+ * RF registers
+@@ -2222,6 +2242,8 @@ struct mac_iveiv_entry {
+ * INTERNAL_TX_ALC: 0: disable, 1: enable
+ * BT_COEXIST: 0: disable, 1: enable
+ * DAC_TEST: 0: disable, 1: enable
++ * EXTERNAL_TX0_PA: 0: disable, 1: enable (only on RT3352)
++ * EXTERNAL_TX1_PA: 0: disable, 1: enable (only on RT3352)
+ */
+ #define EEPROM_NIC_CONF1 0x001b
+ #define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001)
+@@ -2239,6 +2261,8 @@ struct mac_iveiv_entry {
+ #define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
+ #define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000)
+ #define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000)
++#define EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352 FIELD16(0x4000)
++#define EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352 FIELD16(0x8000)
+
+ /*
+ * EEPROM frequency
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -742,6 +742,8 @@ enum rt2x00_capability_flags {
+ CAPABILITY_DOUBLE_ANTENNA,
+ CAPABILITY_BT_COEXIST,
+ CAPABILITY_VCO_RECALIBRATION,
++ CAPABILITY_INTERNAL_PA_TX0,
++ CAPABILITY_INTERNAL_PA_TX1,
+ };
+
+ /*
--- /dev/null
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -5112,6 +5112,27 @@ static const struct rf_channel rf_vals_3
+ {173, 0x61, 0, 9},
+ };
+
++/*
++ * RF value list for rt3xxx with Xtal20MHz
++ * Supports: 2.4 GHz (all) (RF3322)
++ */
++static const struct rf_channel rf_vals_xtal20mhz_3x[] = {
++ {1, 0xE2, 2, 0x14},
++ {2, 0xE3, 2, 0x14},
++ {3, 0xE4, 2, 0x14},
++ {4, 0xE5, 2, 0x14},
++ {5, 0xE6, 2, 0x14},
++ {6, 0xE7, 2, 0x14},
++ {7, 0xE8, 2, 0x14},
++ {8, 0xE9, 2, 0x14},
++ {9, 0xEA, 2, 0x14},
++ {10, 0xEB, 2, 0x14},
++ {11, 0xEC, 2, 0x14},
++ {12, 0xED, 2, 0x14},
++ {13, 0xEE, 2, 0x14},
++ {14, 0xF0, 2, 0x18},
++};
++
+ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+ {
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+@@ -5190,7 +5211,6 @@ static int rt2800_probe_hw_mode(struct r
+ rt2x00_rf(rt2x00dev, RF3022) ||
+ rt2x00_rf(rt2x00dev, RF3290) ||
+ rt2x00_rf(rt2x00dev, RF3320) ||
+- rt2x00_rf(rt2x00dev, RF3322) ||
+ rt2x00_rf(rt2x00dev, RF5360) ||
+ rt2x00_rf(rt2x00dev, RF5370) ||
+ rt2x00_rf(rt2x00dev, RF5372) ||
+@@ -5198,6 +5218,12 @@ static int rt2800_probe_hw_mode(struct r
+ rt2x00_rf(rt2x00dev, RF5392)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_3x;
++ } else if (rt2x00_rf(rt2x00dev, RF3322)) {
++ spec->num_channels = 14;
++ if (spec->clk_is_20mhz)
++ spec->channels = rf_vals_xtal20mhz_3x;
++ else
++ spec->channels = rf_vals_3x;
+ } else if (rt2x00_rf(rt2x00dev, RF3052)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
+ spec->num_channels = ARRAY_SIZE(rf_vals_3x);
+@@ -5291,6 +5317,19 @@ static int rt2800_probe_hw_mode(struct r
+ return 0;
+ }
+
++int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev)
++{
++ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
++ struct hw_mode_spec *spec = &rt2x00dev->spec;
++
++ if (!pdata)
++ return -EINVAL;
++
++ spec->clk_is_20mhz = pdata->clk_is_20mhz;
++
++ return 0;
++}
++
+ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
+ {
+ int retval;
+@@ -5316,6 +5355,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+ rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
+
+ /*
++ * Probe SoC clock.
++ */
++ if (rt2x00_is_soc(rt2x00dev)) {
++ retval = rt2800_probe_clk(rt2x00dev);
++ if (retval)
++ return retval;
++ }
++
++ /*
+ * Initialize hw specifications.
+ */
+ retval = rt2800_probe_hw_mode(rt2x00dev);
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -421,6 +421,7 @@ static inline struct rt2x00_intf* vif_to
+ * @channels: Device/chipset specific channel values (See &struct rf_channel).
+ * @channels_info: Additional information for channels (See &struct channel_info).
+ * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap).
++ * @clk_is_20mhz: External crystal of WiSoC is 20MHz instead of 40MHz
+ */
+ struct hw_mode_spec {
+ unsigned int supported_bands;
+@@ -437,6 +438,7 @@ struct hw_mode_spec {
+ const struct channel_info *channels_info;
+
+ struct ieee80211_sta_ht_cap ht;
++ int clk_is_20mhz;
+ };
+
+ /*
+--- a/include/linux/rt2x00_platform.h
++++ b/include/linux/rt2x00_platform.h
+@@ -18,6 +18,7 @@ struct rt2x00_platform_data {
+
+ int disable_2ghz;
+ int disable_5ghz;
++ int clk_is_20mhz;
+ };
+
+ #endif /* _RT2X00_PLATFORM_H */
+++ /dev/null
-From 03839951515b0ea2b21d649b1fe7b63f9817d0c8 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <dgolle@allnet.de>
-Date: Sun, 9 Sep 2012 14:24:39 +0300
-Subject: [PATCH] rt2x00: add MediaTek/RaLink Rt3352 WiSoC
-
-Support for the RT3352 WiSoC was developed for and tested with the ALL5002
-devboard running OpenWrt. For now, this supports only devices with internal
-TXALC. Corrections were made according to the remarks of Stanislaw Gruszka and
-Gertjan van Wingerde, thank you guys for reviewing!
-
-Signed-off-by: Daniel Golle <dgolle@allnet.de>
-Signed-off-by: John W. Linville <linville@tuxdriver.com>
----
- drivers/net/wireless/rt2x00/rt2800.h | 5 +
- drivers/net/wireless/rt2x00/rt2800lib.c | 211 +++++++++++++++++++++++++++++++-
- drivers/net/wireless/rt2x00/rt2x00.h | 1 +
- 3 files changed, 212 insertions(+), 5 deletions(-)
-
---- a/drivers/net/wireless/rt2x00/rt2800.h
-+++ b/drivers/net/wireless/rt2x00/rt2800.h
-@@ -1943,6 +1943,11 @@ struct mac_iveiv_entry {
- #define BBP47_TSSI_ADC6 FIELD8(0x80)
-
- /*
-+ * BBP 49
-+ */
-+#define BBP49_UPDATE_FLAG FIELD8(0x01)
-+
-+/*
- * BBP 109
- */
- #define BBP109_TX0_POWER FIELD8(0x0f)
---- a/drivers/net/wireless/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -1615,6 +1615,7 @@ void rt2800_config_ant(struct rt2x00_dev
- case 1:
- if (rt2x00_rt(rt2x00dev, RT3070) ||
- rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT3390)) {
- rt2x00_eeprom_read(rt2x00dev,
- EEPROM_NIC_CONF1, &eeprom);
-@@ -2053,6 +2054,60 @@ static void rt2800_config_channel_rf3290
- }
- }
-
-+static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
-+ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
-+
-+ if (info->default_power1 > POWER_BOUND)
-+ rt2800_rfcsr_write(rt2x00dev, 47, POWER_BOUND);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 47, info->default_power1);
-+
-+ if (info->default_power2 > POWER_BOUND)
-+ rt2800_rfcsr_write(rt2x00dev, 48, POWER_BOUND);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 48, info->default_power2);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
-+ if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
-+ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
-+
-+ if ( rt2x00dev->default_ant.tx_chain_num == 2 )
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
-+
-+ if ( rt2x00dev->default_ant.rx_chain_num == 2 )
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
-+
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 31, 80);
-+}
-+
- static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_conf *conf,
- struct rf_channel *rf,
-@@ -2182,6 +2237,9 @@ static void rt2800_config_channel(struct
- case RF3290:
- rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info);
- break;
-+ case RF3322:
-+ rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info);
-+ break;
- case RF5360:
- case RF5370:
- case RF5372:
-@@ -2194,6 +2252,7 @@ static void rt2800_config_channel(struct
- }
-
- if (rt2x00_rf(rt2x00dev, RF3290) ||
-+ rt2x00_rf(rt2x00dev, RF3322) ||
- rt2x00_rf(rt2x00dev, RF5360) ||
- rt2x00_rf(rt2x00dev, RF5370) ||
- rt2x00_rf(rt2x00dev, RF5372) ||
-@@ -2212,10 +2271,17 @@ static void rt2800_config_channel(struct
- /*
- * Change BBP settings
- */
-- rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
-- rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
-- rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
-- rt2800_bbp_write(rt2x00dev, 86, 0);
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_write(rt2x00dev, 27, 0x0);
-+ rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 27, 0x20);
-+ rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 86, 0);
-+ }
-
- if (rf->channel <= 14) {
- if (!rt2x00_rt(rt2x00dev, RT5390) &&
-@@ -2310,6 +2376,15 @@ static void rt2800_config_channel(struct
- rt2800_register_read(rt2x00dev, CH_IDLE_STA, ®);
- rt2800_register_read(rt2x00dev, CH_BUSY_STA, ®);
- rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®);
-+
-+ /*
-+ * Clear update flag
-+ */
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_read(rt2x00dev, 49, &bbp);
-+ rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0);
-+ rt2800_bbp_write(rt2x00dev, 49, bbp);
-+ }
- }
-
- static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
-@@ -2998,6 +3073,10 @@ static int rt2800_init_registers(struct
- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
- rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030);
-+ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
- } else if (rt2x00_rt(rt2x00dev, RT3572)) {
- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-@@ -3378,6 +3457,11 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_wait_bbp_ready(rt2x00dev)))
- return -EACCES;
-
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_write(rt2x00dev, 3, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 4, 0x50);
-+ }
-+
- if (rt2x00_rt(rt2x00dev, RT3290) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
-@@ -3388,15 +3472,20 @@ static int rt2800_init_bbp(struct rt2x00
-
- if (rt2800_is_305x_soc(rt2x00dev) ||
- rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT3572) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 31, 0x08);
-
-+ if (rt2x00_rt(rt2x00dev, RT3352))
-+ rt2800_bbp_write(rt2x00dev, 47, 0x48);
-+
- rt2800_bbp_write(rt2x00dev, 65, 0x2c);
- rt2800_bbp_write(rt2x00dev, 66, 0x38);
-
- if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 68, 0x0b);
-@@ -3405,6 +3494,7 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_bbp_write(rt2x00dev, 69, 0x16);
- rt2800_bbp_write(rt2x00dev, 73, 0x12);
- } else if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_bbp_write(rt2x00dev, 69, 0x12);
-@@ -3436,6 +3526,10 @@ static int rt2800_init_bbp(struct rt2x00
- } else if (rt2800_is_305x_soc(rt2x00dev)) {
- rt2800_bbp_write(rt2x00dev, 78, 0x0e);
- rt2800_bbp_write(rt2x00dev, 80, 0x08);
-+ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_write(rt2x00dev, 78, 0x0e);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x08);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x37);
- } else {
- rt2800_bbp_write(rt2x00dev, 81, 0x37);
- }
-@@ -3465,18 +3559,21 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_bbp_write(rt2x00dev, 84, 0x99);
-
- if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 86, 0x38);
- else
- rt2800_bbp_write(rt2x00dev, 86, 0x00);
-
-- if (rt2x00_rt(rt2x00dev, RT5392))
-+ if (rt2x00_rt(rt2x00dev, RT3352) ||
-+ rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 88, 0x90);
-
- rt2800_bbp_write(rt2x00dev, 91, 0x04);
-
- if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 92, 0x02);
-@@ -3493,6 +3590,7 @@ static int rt2800_init_bbp(struct rt2x00
- rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
- rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
- rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT3572) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392) ||
-@@ -3502,6 +3600,7 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_bbp_write(rt2x00dev, 103, 0x00);
-
- if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 104, 0x92);
-@@ -3510,6 +3609,8 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_bbp_write(rt2x00dev, 105, 0x01);
- else if (rt2x00_rt(rt2x00dev, RT3290))
- rt2800_bbp_write(rt2x00dev, 105, 0x1c);
-+ else if (rt2x00_rt(rt2x00dev, RT3352))
-+ rt2800_bbp_write(rt2x00dev, 105, 0x34);
- else if (rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 105, 0x3c);
-@@ -3519,11 +3620,16 @@ static int rt2800_init_bbp(struct rt2x00
- if (rt2x00_rt(rt2x00dev, RT3290) ||
- rt2x00_rt(rt2x00dev, RT5390))
- rt2800_bbp_write(rt2x00dev, 106, 0x03);
-+ else if (rt2x00_rt(rt2x00dev, RT3352))
-+ rt2800_bbp_write(rt2x00dev, 106, 0x05);
- else if (rt2x00_rt(rt2x00dev, RT5392))
- rt2800_bbp_write(rt2x00dev, 106, 0x12);
- else
- rt2800_bbp_write(rt2x00dev, 106, 0x35);
-
-+ if (rt2x00_rt(rt2x00dev, RT3352))
-+ rt2800_bbp_write(rt2x00dev, 120, 0x50);
-+
- if (rt2x00_rt(rt2x00dev, RT3290) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
-@@ -3534,6 +3640,9 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_bbp_write(rt2x00dev, 135, 0xf6);
- }
-
-+ if (rt2x00_rt(rt2x00dev, RT3352))
-+ rt2800_bbp_write(rt2x00dev, 137, 0x0f);
-+
- if (rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3090) ||
- rt2x00_rt(rt2x00dev, RT3390) ||
-@@ -3574,6 +3683,28 @@ static int rt2800_init_bbp(struct rt2x00
- rt2800_bbp_write(rt2x00dev, 3, value);
- }
-
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_write(rt2x00dev, 163, 0xbd);
-+ /* Set ITxBF timeout to 0x9c40=1000msec */
-+ rt2800_bbp_write(rt2x00dev, 179, 0x02);
-+ rt2800_bbp_write(rt2x00dev, 180, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 182, 0x40);
-+ rt2800_bbp_write(rt2x00dev, 180, 0x01);
-+ rt2800_bbp_write(rt2x00dev, 182, 0x9c);
-+ rt2800_bbp_write(rt2x00dev, 179, 0x00);
-+ /* Reprogram the inband interface to put right values in RXWI */
-+ rt2800_bbp_write(rt2x00dev, 142, 0x04);
-+ rt2800_bbp_write(rt2x00dev, 143, 0x3b);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x06);
-+ rt2800_bbp_write(rt2x00dev, 143, 0xa0);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x07);
-+ rt2800_bbp_write(rt2x00dev, 143, 0xa1);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x08);
-+ rt2800_bbp_write(rt2x00dev, 143, 0xa2);
-+
-+ rt2800_bbp_write(rt2x00dev, 148, 0xc8);
-+ }
-+
- if (rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
- int ant, div_mode;
-@@ -3707,6 +3838,7 @@ static int rt2800_init_rfcsr(struct rt2x
- !rt2x00_rt(rt2x00dev, RT3071) &&
- !rt2x00_rt(rt2x00dev, RT3090) &&
- !rt2x00_rt(rt2x00dev, RT3290) &&
-+ !rt2x00_rt(rt2x00dev, RT3352) &&
- !rt2x00_rt(rt2x00dev, RT3390) &&
- !rt2x00_rt(rt2x00dev, RT3572) &&
- !rt2x00_rt(rt2x00dev, RT5390) &&
-@@ -3903,6 +4035,70 @@ static int rt2800_init_rfcsr(struct rt2x
- rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
- return 0;
-+ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
-+ rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
-+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
-+ rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
- } else if (rt2x00_rt(rt2x00dev, RT5390)) {
- rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-@@ -4104,6 +4300,7 @@ static int rt2800_init_rfcsr(struct rt2x
- rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
- } else if (rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT3390) ||
- rt2x00_rt(rt2x00dev, RT3572)) {
- drv_data->calibration_bw20 =
-@@ -4566,6 +4763,7 @@ static int rt2800_init_eeprom(struct rt2
- case RT3071:
- case RT3090:
- case RT3290:
-+ case RT3352:
- case RT3390:
- case RT3572:
- case RT5390:
-@@ -4588,6 +4786,7 @@ static int rt2800_init_eeprom(struct rt2
- case RF3052:
- case RF3290:
- case RF3320:
-+ case RF3322:
- case RF5360:
- case RF5370:
- case RF5372:
-@@ -4612,6 +4811,7 @@ static int rt2800_init_eeprom(struct rt2
-
- if (rt2x00_rt(rt2x00dev, RT3070) ||
- rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT3390)) {
- value = rt2x00_get_field16(eeprom,
- EEPROM_NIC_CONF1_ANT_DIVERSITY);
-@@ -4904,6 +5104,7 @@ static int rt2800_probe_hw_mode(struct r
- rt2x00_rf(rt2x00dev, RF3022) ||
- rt2x00_rf(rt2x00dev, RF3290) ||
- rt2x00_rf(rt2x00dev, RF3320) ||
-+ rt2x00_rf(rt2x00dev, RF3322) ||
- rt2x00_rf(rt2x00dev, RF5360) ||
- rt2x00_rf(rt2x00dev, RF5370) ||
- rt2x00_rf(rt2x00dev, RF5372) ||
---- a/drivers/net/wireless/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -189,6 +189,7 @@ struct rt2x00_chip {
- #define RT3071 0x3071
- #define RT3090 0x3090 /* 2.4GHz PCIe */
- #define RT3290 0x3290
-+#define RT3352 0x3352 /* WSOC */
- #define RT3390 0x3390
- #define RT3572 0x3572
- #define RT3593 0x3593
+++ /dev/null
-From d0ae5f33c0221339a50bd1005c569934417003a5 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <dgolle@allnet.de>
-Date: Thu, 4 Oct 2012 00:34:01 +0200
-Subject: [PATCH] rt2x00/rt3352: Fix lnagain assignment to use register 66.
-To: users@rt2x00.serialmonkey.com
-Cc: gwingerde@gmail.com
-
----
- drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -2273,9 +2273,9 @@ static void rt2800_config_channel(struct
- */
- if (rt2x00_rt(rt2x00dev, RT3352)) {
- rt2800_bbp_write(rt2x00dev, 27, 0x0);
-- rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
- rt2800_bbp_write(rt2x00dev, 27, 0x20);
-- rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
- } else {
- rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
- rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+++ /dev/null
---- a/drivers/net/wireless/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -2271,15 +2271,18 @@ static void rt2800_config_channel(struct
- /*
- * Change BBP settings
- */
-+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
-+
- if (rt2x00_rt(rt2x00dev, RT3352)) {
- rt2800_bbp_write(rt2x00dev, 27, 0x0);
- rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
- rt2800_bbp_write(rt2x00dev, 27, 0x20);
- rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
- } else {
-- rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
-- rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
-- rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
- rt2800_bbp_write(rt2x00dev, 86, 0);
- }
-
-@@ -3850,6 +3853,7 @@ static int rt2800_init_rfcsr(struct rt2x
- * Init RF calibration.
- */
- if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
-@@ -4036,6 +4040,10 @@ static int rt2800_init_rfcsr(struct rt2x
- rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
- return 0;
- } else if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ int tx0_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX0,
-+ &rt2x00dev->cap_flags);
-+ int tx1_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX1,
-+ &rt2x00dev->cap_flags);
- rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
- rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
-@@ -4069,15 +4077,30 @@ static int rt2800_init_rfcsr(struct rt2x
- rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-- rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
-+ rfcsr = 0x01;
-+ if (!tx0_int_pa)
-+ rt2x00_set_field8(&rfcsr, RFCSR34_TX0_EXT_PA, 1);
-+ if (!tx1_int_pa)
-+ rt2x00_set_field8(&rfcsr, RFCSR34_TX1_EXT_PA, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 34, rfcsr );
- rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
- rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
- rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
- rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
- rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
-- rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
-- rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
-+ rfcsr = 0x52;
-+ if (tx0_int_pa) {
-+ rt2x00_set_field8(&rfcsr, RFCSR41_BIT1, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR41_BIT4, 1);
-+ }
-+ rt2800_rfcsr_write(rt2x00dev, 41, rfcsr);
-+ rfcsr = 0x52;
-+ if (tx1_int_pa) {
-+ rt2x00_set_field8(&rfcsr, RFCSR42_BIT1, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR42_BIT4, 1);
-+ }
-+ rt2800_rfcsr_write(rt2x00dev, 42, rfcsr);
- rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-@@ -4085,15 +4108,20 @@ static int rt2800_init_rfcsr(struct rt2x
- rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
- rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
- rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
-- rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
-- rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
-- rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
-- rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
-- rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
-- rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
-- rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
-- rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
-- rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
-+ rfcsr = 0x2d;
-+ if (!tx0_int_pa)
-+ rt2x00_set_field8(&rfcsr, RFCSR50_TX0_EXT_PA, 1);
-+ if (!tx1_int_pa)
-+ rt2x00_set_field8(&rfcsr, RFCSR50_TX1_EXT_PA, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
-+ rt2800_rfcsr_write(rt2x00dev, 51, (tx0_int_pa ? 0x7f : 0x52));
-+ rt2800_rfcsr_write(rt2x00dev, 52, (tx0_int_pa ? 0x00 : 0xc0));
-+ rt2800_rfcsr_write(rt2x00dev, 53, (tx0_int_pa ? 0x52 : 0xd2));
-+ rt2800_rfcsr_write(rt2x00dev, 54, (tx0_int_pa ? 0x1b : 0xc0));
-+ rt2800_rfcsr_write(rt2x00dev, 55, (tx1_int_pa ? 0x7f : 0x52));
-+ rt2800_rfcsr_write(rt2x00dev, 56, (tx1_int_pa ? 0x00 : 0xc0));
-+ rt2800_rfcsr_write(rt2x00dev, 57, (tx0_int_pa ? 0x52 : 0x49));
-+ rt2800_rfcsr_write(rt2x00dev, 58, (tx1_int_pa ? 0x1b : 0xc0));
- rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-@@ -4854,7 +4882,8 @@ static int rt2800_init_eeprom(struct rt2
- /*
- * Detect if this device has Bluetooth co-existence.
- */
-- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
-+ if (!rt2x00_rt(rt2x00dev, RT3352) &&
-+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
- __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
-
- /*
-@@ -4883,6 +4912,22 @@ static int rt2800_init_eeprom(struct rt2
- EIRP_MAX_TX_POWER_LIMIT)
- __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
-
-+ /*
-+ * Detect if device uses internal or external PA
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ if (!rt2x00_get_field16(eeprom,
-+ EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352))
-+ __set_bit(CAPABILITY_INTERNAL_PA_TX0,
-+ &rt2x00dev->cap_flags);
-+ if (!rt2x00_get_field16(eeprom,
-+ EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352))
-+ __set_bit(CAPABILITY_INTERNAL_PA_TX1,
-+ &rt2x00dev->cap_flags);
-+ }
-+
- return 0;
- }
-
---- a/drivers/net/wireless/rt2x00/rt2800.h
-+++ b/drivers/net/wireless/rt2x00/rt2800.h
-@@ -2115,6 +2115,12 @@ struct mac_iveiv_entry {
- #define RFCSR31_RX_CALIB FIELD8(0x7f)
-
- /*
-+ * RFCSR 34:
-+ */
-+#define RFCSR34_TX0_EXT_PA FIELD8(0x04)
-+#define RFCSR34_TX1_EXT_PA FIELD8(0x08)
-+
-+/*
- * RFCSR 38:
- */
- #define RFCSR38_RX_LO1_EN FIELD8(0x20)
-@@ -2125,6 +2131,18 @@ struct mac_iveiv_entry {
- #define RFCSR39_RX_LO2_EN FIELD8(0x80)
-
- /*
-+ * RFCSR 41:
-+ */
-+#define RFCSR41_BIT1 FIELD8(0x01)
-+#define RFCSR41_BIT4 FIELD8(0x08)
-+
-+/*
-+ * RFCSR 42:
-+ */
-+#define RFCSR42_BIT1 FIELD8(0x01)
-+#define RFCSR42_BIT4 FIELD8(0x08)
-+
-+/*
- * RFCSR 49:
- */
- #define RFCSR49_TX FIELD8(0x3f)
-@@ -2133,6 +2151,8 @@ struct mac_iveiv_entry {
- * RFCSR 50:
- */
- #define RFCSR50_TX FIELD8(0x3f)
-+#define RFCSR50_TX0_EXT_PA FIELD8(0x02)
-+#define RFCSR50_TX1_EXT_PA FIELD8(0x10)
-
- /*
- * RF registers
-@@ -2220,6 +2240,8 @@ struct mac_iveiv_entry {
- * INTERNAL_TX_ALC: 0: disable, 1: enable
- * BT_COEXIST: 0: disable, 1: enable
- * DAC_TEST: 0: disable, 1: enable
-+ * EXTERNAL_TX0_PA: 0: disable, 1: enable (only on RT3352)
-+ * EXTERNAL_TX1_PA: 0: disable, 1: enable (only on RT3352)
- */
- #define EEPROM_NIC_CONF1 0x001b
- #define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001)
-@@ -2237,6 +2259,8 @@ struct mac_iveiv_entry {
- #define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
- #define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000)
- #define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000)
-+#define EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352 FIELD16(0x4000)
-+#define EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352 FIELD16(0x8000)
-
- /*
- * EEPROM frequency
---- a/drivers/net/wireless/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -743,6 +743,8 @@ enum rt2x00_capability_flags {
- CAPABILITY_DOUBLE_ANTENNA,
- CAPABILITY_BT_COEXIST,
- CAPABILITY_VCO_RECALIBRATION,
-+ CAPABILITY_INTERNAL_PA_TX0,
-+ CAPABILITY_INTERNAL_PA_TX1,
- };
-
- /*
+++ /dev/null
---- a/drivers/net/wireless/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -5072,6 +5072,27 @@ static const struct rf_channel rf_vals_3
- {173, 0x61, 0, 9},
- };
-
-+/*
-+ * RF value list for rt3xxx with Xtal20MHz
-+ * Supports: 2.4 GHz (all) (RF3322)
-+ */
-+static const struct rf_channel rf_vals_xtal20mhz_3x[] = {
-+ {1, 0xE2, 2, 0x14},
-+ {2, 0xE3, 2, 0x14},
-+ {3, 0xE4, 2, 0x14},
-+ {4, 0xE5, 2, 0x14},
-+ {5, 0xE6, 2, 0x14},
-+ {6, 0xE7, 2, 0x14},
-+ {7, 0xE8, 2, 0x14},
-+ {8, 0xE9, 2, 0x14},
-+ {9, 0xEA, 2, 0x14},
-+ {10, 0xEB, 2, 0x14},
-+ {11, 0xEC, 2, 0x14},
-+ {12, 0xED, 2, 0x14},
-+ {13, 0xEE, 2, 0x14},
-+ {14, 0xF0, 2, 0x18},
-+};
-+
- static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
- {
- struct hw_mode_spec *spec = &rt2x00dev->spec;
-@@ -5149,7 +5170,6 @@ static int rt2800_probe_hw_mode(struct r
- rt2x00_rf(rt2x00dev, RF3022) ||
- rt2x00_rf(rt2x00dev, RF3290) ||
- rt2x00_rf(rt2x00dev, RF3320) ||
-- rt2x00_rf(rt2x00dev, RF3322) ||
- rt2x00_rf(rt2x00dev, RF5360) ||
- rt2x00_rf(rt2x00dev, RF5370) ||
- rt2x00_rf(rt2x00dev, RF5372) ||
-@@ -5157,6 +5177,12 @@ static int rt2800_probe_hw_mode(struct r
- rt2x00_rf(rt2x00dev, RF5392)) {
- spec->num_channels = 14;
- spec->channels = rf_vals_3x;
-+ } else if (rt2x00_rf(rt2x00dev, RF3322)) {
-+ spec->num_channels = 14;
-+ if (spec->clk_is_20mhz)
-+ spec->channels = rf_vals_xtal20mhz_3x;
-+ else
-+ spec->channels = rf_vals_3x;
- } else if (rt2x00_rf(rt2x00dev, RF3052)) {
- spec->supported_bands |= SUPPORT_BAND_5GHZ;
- spec->num_channels = ARRAY_SIZE(rf_vals_3x);
-@@ -5250,6 +5276,19 @@ static int rt2800_probe_hw_mode(struct r
- return 0;
- }
-
-+int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
-+ struct hw_mode_spec *spec = &rt2x00dev->spec;
-+
-+ if (!pdata)
-+ return -EINVAL;
-+
-+ spec->clk_is_20mhz = pdata->clk_is_20mhz;
-+
-+ return 0;
-+}
-+
- int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
- {
- int retval;
-@@ -5275,6 +5314,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
- rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
-
- /*
-+ * Probe SoC clock.
-+ */
-+ if (rt2x00_is_soc(rt2x00dev)) {
-+ retval = rt2800_probe_clk(rt2x00dev);
-+ if (retval)
-+ return retval;
-+ }
-+
-+ /*
- * Initialize hw specifications.
- */
- retval = rt2800_probe_hw_mode(rt2x00dev);
---- a/drivers/net/wireless/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -421,6 +421,7 @@ static inline struct rt2x00_intf* vif_to
- * @channels: Device/chipset specific channel values (See &struct rf_channel).
- * @channels_info: Additional information for channels (See &struct channel_info).
- * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap).
-+ * @clk_is_20mhz: External crystal of WiSoC is 20MHz instead of 40MHz
- */
- struct hw_mode_spec {
- unsigned int supported_bands;
-@@ -437,6 +438,7 @@ struct hw_mode_spec {
- const struct channel_info *channels_info;
-
- struct ieee80211_sta_ht_cap ht;
-+ int clk_is_20mhz;
- };
-
- /*
---- a/include/linux/rt2x00_platform.h
-+++ b/include/linux/rt2x00_platform.h
-@@ -18,6 +18,7 @@ struct rt2x00_platform_data {
-
- int disable_2ghz;
- int disable_5ghz;
-+ int clk_is_20mhz;
- };
-
- #endif /* _RT2X00_PLATFORM_H */
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
-@@ -5302,6 +5302,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
+@@ -5320,6 +5320,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
MODULE_PARM_DESC(bad_frames_preempt,
-@@ -2688,10 +2693,10 @@ static int b43_gpio_init(struct b43_wlde
+@@ -2712,10 +2717,10 @@ static int b43_gpio_init(struct b43_wlde
u32 mask, set;
b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0);
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
-@@ -1885,10 +1885,12 @@ static void b43_do_interrupt_thread(stru
+@@ -1909,10 +1909,12 @@ static void b43_do_interrupt_thread(stru
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
-@@ -1529,7 +1529,7 @@ static void b43_write_beacon_template(st
+@@ -1553,7 +1553,7 @@ static void b43_write_beacon_template(st
len, ram_offset, shm_size_offset, rate);
/* Write the PHY TX control parameters. */
antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */
-@@ -3049,8 +3049,8 @@ static int b43_chip_init(struct b43_wlde
+@@ -3073,8 +3073,8 @@ static int b43_chip_init(struct b43_wlde
/* Select the antennae */
if (phy->ops->set_rx_antenna)
if (phy->type == B43_PHYTYPE_B) {
value16 = b43_read16(dev, 0x005E);
-@@ -3794,7 +3794,6 @@ static int b43_op_config(struct ieee8021
+@@ -3818,7 +3818,6 @@ static int b43_op_config(struct ieee8021
struct b43_wldev *dev;
struct b43_phy *phy;
struct ieee80211_conf *conf = &hw->conf;
int err = 0;
bool reload_bss = false;
-@@ -3848,11 +3847,9 @@ static int b43_op_config(struct ieee8021
+@@ -3872,11 +3871,9 @@ static int b43_op_config(struct ieee8021
}
/* Antennas for RX and management frame TX. */
if (wl->radio_enabled != phy->radio_on) {
if (wl->radio_enabled) {
-@@ -4974,6 +4971,47 @@ static int b43_op_get_survey(struct ieee
+@@ -4998,6 +4995,47 @@ static int b43_op_get_survey(struct ieee
return 0;
}
static const struct ieee80211_ops b43_hw_ops = {
.tx = b43_op_tx,
.conf_tx = b43_op_conf_tx,
-@@ -4995,6 +5033,8 @@ static const struct ieee80211_ops b43_hw
+@@ -5019,6 +5057,8 @@ static const struct ieee80211_ops b43_hw
.sw_scan_complete = b43_op_sw_scan_complete_notifier,
.get_survey = b43_op_get_survey,
.rfkill_poll = b43_rfkill_poll,
};
/* Hard-reset the chip. Do not call this directly.
-@@ -5241,6 +5281,8 @@ static int b43_one_core_attach(struct b4
+@@ -5265,6 +5305,8 @@ static int b43_one_core_attach(struct b4
if (!wldev)
goto out;
wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
-@@ -5331,6 +5373,9 @@ static struct b43_wl *b43_wireless_init(
+@@ -5355,6 +5397,9 @@ static struct b43_wl *b43_wireless_init(
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+++ /dev/null
---- a/drivers/net/wireless/b43/main.c
-+++ b/drivers/net/wireless/b43/main.c
-@@ -4645,7 +4645,7 @@ static int b43_wireless_core_init(struct
- switch (dev->dev->bus_type) {
- #ifdef CONFIG_B43_BCMA
- case B43_BUS_BCMA:
-- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
-+ bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
- dev->dev->bdev, true);
- break;
- #endif
---- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
-@@ -697,7 +697,7 @@ void ai_pci_up(struct si_pub *sih)
- sii = container_of(sih, struct si_info, pub);
-
- if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
-- bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
-+ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], true);
- }
-
- /* Unconfigure and/or apply various WARs when going down */
-@@ -708,7 +708,7 @@ void ai_pci_down(struct si_pub *sih)
- sii = container_of(sih, struct si_info, pub);
-
- if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
-- bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
-+ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], false);
- }
-
- /* Enable BT-COEX & Ex-PA for 4313 */
---- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
-@@ -5079,7 +5079,7 @@ static int brcms_b_up_prep(struct brcms_
- * Configure pci/pcmcia here instead of in brcms_c_attach()
- * to allow mfg hotswap: down, hotswap (chip power cycle), up.
- */
-- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
-+ bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
- true);
-
- /*
+++ /dev/null
---- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
-@@ -94,6 +94,7 @@ MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw")
-
- /* recognized BCMA Core IDs */
- static struct bcma_device_id brcms_coreid_table[] = {
-+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
- BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
- BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
---- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
-@@ -734,7 +734,7 @@ static void brcms_c_ucode_bsinit(struct
- brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
-
- /* do band-specific ucode IHR, SHM, and SCR inits */
-- if (D11REV_IS(wlc_hw->corerev, 23)) {
-+ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
- if (BRCMS_ISNPHY(wlc_hw->band))
- brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
- else
-@@ -2259,7 +2259,7 @@ static void brcms_ucode_download(struct
- if (wlc_hw->ucode_loaded)
- return;
-
-- if (D11REV_IS(wlc_hw->corerev, 23)) {
-+ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
- if (BRCMS_ISNPHY(wlc_hw->band)) {
- brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
- ucode->bcm43xx_16_mimosz);
-@@ -3221,7 +3221,7 @@ static void brcms_b_coreinit(struct brcm
-
- sflags = bcma_aread32(core, BCMA_IOST);
-
-- if (D11REV_IS(wlc_hw->corerev, 23)) {
-+ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
- if (BRCMS_ISNPHY(wlc_hw->band))
- brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
- else
--- /dev/null
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -95,6 +95,7 @@ MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw")
+
+ /* recognized BCMA Core IDs */
+ static struct bcma_device_id brcms_coreid_table[] = {
++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -719,7 +719,7 @@ static void brcms_c_ucode_bsinit(struct
+ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
+
+ /* do band-specific ucode IHR, SHM, and SCR inits */
+- if (D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
+ else
+@@ -2266,7 +2266,7 @@ static void brcms_ucode_download(struct
+ if (wlc_hw->ucode_loaded)
+ return;
+
+- if (D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
+ ucode->bcm43xx_16_mimosz);
+@@ -3218,7 +3218,7 @@ static void brcms_b_coreinit(struct brcm
+
+ sflags = bcma_aread32(core, BCMA_IOST);
+
+- if (D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
+ else
+++ /dev/null
---- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
-@@ -4537,7 +4537,8 @@ static int brcms_b_attach(struct brcms_c
-
- /* check device id(srom, nvram etc.) to set bands */
- if (wlc_hw->deviceid == BCM43224_D11N_ID ||
-- wlc_hw->deviceid == BCM43224_D11N_ID_VEN1)
-+ wlc_hw->deviceid == BCM43224_D11N_ID_VEN1 ||
-+ wlc_hw->deviceid == BCM43224_CHIP_ID)
- /* Dualband boards */
- wlc_hw->_nbands = 2;
- else
-@@ -5797,7 +5798,7 @@ static bool brcms_c_chipmatch_pci(struct
- return false;
- }
-
-- if (device == BCM43224_D11N_ID_VEN1)
-+ if (device == BCM43224_D11N_ID_VEN1 || device == BCM43224_CHIP_ID)
- return true;
- if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
- return true;
--- /dev/null
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -4537,7 +4537,8 @@ static int brcms_b_attach(struct brcms_c
+
+ /* check device id(srom, nvram etc.) to set bands */
+ if (wlc_hw->deviceid == BCM43224_D11N_ID ||
+- wlc_hw->deviceid == BCM43224_D11N_ID_VEN1)
++ wlc_hw->deviceid == BCM43224_D11N_ID_VEN1 ||
++ wlc_hw->deviceid == BCM43224_CHIP_ID)
+ /* Dualband boards */
+ wlc_hw->_nbands = 2;
+ else
+@@ -5797,7 +5798,7 @@ static bool brcms_c_chipmatch_pci(struct
+ return false;
+ }
+
+- if (device == BCM43224_D11N_ID_VEN1)
++ if (device == BCM43224_D11N_ID_VEN1 || device == BCM43224_CHIP_ID)
+ return true;
+ if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
+ return true;
+++ /dev/null
---- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
-@@ -97,6 +97,7 @@ static struct bcma_device_id brcms_corei
- BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
- BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
- BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
-+// BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 28, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
- };
- MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
---- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
-@@ -734,7 +734,7 @@ static void brcms_c_ucode_bsinit(struct
- brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
-
- /* do band-specific ucode IHR, SHM, and SCR inits */
-- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
-+ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
- if (BRCMS_ISNPHY(wlc_hw->band))
- brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
- else
-@@ -2259,7 +2259,7 @@ static void brcms_ucode_download(struct
- if (wlc_hw->ucode_loaded)
- return;
-
-- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
-+ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
- if (BRCMS_ISNPHY(wlc_hw->band)) {
- brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
- ucode->bcm43xx_16_mimosz);
-@@ -3221,7 +3221,7 @@ static void brcms_b_coreinit(struct brcm
-
- sflags = bcma_aread32(core, BCMA_IOST);
-
-- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
-+ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
- if (BRCMS_ISNPHY(wlc_hw->band))
- brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
- else
-@@ -5818,6 +5818,8 @@ static bool brcms_c_chipmatch_soc(struct
-
- if (chipinfo->id == BCMA_CHIP_ID_BCM4716)
- return true;
-+ if (chipinfo->id == BCMA_CHIP_ID_BCM5357)
-+ return true;
-
- pr_err("unknown chip id %04x\n", chipinfo->id);
- return false;
---- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
-@@ -65,7 +65,7 @@
- #define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */
-
- /* max # supported core revisions (0 .. MAXCOREREV - 1) */
--#define MAXCOREREV 28
-+#define MAXCOREREV 29
-
- /* Double check that unsupported cores are not enabled */
- #if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV)
---- a/drivers/net/wireless/brcm80211/brcmsmac/types.h
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h
-@@ -93,11 +93,11 @@
- #define BOARD_GPIO_13 0x2000
-
- /* **** Core type/rev defaults **** */
--#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27
-+#define D11CONF 0x1fffffb0 /* Supported D11 revs: 4, 5, 7-27
- * also need to update wlc.h MAXCOREREV
- */
-
--#define NCONF 0x000001ff /* Supported nphy revs:
-+#define NCONF 0x000002ff /* Supported nphy revs:
- * 0 4321a0
- * 1 4321a1
- * 2 4321b0/b1/c0/c1
--- /dev/null
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -98,6 +98,7 @@ static struct bcma_device_id brcms_corei
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
++// BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 28, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+ };
+ MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -719,7 +719,7 @@ static void brcms_c_ucode_bsinit(struct
+ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
+
+ /* do band-specific ucode IHR, SHM, and SCR inits */
+- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
+ else
+@@ -2266,7 +2266,7 @@ static void brcms_ucode_download(struct
+ if (wlc_hw->ucode_loaded)
+ return;
+
+- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
+ ucode->bcm43xx_16_mimosz);
+@@ -3218,7 +3218,7 @@ static void brcms_b_coreinit(struct brcm
+
+ sflags = bcma_aread32(core, BCMA_IOST);
+
+- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
+ else
+@@ -5676,6 +5676,8 @@ static bool brcms_c_chipmatch_soc(struct
+
+ if (chipinfo->id == BCMA_CHIP_ID_BCM4716)
+ return true;
++ if (chipinfo->id == BCMA_CHIP_ID_BCM5357)
++ return true;
+
+ pr_err("unknown chip id %04x\n", chipinfo->id);
+ return false;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -65,7 +65,7 @@
+ #define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */
+
+ /* max # supported core revisions (0 .. MAXCOREREV - 1) */
+-#define MAXCOREREV 28
++#define MAXCOREREV 29
+
+ /* Double check that unsupported cores are not enabled */
+ #if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV)
+--- a/drivers/net/wireless/brcm80211/brcmsmac/types.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h
+@@ -93,11 +93,11 @@
+ #define BOARD_GPIO_13 0x2000
+
+ /* **** Core type/rev defaults **** */
+-#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27
++#define D11CONF 0x1fffffb0 /* Supported D11 revs: 4, 5, 7-27
+ * also need to update wlc.h MAXCOREREV
+ */
+
+-#define NCONF 0x000001ff /* Supported nphy revs:
++#define NCONF 0x000002ff /* Supported nphy revs:
+ * 0 4321a0
+ * 1 4321a1
+ * 2 4321b0/b1/c0/c1