mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
mt7603: implement rudimentary skb tx status reporting
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
@@ -49,16 +49,29 @@ struct mt7603_mcu {
|
||||
bool running;
|
||||
};
|
||||
|
||||
struct mt7603_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
int pid;
|
||||
|
||||
int ampdu_count;
|
||||
int ampdu_acked;
|
||||
};
|
||||
|
||||
struct mt7603_vif {
|
||||
u8 idx;
|
||||
|
||||
struct mt76_wcid group_wcid;
|
||||
struct mt7603_sta sta;
|
||||
};
|
||||
|
||||
struct mt7603_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
int ampdu_count;
|
||||
int ampdu_acked;
|
||||
#define MT7603_CB_DMA_DONE BIT(0)
|
||||
#define MT7603_CB_TXS_DONE BIT(1)
|
||||
|
||||
struct mt7603_cb {
|
||||
struct list_head list;
|
||||
u8 wcid;
|
||||
u8 pktid;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct mt7603_dev {
|
||||
@@ -76,6 +89,11 @@ struct mt7603_dev {
|
||||
unsigned long wcid_mask[MT7603_WTBL_SIZE / BITS_PER_LONG];
|
||||
struct mt76_wcid __rcu *wcid[MT7603_WTBL_SIZE];
|
||||
|
||||
spinlock_t status_lock;
|
||||
struct list_head status_list;
|
||||
|
||||
struct mt7603_sta global_sta;
|
||||
|
||||
u8 rx_chains;
|
||||
u8 tx_chains;
|
||||
|
||||
@@ -90,12 +108,29 @@ struct mt7603_dev {
|
||||
|
||||
extern const struct ieee80211_ops mt7603_ops;
|
||||
|
||||
static inline struct mt7603_cb *mt7603_skb_cb(struct sk_buff *skb)
|
||||
{
|
||||
return (void *) IEEE80211_SKB_CB(skb)->rate_driver_data;
|
||||
}
|
||||
|
||||
static inline struct sk_buff *mt7603_cb_skb(struct mt7603_cb *cb)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
void *ptr = cb;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*cb) > sizeof(info->rate_driver_data));
|
||||
info = container_of(ptr, struct ieee80211_tx_info, rate_driver_data);
|
||||
ptr = info;
|
||||
return container_of(ptr, struct sk_buff, cb);
|
||||
}
|
||||
|
||||
u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr);
|
||||
|
||||
struct mt7603_dev *mt7603_alloc_device(struct device *pdev);
|
||||
irqreturn_t mt7603_irq_handler(int irq, void *dev_instance);
|
||||
|
||||
int mt7603_register_device(struct mt7603_dev *dev);
|
||||
void mt7603_unregister_device(struct mt7603_dev *dev);
|
||||
int mt7603_dma_init(struct mt7603_dev *dev);
|
||||
void mt7603_dma_cleanup(struct mt7603_dev *dev);
|
||||
int mt7603_mcu_init(struct mt7603_dev *dev);
|
||||
@@ -118,6 +153,8 @@ 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);
|
||||
struct sk_buff *mt7603_mac_status_skb(struct mt7603_dev *dev,
|
||||
struct mt7603_sta *sta, int pktid);
|
||||
|
||||
int mt7603_mcu_set_channel(struct mt7603_dev *dev);
|
||||
int mt7603_mcu_reg_read(struct mt7603_dev *dev, u32 reg, u32 *val, bool rf);
|
||||
|
||||
@@ -211,6 +211,9 @@ mt7603_mac_init(struct mt7603_dev *dev)
|
||||
|
||||
eth_broadcast_addr(bc_addr);
|
||||
mt7603_wtbl_init(dev, MT7603_WTBL_RESERVED, bc_addr);
|
||||
dev->global_sta.wcid.idx = MT7603_WTBL_RESERVED;
|
||||
rcu_assign_pointer(dev->wcid[MT7603_WTBL_RESERVED],
|
||||
&dev->global_sta.wcid);
|
||||
|
||||
mt76_rmw_field(dev, MT_LPON_BTEIR, MT_LPON_BTEIR_MBSS_MODE, 2);
|
||||
mt76_rmw_field(dev, MT_WF_RMACDR, MT_WF_RMACDR_MBSSID_MASK, 2);
|
||||
@@ -324,6 +327,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
||||
int ret;
|
||||
|
||||
mutex_init(&dev->mutex);
|
||||
spin_lock_init(&dev->status_lock);
|
||||
INIT_LIST_HEAD(&dev->status_list);
|
||||
|
||||
dev->rx_chains = 2;
|
||||
dev->tx_chains = 2;
|
||||
@@ -344,6 +349,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
||||
wiphy->iface_combinations = if_comb;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
|
||||
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
|
||||
|
||||
ret = mt76_register_device(&dev->mt76, true, mt7603_rates,
|
||||
ARRAY_SIZE(mt7603_rates));
|
||||
if (ret)
|
||||
@@ -356,3 +363,12 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt7603_unregister_device(struct mt7603_dev *dev)
|
||||
{
|
||||
mt7603_mac_status_skb(dev, NULL, -1);
|
||||
mt76_unregister_device(&dev->mt76);
|
||||
mt7603_mcu_exit(dev);
|
||||
mt7603_dma_cleanup(dev);
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
}
|
||||
|
||||
+154
-33
@@ -340,7 +340,7 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, int wcid,
|
||||
static int
|
||||
mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta)
|
||||
struct ieee80211_sta *sta, int pid)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *rate = &info->control.rates[0];
|
||||
@@ -348,7 +348,6 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
|
||||
int wlan_idx;
|
||||
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
|
||||
u8 frame_type, frame_subtype;
|
||||
u8 pid = 0;
|
||||
u8 bw;
|
||||
|
||||
if (wcid)
|
||||
@@ -377,7 +376,7 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
|
||||
txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK);
|
||||
pid |= BIT(7);
|
||||
pid |= MT_PID_NOACK;
|
||||
}
|
||||
|
||||
txwi[2] = cpu_to_le32(
|
||||
@@ -426,10 +425,131 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
struct ieee80211_sta *sta, u32 *tx_info)
|
||||
{
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
mt7603_mac_write_txwi(dev, txwi_ptr, skb, wcid, sta);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid);
|
||||
struct mt7603_cb *cb = mt7603_skb_cb(skb);
|
||||
int pid = -1;
|
||||
|
||||
if (!wcid)
|
||||
wcid = &dev->global_sta.wcid;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
|
||||
spin_lock_bh(&dev->status_lock);
|
||||
|
||||
msta->pid = (msta->pid + 1) & MT_PID_INDEX;
|
||||
if (!msta->pid)
|
||||
msta->pid++;
|
||||
|
||||
pid = msta->pid;
|
||||
cb->wcid = wcid->idx;
|
||||
cb->pktid = pid;
|
||||
list_add(&cb->list, &dev->status_list);
|
||||
|
||||
spin_unlock_bh(&dev->status_lock);
|
||||
} else {
|
||||
INIT_LIST_HEAD(&cb->list);
|
||||
}
|
||||
|
||||
mt7603_mac_write_txwi(dev, txwi_ptr, skb, wcid, sta, pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
struct ieee80211_tx_info *info, __le32 *txs_data)
|
||||
{
|
||||
bool final_mpdu;
|
||||
bool ampdu;
|
||||
int count;
|
||||
u32 txs;
|
||||
u8 pid;
|
||||
|
||||
txs = le32_to_cpu(txs_data[4]);
|
||||
final_mpdu = txs & MT_TXS4_ACKED_MPDU;
|
||||
ampdu = txs & MT_TXS4_AMPDU;
|
||||
pid = MT76_GET(MT_TXS4_PID, txs);
|
||||
count = MT76_GET(MT_TXS4_TX_COUNT, txs);
|
||||
|
||||
txs = le32_to_cpu(txs_data[0]);
|
||||
if (!(txs & MT_TXS0_ACK_ERROR_MASK)) {
|
||||
if (ampdu)
|
||||
sta->ampdu_acked++;
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
}
|
||||
|
||||
if (ampdu) {
|
||||
sta->ampdu_count++;
|
||||
if (!final_mpdu)
|
||||
return;
|
||||
|
||||
info->flags |= IEEE80211_TX_CTL_AMPDU | IEEE80211_TX_STAT_AMPDU;
|
||||
info->status.ampdu_len = sta->ampdu_count;
|
||||
info->status.ampdu_ack_len = sta->ampdu_acked;
|
||||
}
|
||||
|
||||
sta->ampdu_count = 0;
|
||||
sta->ampdu_acked = 0;
|
||||
}
|
||||
|
||||
struct sk_buff *
|
||||
mt7603_mac_status_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pktid)
|
||||
{
|
||||
struct mt7603_cb *cb, *tmp;
|
||||
struct sk_buff *skb;
|
||||
|
||||
list_for_each_entry_safe(cb, tmp, &dev->status_list, list) {
|
||||
if (sta && cb->wcid != sta->wcid.idx)
|
||||
continue;
|
||||
|
||||
list_del_init(&cb->list);
|
||||
skb = mt7603_cb_skb(cb);
|
||||
|
||||
if (cb->pktid == pktid)
|
||||
break;
|
||||
|
||||
ieee80211_free_txskb(mt76_hw(dev), skb);
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_skb_done(struct mt7603_dev *dev, struct sk_buff *skb, u8 flags)
|
||||
{
|
||||
struct mt7603_cb *cb = mt7603_skb_cb(skb);
|
||||
|
||||
flags |= cb->flags;
|
||||
cb->flags = flags;
|
||||
|
||||
if (flags != (MT7603_CB_DMA_DONE | MT7603_CB_TXS_DONE))
|
||||
return;
|
||||
|
||||
ieee80211_tx_status(mt76_hw(dev), skb);
|
||||
}
|
||||
|
||||
static bool
|
||||
mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid,
|
||||
__le32 *txs_data)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!pid)
|
||||
return false;
|
||||
|
||||
spin_lock_bh(&dev->status_lock);
|
||||
skb = mt7603_mac_status_skb(dev, sta, pid);
|
||||
if (skb) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
mt7603_fill_txs(dev, sta, info, txs_data);
|
||||
mt7603_skb_done(dev, skb, MT7603_CB_TXS_DONE);
|
||||
}
|
||||
spin_unlock_bh(&dev->status_lock);
|
||||
|
||||
return !!skb;
|
||||
}
|
||||
|
||||
void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
|
||||
{
|
||||
struct ieee80211_tx_info info = {};
|
||||
@@ -438,23 +558,18 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
|
||||
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 (pid & BIT(7)) /* No-ACK */
|
||||
return;
|
||||
|
||||
if (wcidx >= ARRAY_SIZE(dev->wcid))
|
||||
return;
|
||||
|
||||
@@ -467,26 +582,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
|
||||
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;
|
||||
pid &= MT_PID_INDEX;
|
||||
if (!mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) {
|
||||
mt7603_fill_txs(dev, msta, &info, txs_data);
|
||||
ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -494,10 +595,30 @@ out:
|
||||
void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
|
||||
struct mt76_queue_entry *e, bool flush)
|
||||
{
|
||||
if (e->txwi)
|
||||
ieee80211_free_txskb(mdev->hw, e->skb);
|
||||
else
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(e->skb);
|
||||
struct mt7603_cb *cb = mt7603_skb_cb(e->skb);
|
||||
bool free = true;
|
||||
|
||||
if (!e->txwi) {
|
||||
dev_kfree_skb_any(e->skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* will be freed by tx status handling codepath */
|
||||
if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
|
||||
spin_lock_bh(&dev->status_lock);
|
||||
if (!flush) {
|
||||
mt7603_skb_done(dev, e->skb, MT7603_CB_DMA_DONE);
|
||||
free = false;
|
||||
} else {
|
||||
list_del_init(&cb->list);
|
||||
}
|
||||
spin_unlock_bh(&dev->status_lock);
|
||||
}
|
||||
|
||||
if (free)
|
||||
ieee80211_free_txskb(mdev->hw, e->skb);
|
||||
}
|
||||
|
||||
void mt7603_mac_start(struct mt7603_dev *dev)
|
||||
|
||||
@@ -250,4 +250,7 @@ enum mt7603_tx_header_format {
|
||||
#define MT_TXS4_F0_SEQNO GENMASK(11, 0)
|
||||
#define MT_TXS4_F1_TSSI GENMASK(11, 0)
|
||||
|
||||
#define MT_PID_NOACK BIT(7)
|
||||
#define MT_PID_INDEX GENMASK(6, 0)
|
||||
|
||||
#endif
|
||||
|
||||
+9
-7
@@ -46,7 +46,7 @@ mt7603_txq_init(struct mt7603_dev *dev, struct ieee80211_txq *txq)
|
||||
mtxq->wcid = &sta->wcid;
|
||||
} else {
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *) txq->vif->drv_priv;
|
||||
mtxq->wcid = &mvif->group_wcid;
|
||||
mtxq->wcid = &mvif->sta.wcid;
|
||||
}
|
||||
|
||||
mt76_txq_init(&dev->mt76, txq);
|
||||
@@ -57,6 +57,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv;
|
||||
struct mt7603_dev *dev = hw->priv;
|
||||
int idx;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
@@ -67,9 +68,11 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
goto out;
|
||||
}
|
||||
|
||||
idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
|
||||
dev->vif_mask |= BIT(mvif->idx);
|
||||
mvif->group_wcid.idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
|
||||
mvif->group_wcid.hw_key_idx = -1;
|
||||
mvif->sta.wcid.idx = idx;
|
||||
mvif->sta.wcid.hw_key_idx = -1;
|
||||
rcu_assign_pointer(dev->wcid[idx], &mvif->sta.wcid);
|
||||
mt7603_txq_init(dev, vif->txq);
|
||||
|
||||
out:
|
||||
@@ -83,7 +86,9 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv;
|
||||
struct mt7603_dev *dev = hw->priv;
|
||||
int idx = mvif->sta.wcid.idx;
|
||||
|
||||
rcu_assign_pointer(dev->wcid[idx], NULL);
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
@@ -326,11 +331,8 @@ static void mt7603_set_coverage_class(struct ieee80211_hw *hw,
|
||||
static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv;
|
||||
struct mt76_wcid *wcid = &mvif->group_wcid;
|
||||
struct mt7603_dev *dev = hw->priv;
|
||||
struct mt76_wcid *wcid = &dev->global_sta.wcid;
|
||||
|
||||
mt76_tx(&dev->mt76, control->sta, wcid, skb);
|
||||
}
|
||||
|
||||
+1
-4
@@ -73,10 +73,7 @@ mt76pci_remove(struct pci_dev *pdev)
|
||||
struct mt76_dev *mdev = pci_get_drvdata(pdev);
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
|
||||
mt76_unregister_device(&dev->mt76);
|
||||
mt7603_mcu_exit(dev);
|
||||
mt7603_dma_cleanup(dev);
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
mt7603_unregister_device(dev);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, mt76pci_device_table);
|
||||
|
||||
Reference in New Issue
Block a user