diff --git a/mt7603.h b/mt7603.h index 6ec06836..09460d24 100644 --- a/mt7603.h +++ b/mt7603.h @@ -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); diff --git a/mt7603_init.c b/mt7603_init.c index 201cb6c2..43aa9a7e 100644 --- a/mt7603_init.c +++ b/mt7603_init.c @@ -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)); +} diff --git a/mt7603_mac.c b/mt7603_mac.c index c738981a..6787f972 100644 --- a/mt7603_mac.c +++ b/mt7603_mac.c @@ -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) diff --git a/mt7603_mac.h b/mt7603_mac.h index cf0554dd..757a66c2 100644 --- a/mt7603_mac.h +++ b/mt7603_mac.h @@ -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 diff --git a/mt7603_main.c b/mt7603_main.c index adce0c1c..1b3bf8d8 100644 --- a/mt7603_main.c +++ b/mt7603_main.c @@ -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); } diff --git a/mt7603_pci.c b/mt7603_pci.c index 06a82259..8932661a 100644 --- a/mt7603_pci.c +++ b/mt7603_pci.c @@ -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);