diff options
author | Arve Hjønnevåg <arve@android.com> | 2010-03-10 16:38:33 -0800 |
---|---|---|
committer | Arve Hjønnevåg <arve@android.com> | 2010-03-10 16:38:33 -0800 |
commit | 67078ecae3edb5b4657dcb9f67f744ecccd18a97 (patch) | |
tree | 90333318a7229fd977881577e0d19fd8e7e26423 /drivers/net/wireless/ath | |
parent | dc136618cb23810dd3d4adfcb836b289cd528b4f (diff) | |
parent | 7f5e918e62cbc9ac27c2f47d3c3dd4b86f67ff0e (diff) |
Merge commit 'v2.6.32.9' into android-2.6.32
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ar9170/usb.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/eeprom.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/eeprom.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/phy.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/reg.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 28 |
13 files changed, 118 insertions, 29 deletions
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index e974e5829e1a..f141a4f711a1 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x1002) }, /* Cace Airpcap NX */ { USB_DEVICE(0xcace, 0x0300) }, - /* D-Link DWA 160A */ + /* D-Link DWA 160 A1 */ { USB_DEVICE(0x07d1, 0x3c10) }, + /* D-Link DWA 160 A2 */ + { USB_DEVICE(0x07d1, 0x3a09) }, /* Netgear WNDA3100 */ { USB_DEVICE(0x0846, 0x9010) }, /* Netgear WN111 v2 */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 95a8e232b58f..8a82c757ea63 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2349,6 +2349,9 @@ ath5k_init(struct ath5k_softc *sc) */ ath5k_stop_locked(sc); + /* Set PHY calibration interval */ + ah->ah_cal_intval = ath5k_calinterval; + /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to @@ -2376,10 +2379,6 @@ ath5k_init(struct ath5k_softc *sc) /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(ah, false); - - /* Set PHY calibration inteval */ - ah->ah_cal_intval = ath5k_calinterval; - ret = 0; done: mmiowb(); diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 644962adda97..9a96550006ad 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -97,6 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; int ret; u16 val; + u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; /* * Read values from EEPROM and store them in the capability structure @@ -111,20 +112,44 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) return 0; -#ifdef notyet /* * Validate the checksum of the EEPROM date. There are some * devices with invalid EEPROMs. */ - for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { + AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val); + if (val) { + eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << + AR5K_EEPROM_SIZE_ENDLOC_SHIFT; + AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val); + eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE; + + /* + * Fail safe check to prevent stupid loops due + * to busted EEPROMs. XXX: This value is likely too + * big still, waiting on a better value. + */ + if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) { + ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: " + "%d (0x%04x) max expected: %d (0x%04x)\n", + eep_max, eep_max, + 3 * AR5K_EEPROM_INFO_MAX, + 3 * AR5K_EEPROM_INFO_MAX); + return -EIO; + } + } + + for (cksum = 0, offset = 0; offset < eep_max; offset++) { AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); cksum ^= val; } if (cksum != AR5K_EEPROM_INFO_CKSUM) { - ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); + ATH5K_ERR(ah->ah_sc, "Invalid EEPROM " + "checksum: 0x%04x eep_max: 0x%04x (%s)\n", + cksum, eep_max, + eep_max == AR5K_EEPROM_INFO_MAX ? + "default size" : "custom size"); return -EIO; } -#endif AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), ee_ant_gain); diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 0123f3521a0b..473a483bb9c3 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -37,6 +37,14 @@ #define AR5K_EEPROM_RFKILL_POLARITY_S 1 #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ + +/* FLASH(EEPROM) Defines for AR531X chips */ +#define AR5K_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */ +#define AR5K_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */ +#define AR5K_EEPROM_SIZE_UPPER_MASK 0xfff0 +#define AR5K_EEPROM_SIZE_UPPER_SHIFT 4 +#define AR5K_EEPROM_SIZE_ENDLOC_SHIFT 12 + #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 1a039f2bd732..9d676474839d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -2954,8 +2954,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); return -EINVAL; } - if (txpower == 0) - txpower = AR5K_TUNE_DEFAULT_TXPOWER; /* Reset TX power values */ memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1d59f10f68da..cdb90c5bf39b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -139,6 +139,7 @@ struct ath_buf { dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ bool bf_stale; + bool bf_isnullfunc; u16 bf_flags; struct ath_buf_state bf_state; dma_addr_t bf_dmacontext; @@ -524,6 +525,8 @@ struct ath_led { #define SC_OP_BEACON_SYNC BIT(19) #define SC_OP_BTCOEX_ENABLED BIT(20) #define SC_OP_BT_PRIORITY_DETECTED BIT(21) +#define SC_OP_NULLFUNC_COMPLETED BIT(22) +#define SC_OP_PS_ENABLED BIT(23) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ca7694caf364..0905b38f7b62 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -880,12 +880,11 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) } } -static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) +static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah) { u32 i, j; - if ((ah->hw_version.devid == AR9280_DEVID_PCI) && - test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { + if (ah->hw_version.devid == AR9280_DEVID_PCI) { /* EEPROM Fixup */ for (i = 0; i < ah->iniModes.ia_rows; i++) { @@ -937,6 +936,11 @@ int ath9k_hw_init(struct ath_hw *ah) DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; + else + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; + if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " @@ -975,7 +979,7 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_mode_gain_regs(ah); ath9k_hw_fill_cap_info(ah); - ath9k_hw_init_11a_eeprom_fix(ah); + ath9k_hw_init_eeprom_fix(ah); r = ath9k_hw_init_macaddr(ah); if (r) { @@ -3670,7 +3674,11 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->keycache_size = AR_KEYTABLE_SIZE; pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; + else + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; if (AR_SREV_9285_10_OR_LATER(ah)) pCap->num_gpio_pins = AR9285_NUM_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b89234571829..ff4383bb3ac3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -218,6 +218,7 @@ struct ath9k_ops_config { #define AR_SPUR_FEEQ_BOUND_HT20 10 int spurmode; u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; + u8 max_txtrig_level; }; enum ath9k_int { @@ -407,7 +408,7 @@ struct ath9k_hw_version { * Using de Bruijin sequence to to look up 1's index in a 32 bit number * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 */ -#define debruijn32 0x077CB531UL +#define debruijn32 0x077CB531U struct ath_gen_timer_configuration { u32 next_addr; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 800bfab94635..110c16dd465c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -70,7 +70,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) u32 txcfg, curLevel, newLevel; enum ath9k_int omask; - if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD) + if (ah->tx_trig_level >= ah->config.max_txtrig_level) return false; omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); @@ -79,7 +79,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) curLevel = MS(txcfg, AR_FTRIG); newLevel = curLevel; if (bIncTrigLevel) { - if (curLevel < MAX_TX_FIFO_THRESHOLD) + if (curLevel < ah->config.max_txtrig_level) newLevel++; } else if (curLevel > MIN_TX_FIFO_THRESHOLD) newLevel--; @@ -155,7 +155,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to stop TX DMA in 100 " "msec after killing last frame\n"); break; @@ -222,6 +222,8 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) ds->ds_txstat.ts_status = 0; ds->ds_txstat.ts_flags = 0; + if (ads->ds_txstatus1 & AR_FrmXmitOK) + ds->ds_txstat.ts_status |= ATH9K_TX_ACKED; if (ads->ds_txstatus1 & AR_ExcessiveRetries) ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; if (ads->ds_txstatus1 & AR_Filtered) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index f56e77da6c3e..9720c4dc9599 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -76,6 +76,10 @@ #define ATH9K_TXERR_FIFO 0x04 #define ATH9K_TXERR_XTXOP 0x08 #define ATH9K_TXERR_TIMER_EXPIRED 0x10 +#define ATH9K_TX_ACKED 0x20 +#define ATH9K_TXERR_MASK \ + (ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO | \ + ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED) #define ATH9K_TX_BA 0x01 #define ATH9K_TX_PWRMGMT 0x02 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 43d2be9867fc..5864eaa53cfc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2147,6 +2147,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } + /* Ensure HW is awake when we try to shut it down. */ + ath9k_ps_wakeup(sc); + if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { ath9k_hw_btcoex_disable(sc->sc_ah); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) @@ -2167,6 +2170,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1); + ath9k_ps_restore(sc); + + /* Finally, put the chip in FULL SLEEP mode */ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; @@ -2277,10 +2283,12 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { + ath9k_ps_wakeup(sc); ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - ath_beacon_return(sc, avp); + ath9k_ps_restore(sc); } + ath_beacon_return(sc, avp); sc->sc_flags &= ~SC_OP_BEACONS; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { @@ -2327,6 +2335,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { + sc->sc_flags |= SC_OP_PS_ENABLED; if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { @@ -2334,11 +2343,17 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); } - ath9k_hw_setrxabort(sc->sc_ah, 1); } sc->ps_enabled = true; + if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + sc->ps_enabled = true; + ath9k_hw_setrxabort(sc->sc_ah, 1); + } } else { sc->ps_enabled = false; + sc->sc_flags &= ~(SC_OP_PS_ENABLED | + SC_OP_NULLFUNC_COMPLETED); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { @@ -2717,15 +2732,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + ath9k_ps_wakeup(sc); ath_tx_aggr_start(sc, sta, tid, ssn); ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP: + ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + ath9k_ps_wakeup(sc); ath_tx_aggr_resume(sc, sta, tid); + ath9k_ps_restore(sc); break; default: DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index d83b77f821e9..c0d7e65bf6d4 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -969,10 +969,10 @@ enum { #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 -#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000 -#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 42551a48c8ac..9009bac9207d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1076,10 +1076,10 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) if (npend) { int r; - DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); if (r) DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", @@ -1563,7 +1563,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); - if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) + if (conf_is_ht(&sc->hw->conf)) bf->bf_state.bf_type |= BUF_HT; bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); @@ -1592,6 +1592,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, } bf->bf_buf_addr = bf->bf_dmacontext; + + if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { + bf->bf_isnullfunc = true; + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + } else + bf->bf_isnullfunc = false; + return 0; } @@ -1641,7 +1648,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, goto tx_done; } - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. @@ -1989,6 +1996,15 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (ds == txq->axq_gatingds) txq->axq_gatingds = NULL; + if (bf->bf_isnullfunc && + (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { + if ((sc->sc_flags & SC_OP_PS_ENABLED)) { + sc->ps_enabled = true; + ath9k_hw_setrxabort(sc->sc_ah, 1); + } else + sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; + } + /* * Remove ath_buf's of the same transmit unit from txq, * however leave the last descriptor back as the holding @@ -2004,7 +2020,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf_isaggr(bf)) txq->axq_aggr_depth--; - txok = (ds->ds_txstat.ts_status == 0); + txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK); txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); @@ -2065,7 +2081,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); + ath9k_ps_wakeup(sc); ath_reset(sc, false); + ath9k_ps_restore(sc); } ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, |