mt7603: implement rudimentary skb tx status reporting

Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Felix Fietkau
2016-02-06 18:16:38 +01:00
parent fa3ee92842
commit 1c9710dcd1
6 changed files with 225 additions and 49 deletions
+42 -5
View File
@@ -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);
+16
View File
@@ -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
View File
@@ -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)
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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);