@@ -13,6 +13,36 @@
#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
IEEE80211_RADIOTAP_HE_##f)
+static u8
+mt7921_next_pid(struct mt7921_dev *dev, struct mt76_wcid *wcid)
+{
+ wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK;
+ if (wcid->packet_id == MT_PACKET_ID_NO_ACK ||
+ wcid->packet_id == MT_PACKET_ID_NO_SKB)
+ wcid->packet_id = MT_PACKET_ID_FIRST;
+ return wcid->packet_id;
+}
+
+unsigned long
+mt7921_next_txs_set(struct mt7921_dev *dev, struct mt76_wcid *wcid,
+ u32 timeout)
+{
+ struct mt7921_sta *msta;
+
+ msta = container_of(wcid, struct mt7921_sta, wcid);
+ msta->next_txs_ts = jiffies + msecs_to_jiffies(timeout);
+ return msta->next_txs_ts;
+}
+
+bool
+mt7921_next_txs_timeout(struct mt7921_dev *dev, struct mt76_wcid *wcid)
+{
+ struct mt7921_sta *msta;
+
+ msta = container_of(wcid, struct mt7921_sta, wcid);
+ return time_is_before_jiffies(msta->next_txs_ts);
+}
+
static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev,
u16 idx, bool unicast)
{
@@ -726,7 +756,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
- u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+ u8 pid, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
u16 tx_count = 15;
u32 val;
@@ -795,6 +825,15 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
+
+ if ((FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]) &
+ (IEEE80211_FTYPE_DATA >> 2)) &&
+ mt7921_next_txs_timeout(dev, wcid)) {
+ mt7921_next_txs_set(dev, wcid, 250);
+ pid = mt7921_next_pid(dev, wcid);
+ val = MT_TXD5_TX_STATUS_MCU | FIELD_PREP(MT_TXD5_PID, pid);
+ txwi[5] |= cpu_to_le32(val);
+ }
}
static void
@@ -1380,30 +1419,6 @@ mt7921_mac_update_mib_stats(struct mt7921_phy *phy)
}
}
-static void
-mt7921_mac_sta_stats_work(struct mt7921_phy *phy)
-{
- struct mt7921_dev *dev = phy->dev;
- struct mt7921_sta *msta;
- LIST_HEAD(list);
-
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&phy->stats_list, &list);
-
- while (!list_empty(&list)) {
- msta = list_first_entry(&list, struct mt7921_sta, stats_list);
- list_del_init(&msta->stats_list);
- spin_unlock_bh(&dev->sta_poll_lock);
-
- /* query wtbl info to report tx rate for further devices */
- mt7921_get_wtbl_info(dev, msta->wcid.idx);
-
- spin_lock_bh(&dev->sta_poll_lock);
- }
-
- spin_unlock_bh(&dev->sta_poll_lock);
-}
-
void mt7921_mac_work(struct work_struct *work)
{
struct mt7921_phy *phy;
@@ -1421,10 +1436,6 @@ void mt7921_mac_work(struct work_struct *work)
mt7921_mac_update_mib_stats(phy);
}
- if (++phy->sta_work_count == 4) {
- phy->sta_work_count = 0;
- mt7921_mac_sta_stats_work(phy);
- }
mt7921_mutex_release(phy->dev);
ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
@@ -531,6 +531,49 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb)
trace_lp_event(dev, event->state);
}
+static void
+mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb)
+{
+ struct mt7921_mcu_tx_done_event *event;
+ struct mt7921_sta *msta;
+ struct mt7921_phy *mphy = &dev->phy;
+ struct mt7921_mcu_peer_cap peer;
+ struct ieee80211_sta *sta;
+ LIST_HEAD(list);
+
+ skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
+ event = (struct mt7921_mcu_tx_done_event *)skb->data;
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ list_splice_init(&mphy->stats_list, &list);
+
+ while (!list_empty(&list)) {
+ msta = list_first_entry(&list, struct mt7921_sta, stats_list);
+ list_del_init(&msta->stats_list);
+
+ if (msta->wcid.idx != event->wlan_idx)
+ continue;
+
+ spin_unlock_bh(&dev->sta_poll_lock);
+
+ sta = wcid_to_sta(&msta->wcid);
+
+ /* peer config based on IEEE SPEC */
+ memset(&peer, 0x0, sizeof(peer));
+ peer.bw = event->bw;
+ peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
+ peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
+ peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
+ peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
+ mt7921_mcu_tx_rate_parse(mphy->mt76, &peer,
+ &msta->stats.tx_rate, event->tx_rate);
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ break;
+ }
+ spin_unlock_bh(&dev->sta_poll_lock);
+}
+
static void
mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
@@ -557,6 +600,9 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
case MCU_EVENT_LP_INFO:
mt7921_mcu_low_power_event(dev, skb);
break;
+ case MCU_EVENT_TX_DONE:
+ mt7921_mcu_tx_done_event(dev, skb);
+ break;
default:
break;
}
@@ -577,6 +623,7 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
rxd->eid == MCU_EVENT_BSS_ABSENCE ||
rxd->eid == MCU_EVENT_SCAN_DONE ||
+ rxd->eid == MCU_EVENT_TX_DONE ||
rxd->eid == MCU_EVENT_DBG_MSG ||
rxd->eid == MCU_EVENT_COREDUMP ||
rxd->eid == MCU_EVENT_LP_INFO ||
@@ -81,6 +81,7 @@ enum {
MCU_EVENT_REG_ACCESS = 0x05,
MCU_EVENT_LP_INFO = 0x07,
MCU_EVENT_SCAN_DONE = 0x0d,
+ MCU_EVENT_TX_DONE = 0x0f,
MCU_EVENT_BSS_ABSENCE = 0x11,
MCU_EVENT_BSS_BEACON_LOSS = 0x13,
MCU_EVENT_CH_PRIVILEGE = 0x18,
@@ -407,4 +408,31 @@ struct mt7921_txpwr_event {
struct mt7921_txpwr txpwr;
} __packed;
+struct mt7921_mcu_tx_done_event {
+ u8 pid;
+ u8 status;
+ u16 seq;
+
+ u8 wlan_idx;
+ u8 tx_cnt;
+ u16 tx_rate;
+
+ u8 flag;
+ u8 tid;
+ u8 rsp_rate;
+ u8 mcs;
+
+ u8 bw;
+ u8 tx_pwr;
+ u8 reason;
+ u8 rsv0[1];
+
+ u32 delay;
+ u32 timestamp;
+ u32 applied_flag;
+
+ u8 txs[28];
+
+ u8 rsv1[32];
+} __packed;
#endif
@@ -92,6 +92,8 @@ struct mt7921_sta {
unsigned long ampdu_state;
struct mt7921_sta_key_conf bip;
+
+ unsigned long next_txs_ts;
};
DECLARE_EWMA(rssi, 10, 8);