spin_lock_init(&priv->wmi->wmi_lock);
spin_lock_init(&priv->beacon_lock);
+ spin_lock_init(&priv->tx_lock);
mutex_init(&priv->mutex);
mutex_init(&priv->aggr_work.mutex);
tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
{
struct ieee80211_hdr *hdr;
struct ath9k_htc_priv *priv = hw->priv;
- int padpos, padsize;
+ int padpos, padsize, ret;
hdr = (struct ieee80211_hdr *) skb->data;
memmove(skb->data, skb->data + padsize, padpos);
}
- if (ath9k_htc_tx_start(priv, skb) != 0) {
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Tx failed");
+ ret = ath9k_htc_tx_start(priv, skb);
+ if (ret != 0) {
+ if (ret == -ENOMEM) {
+ ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+ "Stopping TX queues\n");
+ ieee80211_stop_queues(hw);
+ spin_lock_bh(&priv->tx_lock);
+ priv->tx_queues_stop = true;
+ spin_unlock_bh(&priv->tx_lock);
+ } else {
+ ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+ "Tx failed");
+ }
goto fail_tx;
}
priv->op_flags &= ~OP_INVALID;
htc_start(priv->htc);
+ spin_lock_bh(&priv->tx_lock);
+ priv->tx_queues_stop = false;
+ spin_unlock_bh(&priv->tx_lock);
+
+ ieee80211_wake_queues(hw);
+
mutex_unlock:
mutex_unlock(&priv->mutex);
return ret;
/* Send status to mac80211 */
ieee80211_tx_status(priv->hw, skb);
}
+
+ /* Wake TX queues if needed */
+ spin_lock_bh(&priv->tx_lock);
+ if (priv->tx_queues_stop) {
+ priv->tx_queues_stop = false;
+ spin_unlock_bh(&priv->tx_lock);
+ ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+ "Waking up TX queues\n");
+ ieee80211_wake_queues(priv->hw);
+ return;
+ }
+ spin_unlock_bh(&priv->tx_lock);
}
void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,