diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915/mac.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 259 |
1 files changed, 160 insertions, 99 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 6825afca1efb..6f159d99a596 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -88,17 +88,16 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask) 0, 5000); } -static u32 mt7915_mac_wtbl_lmac_read(struct mt7915_dev *dev, u16 wcid, - u16 addr) +static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid) { mt76_wr(dev, MT_WTBLON_TOP_WDUCR, FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); - return mt76_rr(dev, MT_WTBL_LMAC_OFFS(wcid, addr)); + return MT_WTBL_LMAC_OFFS(wcid, 0); } /* TODO: use txfree airtime info to avoid runtime accessing in the long run */ -void mt7915_mac_sta_poll(struct mt7915_dev *dev) +static void mt7915_mac_sta_poll(struct mt7915_dev *dev) { static const u8 ac_to_tid[] = { [IEEE80211_AC_BE] = 0, @@ -106,47 +105,50 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev) [IEEE80211_AC_VI] = 4, [IEEE80211_AC_VO] = 6 }; - static const u8 hw_queue_map[] = { - [IEEE80211_AC_BK] = 0, - [IEEE80211_AC_BE] = 1, - [IEEE80211_AC_VI] = 2, - [IEEE80211_AC_VO] = 3, - }; struct ieee80211_sta *sta; struct mt7915_sta *msta; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; + LIST_HEAD(sta_poll_list); int i; + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&dev->sta_poll_list, &sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + rcu_read_lock(); while (true) { bool clear = false; + u32 addr; u16 idx; spin_lock_bh(&dev->sta_poll_lock); - if (list_empty(&dev->sta_poll_list)) { + if (list_empty(&sta_poll_list)) { spin_unlock_bh(&dev->sta_poll_lock); break; } - msta = list_first_entry(&dev->sta_poll_list, + msta = list_first_entry(&sta_poll_list, struct mt7915_sta, poll_list); list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); - for (i = 0, idx = msta->wcid.idx; i < IEEE80211_NUM_ACS; i++) { + idx = msta->wcid.idx; + addr = mt7915_mac_wtbl_lmac_addr(dev, idx) + 20 * 4; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { u32 tx_last = msta->airtime_ac[i]; - u32 rx_last = msta->airtime_ac[i + IEEE80211_NUM_ACS]; + u32 rx_last = msta->airtime_ac[i + 4]; + + msta->airtime_ac[i] = mt76_rr(dev, addr); + msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); - msta->airtime_ac[i] = - mt7915_mac_wtbl_lmac_read(dev, idx, 20 + i); - msta->airtime_ac[i + IEEE80211_NUM_ACS] = - mt7915_mac_wtbl_lmac_read(dev, idx, 21 + i); tx_time[i] = msta->airtime_ac[i] - tx_last; - rx_time[i] = msta->airtime_ac[i + IEEE80211_NUM_ACS] - - rx_last; + rx_time[i] = msta->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; + + addr += 8; } if (clear) { @@ -161,8 +163,9 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev) sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u32 tx_cur = tx_time[i]; - u32 rx_cur = rx_time[hw_queue_map[i]]; + u8 q = mt7915_lmac_mapping(dev, i); + u32 tx_cur = tx_time[q]; + u32 rx_cur = rx_time[q]; u8 tid = ac_to_tid[i]; if (!tx_cur && !rx_cur) @@ -468,7 +471,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) switch (mode) { case MT_PHY_TYPE_CCK: cck = true; - /* fall through */ + fallthrough; case MT_PHY_TYPE_OFDM: i = mt76_get_rate(&dev->mt76, sband, i, cck); break; @@ -487,7 +490,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) break; case MT_PHY_TYPE_HE_MU: status->flag |= RX_FLAG_RADIOTAP_HE_MU; - /* fall through */ + fallthrough; case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: case MT_PHY_TYPE_HE_TB: @@ -565,13 +568,15 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; bool multicast = is_multicast_ether_addr(hdr->addr1); struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->mphy; bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; __le16 fc = hdr->frame_control; - u16 tx_count = 4, seqno = 0; + u16 tx_count = 15, seqno = 0; + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; u32 val; if (vif) { @@ -587,6 +592,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; + txwi[4] = 0; + txwi[5] = 0; + txwi[6] = 0; + if (beacon) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_BCN0; @@ -599,6 +608,20 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb)); } + if (ieee80211_is_action(fc) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + + txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA); + tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; + } else if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; + u16 control = le16_to_cpu(bar->control); + + tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); + } + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); @@ -609,8 +632,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | FIELD_PREP(MT_TXD1_HDR_INFO, ieee80211_get_hdrlen_from_skb(skb) / 2) | - FIELD_PREP(MT_TXD1_TID, - skb->priority & IEEE80211_QOS_CTL_TID_MASK) | + FIELD_PREP(MT_TXD1_TID, tid) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) @@ -634,10 +656,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, } txwi[2] = cpu_to_le32(val); - txwi[4] = 0; - txwi[5] = 0; - txwi[6] = 0; - if (!ieee80211_is_data(fc) || multicast) { u16 rate; @@ -665,20 +683,24 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + if (wcid->amsdu) + val |= MT_TXD7_HW_AMSDU; txwi[7] = cpu_to_le32(val); val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); - if (ieee80211_is_data_qos(fc)) { - seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - val |= MT_TXD3_SN_VALID; - } else if (ieee80211_is_back_req(fc)) { - struct ieee80211_bar *bar; - - bar = (struct ieee80211_bar *)skb->data; - seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); - val |= MT_TXD3_SN_VALID; + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val |= MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); } - val |= FIELD_PREP(MT_TXD3_SEQ, seqno); txwi[3] |= cpu_to_le32(val); } @@ -715,6 +737,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, /* pass partial skb header to fw */ tx_info->buf[1].len = MT_CT_PARSE_LEN; + tx_info->buf[1].skip_unmap = true; tx_info->nbuf = MT_CT_DMA_BUF_NUM; txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD); @@ -747,45 +770,29 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return 0; } -static inline bool -mt7915_tx_check_aggr_tid(struct mt7915_sta *msta, u8 tid) -{ - bool ret = false; - - spin_lock_bh(&msta->ampdu_lock); - if (msta->ampdu_state[tid] == MT7915_AGGR_STOP) - ret = true; - spin_unlock_bh(&msta->ampdu_lock); - - return ret; -} - static void -mt7915_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) +mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct mt7915_sta *msta; - u16 tid; - - if (!sta->ht_cap.ht_supported) - return; + u16 fc, tid; + u32 val; - if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + if (!sta || !sta->ht_cap.ht_supported) return; - if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) + tid = FIELD_GET(MT_TXD1_TID, le32_to_cpu(txwi[1])); + if (tid >= 6) /* skip VO queue */ return; - if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + val = le32_to_cpu(txwi[2]); + fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | + FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4; + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) return; msta = (struct mt7915_sta *)sta->drv_priv; - tid = ieee80211_get_tid(hdr); - - if (mt7915_tx_check_aggr_tid(msta, tid)) { + if (!test_and_set_bit(tid, &msta->ampdu_state)) ieee80211_start_tx_ba_session(sta, tid, 0); - mt7915_set_aggr_state(msta, tid, MT7915_AGGR_PROGRESS); - } } static inline void @@ -822,8 +829,6 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_AMPDU) info->flags |= IEEE80211_TX_STAT_AMPDU; - else if (sta) - mt7915_tx_check_aggr(sta, skb); if (stat) ieee80211_tx_info_clear_status(info); @@ -841,7 +846,7 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, if (sta || !(info->flags & IEEE80211_TX_CTL_NO_ACK)) mt7915_tx_status(sta, hw, info, NULL); - dev_kfree_skb(skb); + ieee80211_free_txskb(hw, skb); } void mt7915_txp_skb_unmap(struct mt76_dev *dev, @@ -864,6 +869,10 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) struct ieee80211_sta *sta = NULL; u8 i, count; + /* clean DMA queues and unmap buffers first */ + mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false); + /* * TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, * to the time ack is received or dropped by hw (air + hw queue time). @@ -880,6 +889,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) */ if (info & MT_TX_FREE_PAIR) { struct mt7915_sta *msta; + struct mt7915_phy *phy; struct mt76_wcid *wcid; u16 idx; @@ -891,8 +901,13 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) continue; msta = container_of(wcid, struct mt7915_sta, wcid); - ieee80211_queue_work(mt76_hw(dev), &msta->stats_work); - continue; + phy = msta->vif->phy; + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->stats_list)) + list_add_tail(&msta->stats_list, &phy->stats_list); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); } msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); @@ -907,6 +922,21 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) mt7915_txp_skb_unmap(mdev, txwi); if (txwi->skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb); + void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi); + + if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7915_tx_check_aggr(sta, txwi_ptr); + + if (sta && !info->tx_time_est) { + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + int pending; + + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); + } + mt7915_tx_complete_status(mdev, txwi->skb, sta, stat); txwi->skb = NULL; } @@ -914,10 +944,12 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) mt76_put_txwi(mdev, txwi); } dev_kfree_skb(skb); + + mt7915_mac_sta_poll(dev); + mt76_worker_schedule(&dev->mt76.tx_worker); } -void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, - struct mt76_queue_entry *e) +void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { struct mt7915_dev *dev; @@ -1186,7 +1218,7 @@ void mt7915_mac_reset_work(struct work_struct *work) if (ext_phy) mt76_txq_schedule_all(ext_phy); - tasklet_disable(&dev->mt76.tx_tasklet); + mt76_worker_disable(&dev->mt76.tx_worker); napi_disable(&dev->mt76.napi[0]); napi_disable(&dev->mt76.napi[1]); napi_disable(&dev->mt76.napi[2]); @@ -1206,7 +1238,7 @@ void mt7915_mac_reset_work(struct work_struct *work) clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); - tasklet_enable(&dev->mt76.tx_tasklet); + mt76_worker_enable(&dev->mt76.tx_worker); napi_enable(&dev->mt76.tx_napi); napi_schedule(&dev->mt76.tx_napi); @@ -1281,39 +1313,63 @@ mt7915_mac_update_mib_stats(struct mt7915_phy *phy) } } -void mt7915_mac_sta_stats_work(struct work_struct *work) +static void +mt7915_mac_sta_stats_work(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_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 mt7915_sta, stats_list); + list_del_init(&msta->stats_list); + spin_unlock_bh(&dev->sta_poll_lock); + + /* use MT_TX_FREE_RATE to report Tx rate for further devices */ + mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, msta->wcid.idx); + + spin_lock_bh(&dev->sta_poll_lock); + } + + spin_unlock_bh(&dev->sta_poll_lock); +} + +void mt7915_mac_sta_rc_work(struct work_struct *work) { + struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work); struct ieee80211_sta *sta; struct ieee80211_vif *vif; - struct mt7915_sta_stats *stats; struct mt7915_sta *msta; - struct mt7915_dev *dev; + u32 changed; + LIST_HEAD(list); - msta = container_of(work, struct mt7915_sta, stats_work); - sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); - vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); - dev = msta->vif->dev; - stats = &msta->stats; + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&dev->sta_rc_list, &list); - /* use MT_TX_FREE_RATE to report Tx rate for further devices */ - if (time_after(jiffies, stats->jiffies + HZ)) { - mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, - msta->wcid.idx); + while (!list_empty(&list)) { + msta = list_first_entry(&list, struct mt7915_sta, rc_list); + list_del_init(&msta->rc_list); + changed = msta->stats.changed; + msta->stats.changed = 0; + spin_unlock_bh(&dev->sta_poll_lock); - stats->jiffies = jiffies; - } + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); - if (test_and_clear_bit(IEEE80211_RC_SUPP_RATES_CHANGED | + if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | IEEE80211_RC_NSS_CHANGED | - IEEE80211_RC_BW_CHANGED, &stats->changed)) - mt7915_mcu_add_rate_ctrl(dev, vif, sta); + IEEE80211_RC_BW_CHANGED)) + mt7915_mcu_add_rate_ctrl(dev, vif, sta); - if (test_and_clear_bit(IEEE80211_RC_SMPS_CHANGED, &stats->changed)) - mt7915_mcu_add_smps(dev, vif, sta); + if (changed & IEEE80211_RC_SMPS_CHANGED) + mt7915_mcu_add_smps(dev, vif, sta); + + spin_lock_bh(&dev->sta_poll_lock); + } - spin_lock_bh(&dev->sta_poll_lock); - if (list_empty(&msta->poll_list)) - list_add_tail(&msta->poll_list, &dev->sta_poll_list); spin_unlock_bh(&dev->sta_poll_lock); } @@ -1335,6 +1391,11 @@ void mt7915_mac_work(struct work_struct *work) mt7915_mac_update_mib_stats(phy); } + if (++phy->sta_work_count == 10) { + phy->sta_work_count = 0; + mt7915_mac_sta_stats_work(phy); + }; + mutex_unlock(&mdev->mutex); ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, |