if (ieee80211_has_a4(hdr->frame_control) &&
sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
return -1;
-@@ -1611,12 +1612,16 @@ __ieee80211_data_to_8023(struct ieee8021
+@@ -1611,11 +1612,13 @@ __ieee80211_data_to_8023(struct ieee8021
return -1;
ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
ehdr = (struct ethhdr *) rx->skb->data;
- if (ehdr->h_proto != rx->sdata->control_port_protocol)
-- return -1;
-+ if (ehdr->h_proto == rx->sdata->control_port_protocol) {
++ if (ehdr->h_proto == rx->sdata->control_port_protocol)
+ *port_control = true;
-+
-+ if (check_port_control)
-+ return -1;
-+ }
++ else if (check_port_control)
+ return -1;
return 0;
- }
-@@ -1916,6 +1921,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
+@@ -1916,6 +1919,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
struct net_device *dev = sdata->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
__le16 fc = hdr->frame_control;
int err;
if (unlikely(!ieee80211_is_data(hdr->frame_control)))
-@@ -1932,13 +1938,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_
+@@ -1932,13 +1936,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_
sdata->vif.type == NL80211_IFTYPE_AP)
return RX_DROP_MONITOR;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -1580,21 +1580,14 @@ ath5k_tx_frame_completed(struct ath5k_so
+ info = IEEE80211_SKB_CB(skb);
+
+ ieee80211_tx_info_clear_status(info);
+- for (i = 0; i < 4; i++) {
++ for (i = 0; i <= ts->ts_final_idx; i++) {
+ struct ieee80211_tx_rate *r =
+ &info->status.rates[i];
+
+- if (ts->ts_rate[i]) {
+- r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]);
+- r->count = ts->ts_retry[i];
+- } else {
+- r->idx = -1;
+- r->count = 0;
+- }
++ r->count = ts->ts_retry[i];
+ }
+
+- /* count the successful attempt as well */
+- info->status.rates[ts->ts_final_idx].count++;
++ info->status.rates[ts->ts_final_idx + 1].idx = -1;
+
+ if (unlikely(ts->ts_status)) {
+ sc->stats.ack_fail++;
+@@ -1609,6 +1602,9 @@ ath5k_tx_frame_completed(struct ath5k_so
+ } else {
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.ack_signal = ts->ts_rssi;
++
++ /* count the successful attempt as well */
++ info->status.rates[ts->ts_final_idx].count++;
+ }
+
+ /*
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1233,7 +1233,7 @@ int ath5k_eeprom_read_mac(struct ath5k_h
+ /* Protocol Control Unit Functions */
+ /* Helpers */
+ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+- int len, struct ieee80211_rate *rate);
++ int len, struct ieee80211_rate *rate, bool shortpre);
+ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
+ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
+ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
+--- a/drivers/net/wireless/ath/ath5k/pcu.c
++++ b/drivers/net/wireless/ath/ath5k/pcu.c
+@@ -75,7 +75,7 @@ static const unsigned int ack_rates_high
+ * bwmodes.
+ */
+ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+- int len, struct ieee80211_rate *rate)
++ int len, struct ieee80211_rate *rate, bool shortpre)
+ {
+ struct ath5k_softc *sc = ah->ah_sc;
+ int sifs, preamble, plcp_bits, sym_time;
+@@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct a
+
+ /* Fallback */
+ if (!ah->ah_bwmode) {
+- dur = ieee80211_generic_frame_duration(sc->hw,
+- NULL, len, rate);
+- return le16_to_cpu(dur);
++ __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw,
++ NULL, len, rate);
++
++ /* subtract difference between long and short preamble */
++ dur = le16_to_cpu(raw_dur);
++ if (shortpre)
++ dur -= 96;
++
++ return dur;
+ }
+
+ bitrate = rate->bitrate;
+@@ -263,27 +269,14 @@ static inline void ath5k_hw_write_rate_d
+ * actual rate for this rate. See mac80211 tx.c
+ * ieee80211_duration() for a brief description of
+ * what rate we should choose to TX ACKs. */
+- tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
++ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
+
+ ath5k_hw_reg_write(ah, tx_time, reg);
+
+ if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
+ continue;
+
+- /*
+- * We're not distinguishing short preamble here,
+- * This is true, all we'll get is a longer value here
+- * which is not necessarilly bad. We could use
+- * export ieee80211_frame_duration() but that needs to be
+- * fixed first to be properly used by mac802111 drivers:
+- *
+- * - remove erp stuff and let the routine figure ofdm
+- * erp rates
+- * - remove passing argument ieee80211_local as
+- * drivers don't have access to it
+- * - move drivers using ieee80211_generic_frame_duration()
+- * to this
+- */
++ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true);
+ ath5k_hw_reg_write(ah, tx_time,
+ reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+ }
+--- a/drivers/net/wireless/ath/ath5k/qcu.c
++++ b/drivers/net/wireless/ath/ath5k/qcu.c
+@@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct at
+ else
+ rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
+
+- ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
++ ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
+
+ /* ack_tx_time includes an SIFS already */
+ eifs = ack_tx_time + sifs + 2 * slot_time;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -224,8 +224,7 @@
+
+ /* SIFS */
+ #define AR5K_INIT_SIFS_TURBO 6
+-/* XXX: 8 from initvals 10 from standard */
+-#define AR5K_INIT_SIFS_DEFAULT_BG 8
++#define AR5K_INIT_SIFS_DEFAULT_BG 10
+ #define AR5K_INIT_SIFS_DEFAULT_A 16
+ #define AR5K_INIT_SIFS_HALF_RATE 32
+ #define AR5K_INIT_SIFS_QUARTER_RATE 64
+--- a/drivers/net/wireless/ath/ath5k/qcu.c
++++ b/drivers/net/wireless/ath/ath5k/qcu.c
+@@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct at
+ return -EINVAL;
+
+ sifs = ath5k_hw_get_default_sifs(ah);
+- sifs_clock = ath5k_hw_htoclock(ah, sifs);
++ sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
+
+ /* EIFS
+ * Txtime of ack at lowest rate + SIFS + DIFS
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1057,6 +1057,7 @@ struct ath5k_hw {
+ u8 ah_coverage_class;
+ bool ah_ack_bitrate_high;
+ u8 ah_bwmode;
++ bool ah_short_slot;
+
+ /* Antenna Control */
+ u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+@@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_
+ if (changes & BSS_CHANGED_BEACON_INT)
+ sc->bintval = bss_conf->beacon_int;
+
++ if (changes & BSS_CHANGED_ERP_SLOT) {
++ int slot_time;
++
++ ah->ah_short_slot = bss_conf->use_short_slot;
++ slot_time = ath5k_hw_get_default_slottime(ah) +
++ 3 * ah->ah_coverage_class;
++ ath5k_hw_set_ifs_intervals(ah, slot_time);
++ }
++
+ if (changes & BSS_CHANGED_ASSOC) {
+ avf->assoc = bss_conf->assoc;
+ if (bss_conf->assoc)
+--- a/drivers/net/wireless/ath/ath5k/pcu.c
++++ b/drivers/net/wireless/ath/ath5k/pcu.c
+@@ -151,9 +151,9 @@ unsigned int ath5k_hw_get_default_slotti
+ slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
+ break;
+ case AR5K_BWMODE_DEFAULT:
+- slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
+ default:
+- if (channel->hw_value & CHANNEL_CCK)
++ slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
++ if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
+ slot_time = AR5K_INIT_SLOT_TIME_B;
+ break;
+ }
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/desc.c
++++ b/drivers/net/wireless/ath/ath5k/desc.c
+@@ -184,6 +184,7 @@ static int ath5k_hw_setup_4word_tx_desc(
+ {
+ struct ath5k_hw_4w_tx_ctl *tx_ctl;
+ unsigned int frame_len;
++ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
+
+ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+@@ -209,7 +210,8 @@ static int ath5k_hw_setup_4word_tx_desc(
+ tx_power = AR5K_TUNE_MAX_TXPOWER;
+
+ /* Clear descriptor */
+- memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
++ memset(&desc->ud.ds_tx5212.tx_stat, 0,
++ sizeof(desc->ud.ds_tx5212.tx_stat));
+
+ /* Setup control descriptor */
+
+@@ -221,7 +223,7 @@ static int ath5k_hw_setup_4word_tx_desc(
+ if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+ return -EINVAL;
+
+- tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
++ txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+ /* Verify and set buffer length */
+
+@@ -232,21 +234,17 @@ static int ath5k_hw_setup_4word_tx_desc(
+ if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+ return -EINVAL;
+
+- tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
++ txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+- tx_ctl->tx_control_0 |=
+- AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+- AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+- tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
+- AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+- tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0,
+- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+- tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
++ txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
++ AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
++ txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
++ txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
++ txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+ #define _TX_FLAGS(_c, _flag) \
+ if (flags & AR5K_TXDESC_##_flag) { \
+- tx_ctl->tx_control_##_c |= \
+- AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
++ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
+ }
+
+ _TX_FLAGS(0, CLRDMASK);
+@@ -262,8 +260,8 @@ static int ath5k_hw_setup_4word_tx_desc(
+ * WEP crap
+ */
+ if (key_index != AR5K_TXKEYIX_INVALID) {
+- tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+- tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
++ txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
++ txctl1 |= AR5K_REG_SM(key_index,
+ AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
+ }
+
+@@ -274,12 +272,16 @@ static int ath5k_hw_setup_4word_tx_desc(
+ if ((flags & AR5K_TXDESC_RTSENA) &&
+ (flags & AR5K_TXDESC_CTSENA))
+ return -EINVAL;
+- tx_ctl->tx_control_2 |= rtscts_duration &
+- AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+- tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
++ txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
++ txctl3 |= AR5K_REG_SM(rtscts_rate,
+ AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+ }
+
++ tx_ctl->tx_control_0 = txctl0;
++ tx_ctl->tx_control_1 = txctl1;
++ tx_ctl->tx_control_2 = txctl2;
++ tx_ctl->tx_control_3 = txctl3;
++
+ return 0;
+ }
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -452,7 +452,6 @@ struct ath5k_tx_status {
+ u16 ts_seqnum;
+ u16 ts_tstamp;
+ u8 ts_status;
+- u8 ts_rate[4];
+ u8 ts_retry[4];
+ u8 ts_final_idx;
+ s8 ts_rssi;
+--- a/drivers/net/wireless/ath/ath5k/desc.c
++++ b/drivers/net/wireless/ath/ath5k/desc.c
+@@ -375,8 +375,6 @@ static int ath5k_hw_proc_2word_tx_status
+ AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+ ts->ts_antenna = 1;
+ ts->ts_status = 0;
+- ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
+- AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+ ts->ts_retry[0] = ts->ts_longretry;
+ ts->ts_final_idx = 0;
+
+@@ -439,32 +437,21 @@ static int ath5k_hw_proc_4word_tx_status
+ ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
+ switch (ts->ts_final_idx) {
+ case 3:
+- ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
+- AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
+-
+ ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+ ts->ts_longretry += ts->ts_retry[2];
+ /* fall through */
+ case 2:
+- ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
+- AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
+-
+ ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+ ts->ts_longretry += ts->ts_retry[1];
+ /* fall through */
+ case 1:
+- ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
+- AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
+-
+ ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+ ts->ts_longretry += ts->ts_retry[0];
+ /* fall through */
+ case 0:
+- ts->ts_rate[0] = tx_ctl->tx_control_3 &
+- AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+ break;
+ }
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/desc.c
++++ b/drivers/net/wireless/ath/ath5k/desc.c
+@@ -401,32 +401,38 @@ static int ath5k_hw_proc_4word_tx_status
+ {
+ struct ath5k_hw_4w_tx_ctl *tx_ctl;
+ struct ath5k_hw_tx_status *tx_status;
++ u32 txstat0, txstat1, txctl2;
+
+ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+ tx_status = &desc->ud.ds_tx5212.tx_stat;
+
++ txstat1 = ACCESS_ONCE(tx_status->tx_status_1);
++
+ /* No frame has been send or error */
+- if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE)))
++ if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
+ return -EINPROGRESS;
+
++ txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
++ txctl2 = ACCESS_ONCE(tx_ctl->tx_control_2);
++
+ /*
+ * Get descriptor status
+ */
+- ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
++ ts->ts_tstamp = AR5K_REG_MS(txstat0,
+ AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+- ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
++ ts->ts_shortretry = AR5K_REG_MS(txstat0,
+ AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
++ ts->ts_longretry = AR5K_REG_MS(txstat0,
+ AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+- ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
++ ts->ts_seqnum = AR5K_REG_MS(txstat1,
+ AR5K_DESC_TX_STATUS1_SEQ_NUM);
+- ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
++ ts->ts_rssi = AR5K_REG_MS(txstat1,
+ AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+- ts->ts_antenna = (tx_status->tx_status_1 &
++ ts->ts_antenna = (txstat1 &
+ AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
+ ts->ts_status = 0;
+
+- ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
++ ts->ts_final_idx = AR5K_REG_MS(txstat1,
+ AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
+
+ /* The longretry counter has the number of un-acked retries
+@@ -437,17 +443,17 @@ static int ath5k_hw_proc_4word_tx_status
+ ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
+ switch (ts->ts_final_idx) {
+ case 3:
+- ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
++ ts->ts_retry[2] = AR5K_REG_MS(txctl2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+ ts->ts_longretry += ts->ts_retry[2];
+ /* fall through */
+ case 2:
+- ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
++ ts->ts_retry[1] = AR5K_REG_MS(txctl2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+ ts->ts_longretry += ts->ts_retry[1];
+ /* fall through */
+ case 1:
+- ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
++ ts->ts_retry[0] = AR5K_REG_MS(txctl2,
+ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+ ts->ts_longretry += ts->ts_retry[0];
+ /* fall through */
+@@ -456,15 +462,14 @@ static int ath5k_hw_proc_4word_tx_status
+ }
+
+ /* TX error */
+- if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+- if (tx_status->tx_status_0 &
+- AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
++ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
++ if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+ ts->ts_status |= AR5K_TXERR_XRETRY;
+
+- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
++ if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+ ts->ts_status |= AR5K_TXERR_FIFO;
+
+- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
++ if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
+ ts->ts_status |= AR5K_TXERR_FILT;
+ }
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/desc.c
++++ b/drivers/net/wireless/ath/ath5k/desc.c
+@@ -603,37 +603,37 @@ static int ath5k_hw_proc_5212_rx_status(
+ struct ath5k_rx_status *rs)
+ {
+ struct ath5k_hw_rx_status *rx_status;
++ u32 rxstat0, rxstat1;
+
+ rx_status = &desc->ud.ds_rx.rx_stat;
++ rxstat1 = ACCESS_ONCE(rx_status->rx_status_1);
+
+ /* No frame received / not ready */
+- if (unlikely(!(rx_status->rx_status_1 &
+- AR5K_5212_RX_DESC_STATUS1_DONE)))
++ if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
+ return -EINPROGRESS;
+
+ memset(rs, 0, sizeof(struct ath5k_rx_status));
++ rxstat0 = ACCESS_ONCE(rx_status->rx_status_0);
+
+ /*
+ * Frame receive status
+ */
+- rs->rs_datalen = rx_status->rx_status_0 &
+- AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+- rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
++ rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
++ rs->rs_rssi = AR5K_REG_MS(rxstat0,
+ AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+- rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
++ rs->rs_rate = AR5K_REG_MS(rxstat0,
+ AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
+- rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
++ rs->rs_antenna = AR5K_REG_MS(rxstat0,
+ AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
+- rs->rs_more = !!(rx_status->rx_status_0 &
+- AR5K_5212_RX_DESC_STATUS0_MORE);
+- rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
++ rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
++ rs->rs_tstamp = AR5K_REG_MS(rxstat1,
+ AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+
+ /*
+ * Key table status
+ */
+- if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
+- rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
++ rs->rs_keyix = AR5K_REG_MS(rxstat1,
+ AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
+ else
+ rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+@@ -641,27 +641,22 @@ static int ath5k_hw_proc_5212_rx_status(
+ /*
+ * Receive/descriptor errors
+ */
+- if (!(rx_status->rx_status_1 &
+- AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+- if (rx_status->rx_status_1 &
+- AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
++ if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+ rs->rs_status |= AR5K_RXERR_CRC;
+
+- if (rx_status->rx_status_1 &
+- AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+ rs->rs_status |= AR5K_RXERR_PHY;
+- rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
++ rs->rs_phyerr = AR5K_REG_MS(rxstat1,
+ AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
+ if (!ah->ah_capabilities.cap_has_phyerr_counters)
+ ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
+ }
+
+- if (rx_status->rx_status_1 &
+- AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+ rs->rs_status |= AR5K_RXERR_DECRYPT;
+
+- if (rx_status->rx_status_1 &
+- AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
++ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+ rs->rs_status |= AR5K_RXERR_MIC;
+ }
+ return 0;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -452,11 +452,10 @@ struct ath5k_tx_status {
+ u16 ts_seqnum;
+ u16 ts_tstamp;
+ u8 ts_status;
+- u8 ts_retry[4];
+ u8 ts_final_idx;
++ u8 ts_final_retry;
+ s8 ts_rssi;
+ u8 ts_shortretry;
+- u8 ts_longretry;
+ u8 ts_virtcol;
+ u8 ts_antenna;
+ };
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -1573,20 +1573,27 @@ ath5k_tx_frame_completed(struct ath5k_so
+ struct ath5k_txq *txq, struct ath5k_tx_status *ts)
+ {
+ struct ieee80211_tx_info *info;
++ u8 tries[3];
+ int i;
+
+ sc->stats.tx_all_count++;
+ sc->stats.tx_bytes_count += skb->len;
+ info = IEEE80211_SKB_CB(skb);
+
++ tries[0] = info->status.rates[0].count;
++ tries[1] = info->status.rates[1].count;
++ tries[2] = info->status.rates[2].count;
++
+ ieee80211_tx_info_clear_status(info);
+- for (i = 0; i <= ts->ts_final_idx; i++) {
++
++ for (i = 0; i < ts->ts_final_idx; i++) {
+ struct ieee80211_tx_rate *r =
+ &info->status.rates[i];
+
+- r->count = ts->ts_retry[i];
++ r->count = tries[i];
+ }
+
++ info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry;
+ info->status.rates[ts->ts_final_idx + 1].idx = -1;
+
+ if (unlikely(ts->ts_status)) {
+--- a/drivers/net/wireless/ath/ath5k/desc.c
++++ b/drivers/net/wireless/ath/ath5k/desc.c
+@@ -366,7 +366,7 @@ static int ath5k_hw_proc_2word_tx_status
+ AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+ ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+ AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
++ ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
+ AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+ /*TODO: ts->ts_virtcol + test*/
+ ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+@@ -375,7 +375,6 @@ static int ath5k_hw_proc_2word_tx_status
+ AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+ ts->ts_antenna = 1;
+ ts->ts_status = 0;
+- ts->ts_retry[0] = ts->ts_longretry;
+ ts->ts_final_idx = 0;
+
+ if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+@@ -401,7 +400,7 @@ static int ath5k_hw_proc_4word_tx_status
+ {
+ struct ath5k_hw_4w_tx_ctl *tx_ctl;
+ struct ath5k_hw_tx_status *tx_status;
+- u32 txstat0, txstat1, txctl2;
++ u32 txstat0, txstat1;
+
+ tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+ tx_status = &desc->ud.ds_tx5212.tx_stat;
+@@ -413,7 +412,6 @@ static int ath5k_hw_proc_4word_tx_status
+ return -EINPROGRESS;
+
+ txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
+- txctl2 = ACCESS_ONCE(tx_ctl->tx_control_2);
+
+ /*
+ * Get descriptor status
+@@ -422,7 +420,7 @@ static int ath5k_hw_proc_4word_tx_status
+ AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+ ts->ts_shortretry = AR5K_REG_MS(txstat0,
+ AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+- ts->ts_longretry = AR5K_REG_MS(txstat0,
++ ts->ts_final_retry = AR5K_REG_MS(txstat0,
+ AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+ ts->ts_seqnum = AR5K_REG_MS(txstat1,
+ AR5K_DESC_TX_STATUS1_SEQ_NUM);
+@@ -435,32 +433,6 @@ static int ath5k_hw_proc_4word_tx_status
+ ts->ts_final_idx = AR5K_REG_MS(txstat1,
+ AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
+
+- /* The longretry counter has the number of un-acked retries
+- * for the final rate. To get the total number of retries
+- * we have to add the retry counters for the other rates
+- * as well
+- */
+- ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
+- switch (ts->ts_final_idx) {
+- case 3:
+- ts->ts_retry[2] = AR5K_REG_MS(txctl2,
+- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+- ts->ts_longretry += ts->ts_retry[2];
+- /* fall through */
+- case 2:
+- ts->ts_retry[1] = AR5K_REG_MS(txctl2,
+- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+- ts->ts_longretry += ts->ts_retry[1];
+- /* fall through */
+- case 1:
+- ts->ts_retry[0] = AR5K_REG_MS(txctl2,
+- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+- ts->ts_longretry += ts->ts_retry[0];
+- /* fall through */
+- case 0:
+- break;
+- }
+-
+ /* TX error */
+ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+ if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/debug.c
++++ b/drivers/net/wireless/ath/ath5k/debug.c
+@@ -888,64 +888,37 @@ static const struct file_operations fops
+ void
+ ath5k_debug_init_device(struct ath5k_softc *sc)
+ {
++ struct dentry *phydir;
++
+ sc->debug.level = ath5k_debug;
+
+- sc->debug.debugfs_phydir = debugfs_create_dir("ath5k",
+- sc->hw->wiphy->debugfsdir);
++ phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir);
++ if (!phydir)
++ return;
+
+- sc->debug.debugfs_debug = debugfs_create_file("debug",
+- S_IWUSR | S_IRUSR,
+- sc->debug.debugfs_phydir, sc, &fops_debug);
+-
+- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
+- sc->debug.debugfs_phydir, sc, &fops_registers);
+-
+- sc->debug.debugfs_beacon = debugfs_create_file("beacon",
+- S_IWUSR | S_IRUSR,
+- sc->debug.debugfs_phydir, sc, &fops_beacon);
+-
+- sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
+- sc->debug.debugfs_phydir, sc, &fops_reset);
+-
+- sc->debug.debugfs_antenna = debugfs_create_file("antenna",
+- S_IWUSR | S_IRUSR,
+- sc->debug.debugfs_phydir, sc, &fops_antenna);
+-
+- sc->debug.debugfs_misc = debugfs_create_file("misc",
+- S_IRUSR,
+- sc->debug.debugfs_phydir, sc, &fops_misc);
+-
+- sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
+- S_IWUSR | S_IRUSR,
+- sc->debug.debugfs_phydir, sc,
+- &fops_frameerrors);
+-
+- sc->debug.debugfs_ani = debugfs_create_file("ani",
+- S_IWUSR | S_IRUSR,
+- sc->debug.debugfs_phydir, sc,
+- &fops_ani);
+-
+- sc->debug.debugfs_queue = debugfs_create_file("queue",
+- S_IWUSR | S_IRUSR,
+- sc->debug.debugfs_phydir, sc,
+- &fops_queue);
+-}
++ debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc,
++ &fops_debug);
+
+-void
+-ath5k_debug_finish_device(struct ath5k_softc *sc)
+-{
+- debugfs_remove(sc->debug.debugfs_debug);
+- debugfs_remove(sc->debug.debugfs_registers);
+- debugfs_remove(sc->debug.debugfs_beacon);
+- debugfs_remove(sc->debug.debugfs_reset);
+- debugfs_remove(sc->debug.debugfs_antenna);
+- debugfs_remove(sc->debug.debugfs_misc);
+- debugfs_remove(sc->debug.debugfs_frameerrors);
+- debugfs_remove(sc->debug.debugfs_ani);
+- debugfs_remove(sc->debug.debugfs_queue);
+- debugfs_remove(sc->debug.debugfs_phydir);
+-}
++ debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers);
++
++ debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc,
++ &fops_beacon);
+
++ debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset);
++
++ debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc,
++ &fops_antenna);
++
++ debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc);
++
++ debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc,
++ &fops_frameerrors);
++
++ debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani);
++
++ debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc,
++ &fops_queue);
++}
+
+ /* functions used in other places */
+
+--- a/drivers/net/wireless/ath/ath5k/debug.h
++++ b/drivers/net/wireless/ath/ath5k/debug.h
+@@ -68,17 +68,6 @@ struct ath5k_buf;
+
+ struct ath5k_dbg_info {
+ unsigned int level; /* debug level */
+- /* debugfs entries */
+- struct dentry *debugfs_phydir;
+- struct dentry *debugfs_debug;
+- struct dentry *debugfs_registers;
+- struct dentry *debugfs_beacon;
+- struct dentry *debugfs_reset;
+- struct dentry *debugfs_antenna;
+- struct dentry *debugfs_misc;
+- struct dentry *debugfs_frameerrors;
+- struct dentry *debugfs_ani;
+- struct dentry *debugfs_queue;
+ };
+
+ /**
+@@ -141,9 +130,6 @@ void
+ ath5k_debug_init_device(struct ath5k_softc *sc);
+
+ void
+-ath5k_debug_finish_device(struct ath5k_softc *sc);
+-
+-void
+ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
+
+ void
+@@ -167,9 +153,6 @@ static inline void
+ ath5k_debug_init_device(struct ath5k_softc *sc) {}
+
+ static inline void
+-ath5k_debug_finish_device(struct ath5k_softc *sc) {}
+-
+-static inline void
+ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
+
+ static inline void
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -2901,7 +2901,6 @@ ath5k_deinit_softc(struct ath5k_softc *s
+ * XXX: ??? detach ath5k_hw ???
+ * Other than that, it's straightforward...
+ */
+- ath5k_debug_finish_device(sc);
+ ieee80211_unregister_hw(hw);
+ ath5k_desc_free(sc);
+ ath5k_txq_release(sc);
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -872,6 +872,19 @@ enum ath5k_int {
+ AR5K_INT_QTRIG = 0x40000000, /* Non common */
+ AR5K_INT_GLOBAL = 0x80000000,
+
++ AR5K_INT_TX_ALL = AR5K_INT_TXOK
++ | AR5K_INT_TXDESC
++ | AR5K_INT_TXERR
++ | AR5K_INT_TXEOL
++ | AR5K_INT_TXURN,
++
++ AR5K_INT_RX_ALL = AR5K_INT_RXOK
++ | AR5K_INT_RXDESC
++ | AR5K_INT_RXERR
++ | AR5K_INT_RXNOFRM
++ | AR5K_INT_RXEOL
++ | AR5K_INT_RXORN,
++
+ AR5K_INT_COMMON = AR5K_INT_RXOK
+ | AR5K_INT_RXDESC
+ | AR5K_INT_RXERR
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_soft
+ }
+
+ static void
++ath5k_set_current_imask(struct ath5k_softc *sc)
++{
++ enum ath5k_int imask = sc->imask;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sc->irqlock, flags);
++ if (sc->rx_pending)
++ imask &= ~AR5K_INT_RX_ALL;
++ if (sc->tx_pending)
++ imask &= ~AR5K_INT_TX_ALL;
++ ath5k_hw_set_imr(sc->ah, imask);
++ spin_unlock_irqrestore(&sc->irqlock, flags);
++}
++
++static void
+ ath5k_tasklet_rx(unsigned long data)
+ {
+ struct ath5k_rx_status rs = {};
+@@ -1506,6 +1521,8 @@ next:
+ } while (ath5k_rxbuf_setup(sc, bf) == 0);
+ unlock:
+ spin_unlock(&sc->rxbuflock);
++ sc->rx_pending = false;
++ ath5k_set_current_imask(sc);
+ }
+
+
+@@ -1693,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
+ for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+ if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
+ ath5k_tx_processq(sc, &sc->txqs[i]);
++
++ sc->tx_pending = false;
++ ath5k_set_current_imask(sc);
+ }
+
+
+@@ -2122,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k
+ * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
+ }
+
++static void
++ath5k_schedule_rx(struct ath5k_softc *sc)
++{
++ sc->rx_pending = true;
++ tasklet_schedule(&sc->rxtq);
++}
++
++static void
++ath5k_schedule_tx(struct ath5k_softc *sc)
++{
++ sc->tx_pending = true;
++ tasklet_schedule(&sc->txtq);
++}
++
+ irqreturn_t
+ ath5k_intr(int irq, void *dev_id)
+ {
+@@ -2164,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
+ ieee80211_queue_work(sc->hw, &sc->reset_work);
+ }
+ else
+- tasklet_schedule(&sc->rxtq);
++ ath5k_schedule_rx(sc);
+ } else {
+ if (status & AR5K_INT_SWBA) {
+ tasklet_hi_schedule(&sc->beacontq);
+@@ -2182,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
+ ath5k_hw_update_tx_triglevel(ah, true);
+ }
+ if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
+- tasklet_schedule(&sc->rxtq);
++ ath5k_schedule_rx(sc);
+ if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
+ | AR5K_INT_TXERR | AR5K_INT_TXEOL))
+- tasklet_schedule(&sc->txtq);
++ ath5k_schedule_tx(sc);
+ if (status & AR5K_INT_BMISS) {
+ /* TODO */
+ }
+@@ -2204,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
+
+ } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
+
++ if (sc->rx_pending || sc->tx_pending)
++ ath5k_set_current_imask(sc);
++
+ if (unlikely(!counter))
+ ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
+
+@@ -2575,6 +2612,8 @@ done:
+
+ static void stop_tasklets(struct ath5k_softc *sc)
+ {
++ sc->rx_pending = false;
++ sc->tx_pending = false;
+ tasklet_kill(&sc->rxtq);
+ tasklet_kill(&sc->txtq);
+ tasklet_kill(&sc->calib);
+--- a/drivers/net/wireless/ath/ath5k/base.h
++++ b/drivers/net/wireless/ath/ath5k/base.h
+@@ -207,6 +207,10 @@ struct ath5k_softc {
+
+ enum ath5k_int imask; /* interrupt mask copy */
+
++ spinlock_t irqlock;
++ bool rx_pending; /* rx tasklet pending */
++ bool tx_pending; /* tx tasklet pending */
++
+ u8 lladdr[ETH_ALEN];
+ u8 bssidmask[ETH_ALEN];
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/caps.c
++++ b/drivers/net/wireless/ath/ath5k/caps.c
+@@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath
+ }
+ }
+
++ if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112)
++ __clear_bit(AR5K_MODE_11A, caps->cap_mode);
++
+ /* Set number of supported TX queues */
+ if (ah->ah_version == AR5K_AR5210)
+ caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -123,14 +123,7 @@ struct ath_ops {
+ };
+
+ struct ath_common;
+-
+-struct ath_bus_ops {
+- enum ath_bus_type ath_bus_type;
+- void (*read_cachesize)(struct ath_common *common, int *csz);
+- bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+- void (*bt_coex_prep)(struct ath_common *common);
+- void (*extn_synch_en)(struct ath_common *common);
+-};
++struct ath_bus_ops;
+
+ struct ath_common {
+ void *ah;
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -847,6 +847,14 @@ struct ath_hw {
+ u32 ent_mode;
+ };
+
++struct ath_bus_ops {
++ enum ath_bus_type ath_bus_type;
++ void (*read_cachesize)(struct ath_common *common, int *csz);
++ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
++ void (*bt_coex_prep)(struct ath_common *common);
++ void (*extn_synch_en)(struct ath_common *common);
++};
++
+ static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
+ {
+ return &ah->common;
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1155,6 +1155,12 @@ struct ath5k_hw {
+ struct ath5k_rx_status *);
+ };
+
++struct ath_bus_ops {
++ enum ath_bus_type ath_bus_type;
++ void (*read_cachesize)(struct ath_common *common, int *csz);
++ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
++};
++
+ /*
+ * Prototypes
+ */
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1159,6 +1159,7 @@ struct ath_bus_ops {
+ enum ath_bus_type ath_bus_type;
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
++ int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac);
+ };
+
+ /*
+@@ -1244,7 +1245,6 @@ int ath5k_hw_dma_stop(struct ath5k_hw *a
+ /* EEPROM access functions */
+ int ath5k_eeprom_init(struct ath5k_hw *ah);
+ void ath5k_eeprom_detach(struct ath5k_hw *ah);
+-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+
+
+ /* Protocol Control Unit Functions */
+--- a/drivers/net/wireless/ath/ath5k/eeprom.c
++++ b/drivers/net/wireless/ath/ath5k/eeprom.c
+@@ -1723,46 +1723,6 @@ ath5k_eeprom_read_spur_chans(struct ath5
+ return ret;
+ }
+
+-/*
+- * Read the MAC address from eeprom or platform_data
+- */
+-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+-{
+- u8 mac_d[ETH_ALEN] = {};
+- u32 total, offset;
+- u16 data;
+- int octet;
+- struct ath5k_platform_data *pdata = NULL;
+-
+- if (ah->ah_sc->pdev)
+- pdata = ah->ah_sc->pdev->dev.platform_data;
+-
+- if (pdata && pdata->macaddr)
+- {
+- memcpy(mac, pdata->macaddr, ETH_ALEN);
+- return 0;
+- }
+-
+- AR5K_EEPROM_READ(0x20, data);
+-
+- for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+- AR5K_EEPROM_READ(offset, data);
+-
+- total += data;
+- mac_d[octet + 1] = data & 0xff;
+- mac_d[octet] = data >> 8;
+- octet += 2;
+- }
+-
+- if (!total || total == 3 * 0xffff)
+- return -EINVAL;
+-
+- memcpy(mac, mac_d, ETH_ALEN);
+-
+- return 0;
+-}
+-
+-
+ /***********************\
+ * Init/Detach functions *
+ \***********************/
+--- a/drivers/net/wireless/ath/ath5k/pci.c
++++ b/drivers/net/wireless/ath/ath5k/pci.c
+@@ -18,6 +18,7 @@
+ #include <linux/pci.h>
+ #include <linux/pci-aspm.h>
+ #include <linux/ath5k_platform.h>
++#include <linux/etherdevice.h>
+ #include "../ath.h"
+ #include "ath5k.h"
+ #include "debug.h"
+@@ -122,11 +123,52 @@ int ath5k_hw_read_srev(struct ath5k_hw *
+ return 0;
+ }
+
++/*
++ * Read the MAC address from eeprom or platform_data
++ */
++static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
++{
++ u8 mac_d[ETH_ALEN] = {};
++ u32 total, offset;
++ u16 data;
++ int octet;
++ struct ath5k_platform_data *pdata = NULL;
++
++ if (ah->ah_sc->pdev)
++ pdata = ah->ah_sc->pdev->dev.platform_data;
++
++ if (pdata && pdata->macaddr)
++ {
++ memcpy(mac, pdata->macaddr, ETH_ALEN);
++ return 0;
++ }
++
++ AR5K_EEPROM_READ(0x20, data);
++
++ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
++ AR5K_EEPROM_READ(offset, data);
++
++ total += data;
++ mac_d[octet + 1] = data & 0xff;
++ mac_d[octet] = data >> 8;
++ octet += 2;
++ }
++
++ if (!total || total == 3 * 0xffff)
++ return -EINVAL;
++
++ memcpy(mac, mac_d, ETH_ALEN);
++
++ return 0;
++}
++
++
+ /* Common ath_bus_opts structure */
+ static const struct ath_bus_ops ath_pci_bus_ops = {
+ .ath_bus_type = ATH_PCI,
+ .read_cachesize = ath5k_pci_read_cachesize,
+ .eeprom_read = ath5k_pci_eeprom_read,
++ .eeprom_read_mac = ath5k_pci_eeprom_read_mac,
+ };
+
+ /********************\
+--- a/drivers/net/wireless/ath/ath5k/ahb.c
++++ b/drivers/net/wireless/ath/ath5k/ahb.c
+@@ -18,6 +18,7 @@
+
+ #include <linux/nl80211.h>
+ #include <linux/platform_device.h>
++#include <linux/etherdevice.h>
+ #include <ar231x_platform.h>
+ #include "ath5k.h"
+ #include "debug.h"
+@@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *
+ return 0;
+ }
+
++static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
++{
++ struct ath5k_softc *sc = ah->ah_sc;
++ struct platform_device *pdev = to_platform_device(sc->dev);
++ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
++ u8 *cfg_mac;
++
++ if (to_platform_device(sc->dev)->id == 0)
++ cfg_mac = bcfg->config->wlan0_mac;
++ else
++ cfg_mac = bcfg->config->wlan1_mac;
++
++ memcpy(mac, cfg_mac, ETH_ALEN);
++ return 0;
++}
++
+ static const struct ath_bus_ops ath_ahb_bus_ops = {
+ .ath_bus_type = ATH_AHB,
+ .read_cachesize = ath5k_ahb_read_cachesize,
+ .eeprom_read = ath5k_ahb_eeprom_read,
++ .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
+ };
+
+ /*Initialization*/
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -2880,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw)
+ INIT_WORK(&sc->reset_work, ath5k_reset_work);
+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
+
+- ret = ath5k_eeprom_read_mac(ah, mac);
++ ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);
+ if (ret) {
+ ATH5K_ERR(sc, "unable to read address from EEPROM\n");
+ goto err_queues;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/attach.c
++++ b/drivers/net/wireless/ath/ath5k/attach.c
+@@ -318,7 +318,7 @@ int ath5k_hw_init(struct ath5k_softc *sc
+ AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
+
+ if (srev >= AR5K_SREV_AR5212_V4 &&
+- (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
++ (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
+ !AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
+ common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath5k/base.h
++++ b/drivers/net/wireless/ath/ath5k/base.h
+@@ -193,12 +193,13 @@ struct ath5k_softc {
+ dma_addr_t desc_daddr; /* DMA (physical) address */
+ size_t desc_len; /* size of TX/RX descriptors */
+
+- DECLARE_BITMAP(status, 5);
++ DECLARE_BITMAP(status, 6);
+ #define ATH_STAT_INVALID 0 /* disable hardware accesses */
+ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
+ #define ATH_STAT_PROMISC 2
+ #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
+ #define ATH_STAT_STARTED 4 /* opened & irqs enabled */
++#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */
+
+ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
+ struct ieee80211_channel *curchan; /* current h/w channel */
+--- a/drivers/net/wireless/ath/ath5k/ahb.c
++++ b/drivers/net/wireless/ath/ath5k/ahb.c
+@@ -160,6 +160,16 @@ static int ath_ahb_probe(struct platform
+ else
+ reg |= AR5K_AR5312_ENABLE_WLAN1;
+ __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
++
++ /*
++ * On a dual-band AR5312, the multiband radio is only
++ * used as pass-through. Disable 2 GHz support in the
++ * driver for it
++ */
++ if (to_platform_device(sc->dev)->id == 0 &&
++ (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) ==
++ (BD_WLAN1|BD_WLAN0))
++ __set_bit(ATH_STAT_2G_DISABLED, sc->status);
+ }
+
+ ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);
+--- a/drivers/net/wireless/ath/ath5k/attach.c
++++ b/drivers/net/wireless/ath/ath5k/attach.c
+@@ -313,6 +313,11 @@ int ath5k_hw_init(struct ath5k_softc *sc
+ goto err;
+ }
+
++ if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) {
++ __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
++ __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
++ }
++
+ /* Crypto settings */
+ common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
+ AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2330,13 +2330,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
+@@ -2328,13 +2328,14 @@ 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_DEAUTH):
case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
-@@ -2716,7 +2717,10 @@ static int prepare_for_handlers(struct i
+@@ -2714,7 +2715,10 @@ static int prepare_for_handlers(struct i
}
break;
case NL80211_IFTYPE_WDS:
IEEE80211_STYPE_ACTION);
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2132,7 +2132,8 @@ ieee80211_rx_h_action(struct ieee80211_r
+@@ -2130,7 +2130,8 @@ ieee80211_rx_h_action(struct ieee80211_r
*/
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
break;
/* verify action_code is present */
-@@ -2717,13 +2718,16 @@ static int prepare_for_handlers(struct i
+@@ -2715,13 +2716,16 @@ static int prepare_for_handlers(struct i
}
break;
case NL80211_IFTYPE_WDS: