diff --git a/mt7603.h b/mt7603.h index a43124ae..db4562c1 100644 --- a/mt7603.h +++ b/mt7603.h @@ -57,6 +57,8 @@ struct mt7603_vif { struct mt7603_sta { struct mt76_wcid wcid; /* must be first */ + int ampdu_count; + int ampdu_acked; }; struct mt7603_dev { @@ -72,6 +74,7 @@ struct mt7603_dev { u8 vif_mask; unsigned long wcid_mask[MT7603_WTBL_SIZE / BITS_PER_LONG]; + struct mt76_wcid __rcu *wcid[MT7603_WTBL_SIZE]; u8 rx_chains; u8 tx_chains; @@ -121,6 +124,7 @@ static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask) void mt7603_mac_start(struct mt7603_dev *dev); void mt7603_mac_stop(struct mt7603_dev *dev); int mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb); +void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); int mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def); int mt7603_mcu_set_channel(struct mt7603_dev *dev); @@ -134,5 +138,4 @@ void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx); int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta); - #endif diff --git a/mt7603_dma.c b/mt7603_dma.c index ee5acdc1..f9f0f54e 100644 --- a/mt7603_dma.c +++ b/mt7603_dma.c @@ -104,6 +104,10 @@ mt7603_process_rx_skb(struct mt7603_dev *dev, struct mt76_queue *q, type = MT76_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); switch(type) { + case PKT_TYPE_TXS: + mt7603_mac_add_txs(dev, &rxd[1]); + dev_kfree_skb(skb); + break; case PKT_TYPE_RX_EVENT: skb_queue_tail(&dev->mcu.res_q, skb); wake_up(&dev->mcu.wait); @@ -116,6 +120,7 @@ mt7603_process_rx_skb(struct mt7603_dev *dev, struct mt76_queue *q, /* fall through */ default: dev_kfree_skb(skb); + break; } } diff --git a/mt7603_mac.c b/mt7603_mac.c index d47de63d..a9e2305a 100644 --- a/mt7603_mac.c +++ b/mt7603_mac.c @@ -282,6 +282,7 @@ int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, int hdr_len = ieee80211_get_hdrlen_from_skb(skb); u8 frame_type, frame_subtype; u8 nss, bw; + u8 pid = 0; if (wcid) wlan_idx = wcid->idx; @@ -307,8 +308,10 @@ int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, MT76_SET(MT_TXD1_WLAN_IDX, wlan_idx) ); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) + if (info->flags & IEEE80211_TX_CTL_NO_ACK) { txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK); + pid |= BIT(7); + } txwi[2] = cpu_to_le32( MT76_SET(MT_TXD2_FRAME_TYPE, frame_type) | @@ -320,7 +323,10 @@ int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, txwi[3] = cpu_to_le32(MT76_SET(MT_TXD3_REM_TX_COUNT, 0xf)); txwi[4] = 0; - txwi[5] = cpu_to_le32(MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT); + txwi[5] = cpu_to_le32( + MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT | + MT76_SET(MT_TXD5_PID, pid) + ); txwi[6] = 0; spin_lock_bh(&dev->mt76.lock); @@ -350,6 +356,67 @@ int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, return 0; } +void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) +{ + struct ieee80211_tx_info info = {}; + struct ieee80211_sta *sta = NULL; + struct mt7603_sta *msta = NULL; + struct mt76_wcid *wcid; + __le32 *txs_data = data; + void *priv; + bool final_mpdu; + bool ampdu; + u32 txs; + u8 wcidx; + u8 pid; + + txs = le32_to_cpu(txs_data[4]); + pid = MT76_GET(MT_TXS4_PID, txs); + if (pid & BIT(7)) /* No-ACK */ + return; + + final_mpdu = txs & MT_TXS4_ACKED_MPDU; + ampdu = txs & MT_TXS4_AMPDU; + + txs = le32_to_cpu(txs_data[3]); + wcidx = MT76_GET(MT_TXS3_WCID, txs); + + if (wcidx >= ARRAY_SIZE(dev->wcid)) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->wcid[wcidx]); + if (!wcid) + goto out; + + priv = msta = container_of(wcid, struct mt7603_sta, wcid); + sta = container_of(priv, struct ieee80211_sta, drv_priv); + + txs = le32_to_cpu(txs_data[0]); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) { + msta->ampdu_acked++; + info.flags |= IEEE80211_TX_STAT_ACK; + } + + msta->ampdu_count++; + if (ampdu) { + if (!final_mpdu) + return; + + info.flags |= IEEE80211_TX_CTL_AMPDU | IEEE80211_TX_STAT_AMPDU; + info.status.ampdu_len = msta->ampdu_count; + info.status.ampdu_ack_len = msta->ampdu_acked; + } + + ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info); + msta->ampdu_count = 0; + msta->ampdu_acked = 0; + +out: + rcu_read_unlock(); +} + void mt7603_mac_start(struct mt7603_dev *dev) { mt76_clear(dev, MT_WF_ARB_SCR, MT_WF_ARB_TX_DISABLE | MT_WF_ARB_RX_DISABLE);