ath9k: fix tx queueing issues after background scans
[openwrt.git] / package / kernel / mac80211 / patches / 300-pending_work.patch
index f1a03c7..3f1f7e3 100644 (file)
                break;
        case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
        case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
-@@ -3059,10 +3067,16 @@ static int prepare_for_handlers(struct i
+@@ -3008,6 +3016,9 @@ static int prepare_for_handlers(struct i
+       case NL80211_IFTYPE_ADHOC:
+               if (!bssid)
+                       return 0;
++              if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
++                  ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
++                      return 0;
+               if (ieee80211_is_beacon(hdr->frame_control)) {
+                       return 1;
+               } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
+@@ -3059,10 +3070,16 @@ static int prepare_for_handlers(struct i
                }
                break;
        case NL80211_IFTYPE_WDS:
                }
  
                info.buf_addr[0] = bf->bf_buf_addr;
-@@ -1188,53 +1304,86 @@ static void ath_tx_fill_desc(struct ath_
+@@ -1188,64 +1304,101 @@ static void ath_tx_fill_desc(struct ath_
        }
  }
  
  }
  
  int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
-@@ -1258,6 +1407,9 @@ int ath_tx_aggr_start(struct ath_softc *
+                     u16 tid, u16 *ssn)
+ {
+       struct ath_atx_tid *txtid;
++      struct ath_txq *txq;
+       struct ath_node *an;
+       u8 density;
+       an = (struct ath_node *)sta->drv_priv;
+       txtid = ATH_AN_2_TID(an, tid);
++      txq = txtid->ac->txq;
++
++      ath_txq_lock(sc, txq);
+       /* update ampdu factor/density, they may have changed. This may happen
+        * in HT IBSS when a beacon with HT-info is received after the station
+@@ -1258,6 +1411,9 @@ int ath_tx_aggr_start(struct ath_softc *
                an->mpdudensity = density;
        }
  
        txtid->active = true;
        txtid->paused = true;
        *ssn = txtid->seq_start = txtid->seq_next;
-@@ -1277,8 +1429,9 @@ void ath_tx_aggr_stop(struct ath_softc *
+@@ -1266,6 +1422,8 @@ int ath_tx_aggr_start(struct ath_softc *
+       memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
+       txtid->baw_head = txtid->baw_tail = 0;
++      ath_txq_unlock_complete(sc, txq);
++
+       return 0;
+ }
+@@ -1277,8 +1435,9 @@ void ath_tx_aggr_stop(struct ath_softc *
  
        ath_txq_lock(sc, txq);
        txtid->active = false;
        ath_txq_unlock_complete(sc, txq);
  }
  
-@@ -1302,7 +1455,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
+@@ -1302,7 +1461,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
  
                ath_txq_lock(sc, txq);
  
  
                tid->sched = false;
                list_del(&tid->list);
-@@ -1334,7 +1487,7 @@ void ath_tx_aggr_wakeup(struct ath_softc
+@@ -1334,7 +1493,7 @@ void ath_tx_aggr_wakeup(struct ath_softc
                ath_txq_lock(sc, txq);
                ac->clear_ps_filter = true;
  
                        ath_tx_queue_tid(txq, tid);
                        ath_txq_schedule(sc, txq);
                }
-@@ -1359,7 +1512,7 @@ void ath_tx_aggr_resume(struct ath_softc
+@@ -1359,7 +1518,7 @@ void ath_tx_aggr_resume(struct ath_softc
        tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
        tid->paused = false;
  
                ath_tx_queue_tid(txq, tid);
                ath_txq_schedule(sc, txq);
        }
-@@ -1379,6 +1532,7 @@ void ath9k_release_buffered_frames(struc
+@@ -1379,6 +1538,7 @@ void ath9k_release_buffered_frames(struc
        struct ieee80211_tx_info *info;
        struct list_head bf_q;
        struct ath_buf *bf_tail = NULL, *bf;
        int sent = 0;
        int i;
  
-@@ -1394,15 +1548,15 @@ void ath9k_release_buffered_frames(struc
+@@ -1394,16 +1554,18 @@ void ath9k_release_buffered_frames(struc
                        continue;
  
                ath_txq_lock(sc, tid->ac->txq);
                        list_add_tail(&bf->list, &bf_q);
                        ath_set_rates(tid->an->vif, tid->an->sta, bf);
 -                      ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
-+                      ath_tx_addto_baw(sc, tid, bf);
-                       bf->bf_state.bf_type &= ~BUF_AGGR;
+-                      bf->bf_state.bf_type &= ~BUF_AGGR;
++                      if (bf_isampdu(bf)) {
++                              ath_tx_addto_baw(sc, tid, bf);
++                              bf->bf_state.bf_type &= ~BUF_AGGR;
++                      }
                        if (bf_tail)
                                bf_tail->bf_next = bf;
-@@ -1412,7 +1566,7 @@ void ath9k_release_buffered_frames(struc
+@@ -1412,7 +1574,7 @@ void ath9k_release_buffered_frames(struc
                        sent++;
                        TX_STAT_INC(txq->axq_qnum, a_queued_hw);
  
                                ieee80211_sta_set_buffered(an->sta, i, false);
                }
                ath_txq_unlock_complete(sc, tid->ac->txq);
-@@ -1571,7 +1725,7 @@ static void ath_drain_txq_list(struct at
+@@ -1571,7 +1733,7 @@ static void ath_drain_txq_list(struct at
        while (!list_empty(list)) {
                bf = list_first_entry(list, struct ath_buf, list);
  
                        list_del(&bf->list);
  
                        ath_tx_return_buffer(sc, bf);
-@@ -1665,25 +1819,27 @@ void ath_tx_cleanupq(struct ath_softc *s
+@@ -1665,25 +1827,27 @@ void ath_tx_cleanupq(struct ath_softc *s
   */
  void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
  {
                        tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
                                               list);
                        list_del(&tid->list);
-@@ -1692,17 +1848,17 @@ void ath_txq_schedule(struct ath_softc *
+@@ -1692,17 +1856,17 @@ void ath_txq_schedule(struct ath_softc *
                        if (tid->paused)
                                continue;
  
                                break;
                }
  
-@@ -1711,9 +1867,17 @@ void ath_txq_schedule(struct ath_softc *
+@@ -1711,9 +1875,17 @@ void ath_txq_schedule(struct ath_softc *
                        list_add_tail(&ac->list, &txq->axq_acq);
                }
  
        }
  
        rcu_read_unlock();
-@@ -1792,57 +1956,6 @@ static void ath_tx_txqaddbuf(struct ath_
+@@ -1787,74 +1959,28 @@ static void ath_tx_txqaddbuf(struct ath_
+                       if (bf_is_ampdu_not_probing(bf))
+                               txq->axq_ampdu_depth++;
+-                      bf = bf->bf_lastbf->bf_next;
++                      bf_last = bf->bf_lastbf;
++                      bf = bf_last->bf_next;
++                      bf_last->bf_next = NULL;
+               }
        }
  }
  
  static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
                               struct ath_atx_tid *tid, struct sk_buff *skb)
  {
-@@ -1985,6 +2098,7 @@ static int ath_tx_prepare(struct ieee802
++      struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_frame_info *fi = get_frame_info(skb);
+       struct list_head bf_head;
+-      struct ath_buf *bf;
+-
+-      bf = fi->bf;
++      struct ath_buf *bf = fi->bf;
+       INIT_LIST_HEAD(&bf_head);
+       list_add_tail(&bf->list, &bf_head);
+       bf->bf_state.bf_type = 0;
++      if (tid && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
++              bf->bf_state.bf_type = BUF_AMPDU;
++              ath_tx_addto_baw(sc, tid, bf);
++      }
+       bf->bf_next = NULL;
+       bf->bf_lastbf = bf;
+@@ -1985,6 +2111,7 @@ static int ath_tx_prepare(struct ieee802
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_sta *sta = txctl->sta;
        struct ieee80211_vif *vif = info->control.vif;
        struct ath_softc *sc = hw->priv;
        int frmlen = skb->len + FCS_LEN;
        int padpos, padsize;
-@@ -1992,6 +2106,10 @@ static int ath_tx_prepare(struct ieee802
+@@ -1992,6 +2119,10 @@ static int ath_tx_prepare(struct ieee802
        /* NOTE:  sta can be NULL according to net/mac80211.h */
        if (sta)
                txctl->an = (struct ath_node *)sta->drv_priv;
  
        if (info->control.hw_key)
                frmlen += info->control.hw_key->icv_len;
-@@ -2041,7 +2159,6 @@ int ath_tx_start(struct ieee80211_hw *hw
+@@ -2041,7 +2172,6 @@ int ath_tx_start(struct ieee80211_hw *hw
        struct ath_txq *txq = txctl->txq;
        struct ath_atx_tid *tid = NULL;
        struct ath_buf *bf;
        int q;
        int ret;
  
-@@ -2069,27 +2186,31 @@ int ath_tx_start(struct ieee80211_hw *hw
+@@ -2069,27 +2199,31 @@ int ath_tx_start(struct ieee80211_hw *hw
                ath_txq_unlock(sc, txq);
                txq = sc->tx.uapsdq;
                ath_txq_lock(sc, txq);
                if (txctl->paprd)
                        dev_kfree_skb_any(skb);
                else
-@@ -2142,7 +2263,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
+@@ -2142,7 +2276,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
  
                bf->bf_lastbf = bf;
                ath_set_rates(vif, NULL, bf);
                duration += info.rates[0].PktDuration;
                if (bf_tail)
                        bf_tail->bf_next = bf;
-@@ -2189,7 +2310,7 @@ static void ath_tx_complete(struct ath_s
+@@ -2189,7 +2323,7 @@ static void ath_tx_complete(struct ath_s
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
        unsigned long flags;
  
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
-@@ -2225,21 +2346,7 @@ static void ath_tx_complete(struct ath_s
+@@ -2225,21 +2359,7 @@ static void ath_tx_complete(struct ath_s
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
  
        __skb_queue_tail(&txq->complete_q, skb);
  }
  
  static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-@@ -2360,8 +2467,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2360,8 +2480,7 @@ static void ath_tx_processq(struct ath_s
  
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
                        break;
                }
                bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
-@@ -2375,7 +2481,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2375,7 +2494,7 @@ static void ath_tx_processq(struct ath_s
                 * it with the STALE flag.
                 */
                bf_held = NULL;
                        bf_held = bf;
                        if (list_is_last(&bf_held->list, &txq->axq_q))
                                break;
-@@ -2399,7 +2505,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2399,7 +2518,7 @@ static void ath_tx_processq(struct ath_s
                 * however leave the last descriptor back as the holding
                 * descriptor for hw.
                 */
                INIT_LIST_HEAD(&bf_head);
                if (!list_is_singular(&lastbf->list))
                        list_cut_position(&bf_head,
-@@ -2470,7 +2576,7 @@ void ath_tx_edma_tasklet(struct ath_soft
+@@ -2470,7 +2589,7 @@ void ath_tx_edma_tasklet(struct ath_soft
                }
  
                bf = list_first_entry(fifo_list, struct ath_buf, list);
                        list_del(&bf->list);
                        ath_tx_return_buffer(sc, bf);
                        bf = list_first_entry(fifo_list, struct ath_buf, list);
-@@ -2492,7 +2598,7 @@ void ath_tx_edma_tasklet(struct ath_soft
+@@ -2492,7 +2611,7 @@ void ath_tx_edma_tasklet(struct ath_soft
                                ath_tx_txqaddbuf(sc, txq, &bf_q, true);
                        }
                } else {
                        if (bf != lastbf)
                                list_cut_position(&bf_head, fifo_list,
                                                  lastbf->list.prev);
-@@ -2583,6 +2689,7 @@ void ath_tx_node_init(struct ath_softc *
+@@ -2583,6 +2702,7 @@ void ath_tx_node_init(struct ath_softc *
                tid->paused    = false;
                tid->active        = false;
                __skb_queue_head_init(&tid->buf_q);
                acno = TID_TO_WME_AC(tidno);
                tid->ac = &an->ac[acno];
        }
-@@ -2590,6 +2697,7 @@ void ath_tx_node_init(struct ath_softc *
+@@ -2590,6 +2710,7 @@ void ath_tx_node_init(struct ath_softc *
        for (acno = 0, ac = &an->ac[acno];
             acno < IEEE80211_NUM_ACS; acno++, ac++) {
                ac->sched    = false;
                ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
                                     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
  
-@@ -238,9 +237,6 @@ static bool ath_complete_reset(struct at
+@@ -209,6 +208,7 @@ static bool ath_complete_reset(struct at
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       unsigned long flags;
++      int i;
+       if (ath_startrecv(sc) != 0) {
+               ath_err(common, "Unable to restart recv logic\n");
+@@ -236,10 +236,16 @@ static bool ath_complete_reset(struct at
+               }
+       work:
                ath_restart_work(sc);
-       }
+-      }
  
 -      if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
 -              ath_ant_comb_update(sc);
--
++              for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
++                      if (!ATH_TXQ_SETUP(sc, i))
++                              continue;
++
++                      spin_lock_bh(&sc->tx.txq[i].axq_lock);
++                      ath_txq_schedule(sc, &sc->tx.txq[i]);
++                      spin_unlock_bh(&sc->tx.txq[i].axq_lock);
++              }
++      }
        ieee80211_wake_queues(sc->hw);
  
-       return true;
-@@ -966,6 +962,8 @@ static int ath9k_add_interface(struct ie
+@@ -543,21 +549,10 @@ chip_reset:
+ static int ath_reset(struct ath_softc *sc)
+ {
+-      int i, r;
++      int r;
+       ath9k_ps_wakeup(sc);
+-
+       r = ath_reset_internal(sc, NULL);
+-
+-      for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+-              if (!ATH_TXQ_SETUP(sc, i))
+-                      continue;
+-
+-              spin_lock_bh(&sc->tx.txq[i].axq_lock);
+-              ath_txq_schedule(sc, &sc->tx.txq[i]);
+-              spin_unlock_bh(&sc->tx.txq[i].axq_lock);
+-      }
+-
+       ath9k_ps_restore(sc);
+       return r;
+@@ -966,6 +961,8 @@ static int ath9k_add_interface(struct ie
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
  
        mutex_lock(&sc->mutex);
  
-@@ -979,6 +977,12 @@ static int ath9k_add_interface(struct ie
+@@ -979,6 +976,12 @@ static int ath9k_add_interface(struct ie
        if (ath9k_uses_beacons(vif->type))
                ath9k_beacon_assign_slot(sc, vif);
  
        mutex_unlock(&sc->mutex);
        return 0;
  }
-@@ -1016,6 +1020,7 @@ static void ath9k_remove_interface(struc
+@@ -1016,6 +1019,7 @@ static void ath9k_remove_interface(struc
  {
        struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  
        ath_dbg(common, CONFIG, "Detach Interface\n");
  
-@@ -1030,6 +1035,8 @@ static void ath9k_remove_interface(struc
+@@ -1030,6 +1034,8 @@ static void ath9k_remove_interface(struc
        ath9k_calculate_summary_state(hw, NULL);
        ath9k_ps_restore(sc);
  
        mutex_unlock(&sc->mutex);
  }
  
-@@ -1193,8 +1200,6 @@ static int ath9k_config(struct ieee80211
+@@ -1193,8 +1199,6 @@ static int ath9k_config(struct ieee80211
  
        if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
                struct ieee80211_channel *curchan = hw->conf.chandef.chan;
                int pos = curchan->hw_value;
                int old_pos = -1;
                unsigned long flags;
-@@ -1202,8 +1207,8 @@ static int ath9k_config(struct ieee80211
+@@ -1202,8 +1206,8 @@ static int ath9k_config(struct ieee80211
                if (ah->curchan)
                        old_pos = ah->curchan - &ah->channels[0];
  
  
                /* update survey stats for the old channel before switching */
                spin_lock_irqsave(&common->cc_lock, flags);
-@@ -1211,7 +1216,7 @@ static int ath9k_config(struct ieee80211
+@@ -1211,7 +1215,7 @@ static int ath9k_config(struct ieee80211
                spin_unlock_irqrestore(&common->cc_lock, flags);
  
                ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
  
                /*
                 * If the operating channel changes, change the survey in-use flags
-@@ -1374,9 +1379,6 @@ static void ath9k_sta_notify(struct ieee
+@@ -1374,9 +1378,6 @@ static void ath9k_sta_notify(struct ieee
        struct ath_softc *sc = hw->priv;
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
  
        switch (cmd) {
        case STA_NOTIFY_SLEEP:
                an->sleeping = true;
-@@ -2094,7 +2096,7 @@ static void ath9k_wow_add_pattern(struct
+@@ -2094,7 +2095,7 @@ static void ath9k_wow_add_pattern(struct
  {
        struct ath_hw *ah = sc->sc_ah;
        struct ath9k_wow_pattern *wow_pattern = NULL;
  static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                             struct ieee80211_channel *chan, bool offchan,
                             unsigned int wait, const u8 *buf, size_t len,
+@@ -3332,7 +3514,7 @@ static int ieee80211_probe_client(struct
+               return -EINVAL;
+       }
+       band = chanctx_conf->def.chan->band;
+-      sta = sta_info_get(sdata, peer);
++      sta = sta_info_get_bss(sdata, peer);
+       if (sta) {
+               qos = test_sta_flag(sta, WLAN_STA_WME);
+       } else {
 @@ -3501,4 +3683,5 @@ struct cfg80211_ops mac80211_config_ops 
        .get_et_strings = ieee80211_get_et_strings,
        .get_channel = ieee80211_cfg_get_channel,
  #define TRACE_SYSTEM mac80211_msg
 --- a/net/mac80211/tx.c
 +++ b/net/mac80211/tx.c
-@@ -2326,6 +2326,81 @@ static int ieee80211_beacon_add_tim(stru
+@@ -1101,7 +1101,8 @@ ieee80211_tx_prepare(struct ieee80211_su
+               tx->sta = rcu_dereference(sdata->u.vlan.sta);
+               if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
+                       return TX_DROP;
+-      } else if (info->flags & IEEE80211_TX_CTL_INJECTED ||
++      } else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
++                                IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
+                  tx->sdata->control_port_protocol == tx->skb->protocol) {
+               tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+       }
+@@ -2326,6 +2327,81 @@ static int ieee80211_beacon_add_tim(stru
        return 0;
  }
  
  struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                                         struct ieee80211_vif *vif,
                                         u16 *tim_offset, u16 *tim_length)
-@@ -2356,6 +2431,9 @@ struct sk_buff *ieee80211_beacon_get_tim
+@@ -2356,6 +2432,9 @@ struct sk_buff *ieee80211_beacon_get_tim
                struct beacon_data *beacon = rcu_dereference(ap->beacon);
  
                if (beacon) {
  #define AR_SREV_9485_OR_LATER(_ah) \
        (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
  
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -101,7 +101,7 @@ static u32 ieee80211_hw_conf_chan(struct
+       struct ieee80211_sub_if_data *sdata;
+       struct cfg80211_chan_def chandef = {};
+       u32 changed = 0;
+-      int power;
++      int power = 0;
+       u32 offchannel_flag;
+       offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
+@@ -155,16 +155,16 @@ static u32 ieee80211_hw_conf_chan(struct
+               changed |= IEEE80211_CONF_CHANGE_SMPS;
+       }
+-      power = chandef.chan->max_power;
+-
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!rcu_access_pointer(sdata->vif.chanctx_conf))
+                       continue;
+-              power = min(power, sdata->vif.bss_conf.txpower);
++              power = max(power, sdata->vif.bss_conf.txpower);
+       }
+       rcu_read_unlock();
++      power = min(power, chandef.chan->max_power);
++
+       if (local->hw.conf.power_level != power) {
+               changed |= IEEE80211_CONF_CHANGE_POWER;
+               local->hw.conf.power_level = power;
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -180,6 +180,9 @@ static void ieee80211_frame_acked(struct
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
++      if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
++              sta->last_rx = jiffies;
++
+       if (ieee80211_is_data_qos(mgmt->frame_control)) {
+               struct ieee80211_hdr *hdr = (void *) skb->data;
+               u8 *qc = ieee80211_get_qos_ctl(hdr);