aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/dev/mediatek/mt76/mt7996/mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/dev/mediatek/mt76/mt7996/mac.c')
-rw-r--r--sys/contrib/dev/mediatek/mt76/mt7996/mac.c492
1 files changed, 303 insertions, 189 deletions
diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mac.c b/sys/contrib/dev/mediatek/mt76/mt7996/mac.c
index 3f1536f2bbe7..13ea5b55d619 100644
--- a/sys/contrib/dev/mediatek/mt76/mt7996/mac.c
+++ b/sys/contrib/dev/mediatek/mt76/mt7996/mac.c
@@ -56,26 +56,45 @@ static const struct mt7996_dfs_radar_spec jp_radar_specs = {
};
static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
- u16 idx, bool unicast)
+ u16 idx, u8 band_idx)
{
- struct mt7996_sta *sta;
+ struct mt7996_sta_link *msta_link;
+ struct mt7996_sta *msta;
+ struct mt7996_vif *mvif;
struct mt76_wcid *wcid;
+ int i;
+
+ wcid = mt76_wcid_ptr(dev, idx);
+ if (!wcid || !wcid->sta)
+ return NULL;
- if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+ if (!mt7996_band_valid(dev, band_idx))
return NULL;
- wcid = rcu_dereference(dev->mt76.wcid[idx]);
- if (unicast || !wcid)
+ if (wcid->phy_idx == band_idx)
return wcid;
- if (!wcid->sta)
+ msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
+ msta = msta_link->sta;
+ if (!msta || !msta->vif)
return NULL;
- sta = container_of(wcid, struct mt7996_sta, wcid);
- if (!sta->vif)
- return NULL;
+ mvif = msta->vif;
+ for (i = 0; i < ARRAY_SIZE(mvif->mt76.link); i++) {
+ struct mt76_vif_link *mlink;
+
+ mlink = rcu_dereference(mvif->mt76.link[i]);
+ if (!mlink)
+ continue;
+
+ if (mlink->band_idx != band_idx)
+ continue;
+
+ msta_link = rcu_dereference(msta->link[i]);
+ break;
+ }
- return &sta->vif->deflink.sta.wcid;
+ return &msta_link->wcid;
}
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
@@ -103,10 +122,13 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
[IEEE80211_AC_VI] = 4,
[IEEE80211_AC_VO] = 6
};
+ struct mt7996_sta_link *msta_link;
+ struct mt76_vif_link *mlink;
struct ieee80211_sta *sta;
struct mt7996_sta *msta;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
+ struct mt76_wcid *wcid;
int i;
spin_lock_bh(&dev->mt76.sta_poll_lock);
@@ -126,25 +148,28 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
spin_unlock_bh(&dev->mt76.sta_poll_lock);
break;
}
- msta = list_first_entry(&sta_poll_list,
- struct mt7996_sta, wcid.poll_list);
- list_del_init(&msta->wcid.poll_list);
+ msta_link = list_first_entry(&sta_poll_list,
+ struct mt7996_sta_link,
+ wcid.poll_list);
+ msta = msta_link->sta;
+ wcid = &msta_link->wcid;
+ list_del_init(&wcid->poll_list);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
- idx = msta->wcid.idx;
+ idx = wcid->idx;
/* refresh peer's airtime reporting */
addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- u32 tx_last = msta->airtime_ac[i];
- u32 rx_last = msta->airtime_ac[i + 4];
+ u32 tx_last = msta_link->airtime_ac[i];
+ u32 rx_last = msta_link->airtime_ac[i + 4];
- msta->airtime_ac[i] = mt76_rr(dev, addr);
- msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
+ msta_link->airtime_ac[i] = mt76_rr(dev, addr);
+ msta_link->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
- tx_time[i] = msta->airtime_ac[i] - tx_last;
- rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
+ tx_time[i] = msta_link->airtime_ac[i] - tx_last;
+ rx_time[i] = msta_link->airtime_ac[i + 4] - rx_last;
if ((tx_last | rx_last) & BIT(30))
clear = true;
@@ -155,10 +180,11 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
if (clear) {
mt7996_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
+ memset(msta_link->airtime_ac, 0,
+ sizeof(msta_link->airtime_ac));
}
- if (!msta->wcid.sta)
+ if (!wcid->sta)
continue;
sta = container_of((void *)msta, struct ieee80211_sta,
@@ -184,28 +210,23 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
rssi[2] = to_rssi(GENMASK(23, 16), val);
rssi[3] = to_rssi(GENMASK(31, 14), val);
- msta->ack_signal =
- mt76_rx_signal(msta->vif->deflink.phy->mt76->antenna_mask, rssi);
+ mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]);
+ if (mlink) {
+ struct mt76_phy *mphy = mt76_vif_link_phy(mlink);
+
+ if (mphy)
+ msta_link->ack_signal =
+ mt76_rx_signal(mphy->antenna_mask,
+ rssi);
+ }
- ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
+ ewma_avg_signal_add(&msta_link->avg_ack_signal,
+ -msta_link->ack_signal);
}
rcu_read_unlock();
}
-void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
- struct ieee80211_vif *vif, bool enable)
-{
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
- u32 addr;
-
- addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->deflink.sta.wcid.idx, 5);
- if (enable)
- mt76_set(dev, addr, BIT(5));
- else
- mt76_clear(dev, addr, BIT(5));
-}
-
/* The HW does not translate the mac header to 802.3 for mesh point */
static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
{
@@ -477,11 +498,15 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
- status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
+ status->wcid = mt7996_rx_get_wcid(dev, idx, band_idx);
if (status->wcid) {
- msta = container_of(status->wcid, struct mt7996_sta, wcid);
- mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
+ struct mt7996_sta_link *msta_link;
+
+ msta_link = container_of(status->wcid, struct mt7996_sta_link,
+ wcid);
+ msta = msta_link->sta;
+ mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
}
status->freq = mphy->chandef.chan->center_freq;
@@ -622,6 +647,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
}
+ /* IEEE 802.11 fragmentation can only be applied to unicast frames.
+ * Hence, drop fragments with multicast/broadcast RA.
+ * This check fixes vulnerabilities, like CVE-2020-26145.
+ */
+ if ((ieee80211_has_morefrags(fc) || seq_ctrl & IEEE80211_SCTL_FRAG) &&
+ FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) != MT_RXD3_NORMAL_U2M)
+ return -EINVAL;
+
hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
if (hdr_trans && ieee80211_has_morefrags(fc)) {
if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
@@ -720,9 +753,8 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
u32 val;
if (wcid->sta) {
- struct ieee80211_sta *sta;
+ struct ieee80211_sta *sta = wcid_to_sta(wcid);
- sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
wmm = sta->wme;
}
@@ -749,7 +781,9 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
static void
mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
- struct sk_buff *skb, struct ieee80211_key_conf *key)
+ struct sk_buff *skb,
+ struct ieee80211_key_conf *key,
+ struct mt76_wcid *wcid)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
@@ -757,15 +791,19 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
bool multicast = is_multicast_ether_addr(hdr->addr1);
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
__le16 fc = hdr->frame_control, sc = hdr->seq_ctrl;
+ u16 seqno = le16_to_cpu(sc);
u8 fc_type, fc_stype;
u32 val;
if (ieee80211_is_action(fc) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
- mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
+ mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
+ if (is_mt7990(&dev->mt76))
+ txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TID_ADDBA, tid));
tid = MT_TX_ADDBA;
- else if (ieee80211_is_mgmt(hdr->frame_control))
+ } else if (ieee80211_is_mgmt(hdr->frame_control)) {
tid = MT_TX_NORMAL;
+ }
val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
FIELD_PREP(MT_TXD1_HDR_INFO,
@@ -776,8 +814,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
info->flags & IEEE80211_TX_CTL_USE_MINRATE)
val |= MT_TXD1_FIXED_RATE;
- if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
- key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (key && multicast && ieee80211_is_robust_mgmt_frame(skb)) {
val |= MT_TXD1_BIP;
txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
}
@@ -807,9 +844,13 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
}
- if (info->flags & IEEE80211_TX_CTL_INJECTED) {
- u16 seqno = le16_to_cpu(sc);
+ if (multicast && ieee80211_vif_is_mld(info->control.vif)) {
+ val = MT_TXD3_SN_VALID |
+ FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
+ txwi[3] |= cpu_to_le32(val);
+ }
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
if (ieee80211_is_back_req(hdr->frame_control)) {
struct ieee80211_bar *bar;
@@ -822,6 +863,19 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
txwi[3] |= cpu_to_le32(val);
txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
}
+
+ if (ieee80211_vif_is_mld(info->control.vif) &&
+ (multicast || unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))))
+ txwi[5] |= cpu_to_le32(MT_TXD5_FL);
+
+ if (ieee80211_is_nullfunc(fc) && ieee80211_has_a4(fc) &&
+ ieee80211_vif_is_mld(info->control.vif)) {
+ txwi[5] |= cpu_to_le32(MT_TXD5_FL);
+ txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT);
+ }
+
+ if (!wcid->sta && ieee80211_is_mgmt(fc))
+ txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT);
}
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
@@ -835,7 +889,9 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
- struct mt76_vif_link *mvif;
+ struct mt76_vif_link *mlink = NULL;
+ struct mt7996_vif *mvif;
+ unsigned int link_id;
u16 tx_count = 15;
u32 val;
bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
@@ -843,11 +899,24 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
bool beacon = !!(changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
- mvif = vif ? (struct mt76_vif_link *)vif->drv_priv : NULL;
+ if (wcid != &dev->mt76.global_wcid)
+ link_id = wcid->link_id;
+ else
+ link_id = u32_get_bits(info->control.flags,
+ IEEE80211_TX_CTRL_MLO_LINK);
+
+ mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
if (mvif) {
- omac_idx = mvif->omac_idx;
- wmm_idx = mvif->wmm_idx;
- band_idx = mvif->band_idx;
+ if (wcid->offchannel)
+ mlink = rcu_dereference(mvif->mt76.offchannel_link);
+ if (!mlink)
+ mlink = rcu_dereference(mvif->mt76.link[link_id]);
+ }
+
+ if (mlink) {
+ omac_idx = mlink->omac_idx;
+ wmm_idx = mlink->wmm_idx;
+ band_idx = mlink->band_idx;
}
if (inband_disc) {
@@ -894,7 +963,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
val |= MT_TXD5_TX_STATUS_HOST;
txwi[5] = cpu_to_le32(val);
- val = MT_TXD6_DIS_MAT | MT_TXD6_DAS;
+ val = MT_TXD6_DAS;
+ if (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)
+ val |= MT_TXD6_DIS_MAT;
+
if (is_mt7996(&dev->mt76))
val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
else if (is_8023 || !ieee80211_is_mgmt(hdr->frame_control))
@@ -906,34 +978,56 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
if (is_8023)
mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);
else
- mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
+ mt7996_mac_write_txwi_80211(dev, txwi, skb, key, wcid);
if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
bool mcast = ieee80211_is_data(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1);
u8 idx = MT7996_BASIC_RATES_TBL;
- if (mvif) {
- if (mcast && mvif->mcast_rates_idx)
- idx = mvif->mcast_rates_idx;
- else if (beacon && mvif->beacon_rates_idx)
- idx = mvif->beacon_rates_idx;
+ if (mlink) {
+ if (mcast && mlink->mcast_rates_idx)
+ idx = mlink->mcast_rates_idx;
+ else if (beacon && mlink->beacon_rates_idx)
+ idx = mlink->beacon_rates_idx;
else
- idx = mvif->basic_rates_idx;
+ idx = mlink->basic_rates_idx;
}
val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW;
+ if (mcast)
+ val |= MT_TXD6_DIS_MAT;
txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
}
+static bool
+mt7996_tx_use_mgmt(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (ieee80211_is_mgmt(hdr->frame_control))
+ return true;
+
+ /* for SDO to bypass specific data frame */
+ if (!mt7996_has_wa(dev)) {
+ if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+ return true;
+
+ if (ieee80211_has_a4(hdr->frame_control) &&
+ !ieee80211_is_data_present(hdr->frame_control))
+ return true;
+ }
+
+ return false;
+}
+
int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
@@ -958,8 +1052,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return id;
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
- pid, qid, 0);
+ memset(txwi_ptr, 0, MT_TXD_SIZE);
+ /* Transmit non qos data by 802.11 header and need to fill txd by host*/
+ if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
+ mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
+ pid, qid, 0);
txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
@@ -976,19 +1073,27 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
}
txp->fw.nbuf = nbuf;
- txp->fw.flags =
- cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD);
+ txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
+
+ if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
+ txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
if (!key)
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
- if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
+ if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb))
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
if (vif) {
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt76_vif_link *mlink = NULL;
+
+ if (wcid->offchannel)
+ mlink = rcu_dereference(mvif->mt76.offchannel_link);
+ if (!mlink)
+ mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]);
- txp->fw.bss_idx = mvif->deflink.mt76.idx;
+ txp->fw.bss_idx = mlink ? mlink->idx : mvif->deflink.mt76.idx;
}
txp->fw.token = cpu_to_le16(id);
@@ -1032,14 +1137,14 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
}
static void
-mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
+mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta,
+ struct mt76_wcid *wcid, struct sk_buff *skb)
{
- struct mt7996_sta *msta;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
u16 fc, tid;
- if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
+ if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
return;
tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -1048,7 +1153,8 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
if (is_8023) {
fc = IEEE80211_FTYPE_DATA |
- (sta->wme ? IEEE80211_STYPE_QOS_DATA : IEEE80211_STYPE_DATA);
+ (link_sta->sta->wme ? IEEE80211_STYPE_QOS_DATA
+ : IEEE80211_STYPE_DATA);
} else {
/* No need to get precise TID for Action/Management Frame,
* since it will not meet the following Frame Control
@@ -1064,17 +1170,16 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
return;
- msta = (struct mt7996_sta *)sta->drv_priv;
- if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
- ieee80211_start_tx_ba_session(sta, tid, 0);
+ if (!test_and_set_bit(tid, &wcid->ampdu_state))
+ ieee80211_start_tx_ba_session(link_sta->sta, tid, 0);
}
static void
mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, struct list_head *free_list)
+ struct ieee80211_link_sta *link_sta,
+ struct mt76_wcid *wcid, struct list_head *free_list)
{
struct mt76_dev *mdev = &dev->mt76;
- struct mt76_wcid *wcid;
__le32 *txwi;
u16 wcid_idx;
@@ -1083,12 +1188,10 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
goto out;
txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
- if (sta) {
- wcid = (struct mt76_wcid *)sta->drv_priv;
+ if (link_sta) {
wcid_idx = wcid->idx;
-
if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
- mt7996_tx_check_aggr(sta, t->skb);
+ mt7996_tx_check_aggr(link_sta, wcid, t->skb);
} else {
wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);
}
@@ -1107,8 +1210,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
struct mt76_dev *mdev = &dev->mt76;
struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
+ struct ieee80211_link_sta *link_sta = NULL;
struct mt76_txwi_cache *txwi;
- struct ieee80211_sta *sta = NULL;
struct mt76_wcid *wcid = NULL;
LIST_HEAD(free_list);
struct sk_buff *skb, *tmp;
@@ -1119,6 +1222,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
#endif
bool wake = false;
u16 total, count = 0;
+ u8 ver;
/* clean DMA queues and unmap buffers first */
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
@@ -1132,7 +1236,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);
}
- if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 5))
+ ver = le32_get_bits(tx_free[1], MT_TXFREE1_VER);
+ if (WARN_ON_ONCE(ver < 5))
return;
total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);
@@ -1147,17 +1252,27 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
*/
info = le32_to_cpu(*cur_info);
if (info & MT_TXFREE_INFO_PAIR) {
- struct mt7996_sta *msta;
+ struct ieee80211_sta *sta;
u16 idx;
idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
- wcid = rcu_dereference(dev->mt76.wcid[idx]);
+ wcid = mt76_wcid_ptr(dev, idx);
sta = wcid_to_sta(wcid);
- if (!sta)
- continue;
+ if (!sta) {
+ link_sta = NULL;
+ goto next;
+ }
- msta = container_of(wcid, struct mt7996_sta, wcid);
- mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
+ link_sta = rcu_dereference(sta->link[wcid->link_id]);
+ if (!link_sta)
+ goto next;
+
+ mt76_wcid_add_poll(&dev->mt76, wcid);
+next:
+ /* ver 7 has a new DW with pair = 1, skip it */
+ if (ver == 7 && ((void *)(cur_info + 1) < end) &&
+ (le32_to_cpu(*(cur_info + 1)) & MT_TXFREE_INFO_PAIR))
+ cur_info++;
continue;
} else if (info & MT_TXFREE_INFO_HEADER) {
u32 tx_retries = 0, tx_failed = 0;
@@ -1185,7 +1300,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
if (!txwi)
continue;
- mt7996_txwi_free(dev, txwi, sta, &free_list);
+ mt7996_txwi_free(dev, txwi, link_sta, wcid,
+ &free_list);
}
}
@@ -1241,7 +1357,7 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_sta *sta;
u8 tid;
- sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
+ sta = wcid_to_sta(wcid);
tid = FIELD_GET(MT_TXS0_TID, txs);
ieee80211_refresh_tx_agg_session_timer(sta, tid);
}
@@ -1355,7 +1471,7 @@ out:
static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
{
- struct mt7996_sta *msta = NULL;
+ struct mt7996_sta_link *msta_link;
struct mt76_wcid *wcid;
__le32 *txs_data = data;
u16 wcidx;
@@ -1367,23 +1483,19 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
if (pid < MT_PACKET_ID_NO_SKB)
return;
- if (wcidx >= mt7996_wtbl_size(dev))
- return;
-
rcu_read_lock();
- wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
+ wcid = mt76_wcid_ptr(dev, wcidx);
if (!wcid)
goto out;
- msta = container_of(wcid, struct mt7996_sta, wcid);
-
mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
if (!wcid->sta)
goto out;
- mt76_wcid_add_poll(&dev->mt76, &msta->wcid);
+ msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
+ mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
out:
rcu_read_unlock();
@@ -1410,7 +1522,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
mt7996_mac_tx_free(dev, data, len);
return false;
case PKT_TYPE_TXS:
- for (rxd += 4; rxd + 8 <= end; rxd += 8)
+ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE)
mt7996_mac_add_txs(dev, rxd);
return false;
case PKT_TYPE_RX_FW_MONITOR:
@@ -1455,7 +1567,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
mt7996_mcu_rx_event(dev, skb);
break;
case PKT_TYPE_TXS:
- for (rxd += 4; rxd + 8 <= end; rxd += 8)
+ for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE)
mt7996_mac_add_txs(dev, rxd);
dev_kfree_skb(skb);
break;
@@ -1603,43 +1715,53 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
static void
mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
- struct ieee80211_hw *hw = priv;
+ struct ieee80211_bss_conf *link_conf;
+ struct mt7996_phy *phy = priv;
+ struct mt7996_dev *dev = phy->dev;
+ unsigned int link_id;
+
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
- mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf);
break;
default:
- break;
+ return;
+ }
+
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ struct mt7996_vif_link *link;
+
+ link = mt7996_vif_link(dev, vif, link_id);
+ if (!link || link->phy != phy)
+ continue;
+
+ mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf);
}
}
+void mt7996_mac_update_beacons(struct mt7996_phy *phy)
+{
+ ieee80211_iterate_active_interfaces(phy->mt76->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7996_update_vif_beacon, phy);
+}
+
static void
mt7996_update_beacons(struct mt7996_dev *dev)
{
struct mt76_phy *phy2, *phy3;
- ieee80211_iterate_active_interfaces(dev->mt76.hw,
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7996_update_vif_beacon, dev->mt76.hw);
+ mt7996_mac_update_beacons(&dev->phy);
phy2 = dev->mt76.phys[MT_BAND1];
- if (!phy2)
- return;
-
- ieee80211_iterate_active_interfaces(phy2->hw,
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7996_update_vif_beacon, phy2->hw);
+ if (phy2)
+ mt7996_mac_update_beacons(phy2->priv);
phy3 = dev->mt76.phys[MT_BAND2];
- if (!phy3)
- return;
-
- ieee80211_iterate_active_interfaces(phy3->hw,
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7996_update_vif_beacon, phy3->hw);
+ if (phy3)
+ mt7996_mac_update_beacons(phy3->priv);
}
void mt7996_tx_token_put(struct mt7996_dev *dev)
@@ -1649,7 +1771,7 @@ void mt7996_tx_token_put(struct mt7996_dev *dev)
spin_lock_bh(&dev->mt76.token_lock);
idr_for_each_entry(&dev->mt76.token, txwi, id) {
- mt7996_txwi_free(dev, txwi, NULL, NULL);
+ mt7996_txwi_free(dev, txwi, NULL, NULL, NULL);
dev->mt76.token_count--;
}
spin_unlock_bh(&dev->mt76.token_lock);
@@ -2254,32 +2376,38 @@ void mt7996_mac_update_stats(struct mt7996_phy *phy)
void mt7996_mac_sta_rc_work(struct work_struct *work)
{
struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
- struct ieee80211_sta *sta;
+ struct mt7996_sta_link *msta_link;
struct ieee80211_vif *vif;
- struct mt7996_sta *msta;
- u32 changed;
+ struct mt7996_vif *mvif;
LIST_HEAD(list);
+ u32 changed;
spin_lock_bh(&dev->mt76.sta_poll_lock);
list_splice_init(&dev->sta_rc_list, &list);
while (!list_empty(&list)) {
- msta = list_first_entry(&list, struct mt7996_sta, rc_list);
- list_del_init(&msta->rc_list);
- changed = msta->changed;
- msta->changed = 0;
- spin_unlock_bh(&dev->mt76.sta_poll_lock);
+ msta_link = list_first_entry(&list, struct mt7996_sta_link,
+ rc_list);
+ list_del_init(&msta_link->rc_list);
+
+ changed = msta_link->changed;
+ msta_link->changed = 0;
+ mvif = msta_link->sta->vif;
+ vif = container_of((void *)mvif, struct ieee80211_vif,
+ drv_priv);
- sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
- vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
IEEE80211_RC_NSS_CHANGED |
IEEE80211_RC_BW_CHANGED))
- mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
+ mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif,
+ msta_link->wcid.link_id,
+ true);
if (changed & IEEE80211_RC_SMPS_CHANGED)
- mt7996_mcu_set_fixed_field(dev, vif, sta, NULL,
+ mt7996_mcu_set_fixed_field(dev, msta_link->sta, NULL,
+ msta_link->wcid.link_id,
RATE_PARAM_MMPS_UPDATE);
spin_lock_bh(&dev->mt76.sta_poll_lock);
@@ -2323,16 +2451,15 @@ void mt7996_mac_work(struct work_struct *work)
static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
{
struct mt7996_dev *dev = phy->dev;
+ int rdd_idx = mt7996_get_rdd_idx(phy, false);
- if (phy->rdd_state & BIT(0))
- mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0,
- MT_RX_SEL0, 0);
- if (phy->rdd_state & BIT(1))
- mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1,
- MT_RX_SEL0, 0);
+ if (rdd_idx < 0)
+ return;
+
+ mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0);
}
-static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
+static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx)
{
int err, region;
@@ -2349,44 +2476,30 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
break;
}
- err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain,
- MT_RX_SEL0, region);
+ err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);
if (err < 0)
return err;
- return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
- MT_RX_SEL0, 1);
+ return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1);
}
static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
{
- struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
struct mt7996_dev *dev = phy->dev;
- u8 band_idx = phy->mt76->band_idx;
- int err;
+ int err, rdd_idx;
- /* start CAC */
- err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx,
- MT_RX_SEL0, 0);
- if (err < 0)
- return err;
+ rdd_idx = mt7996_get_rdd_idx(phy, false);
+ if (rdd_idx < 0)
+ return -EINVAL;
- err = mt7996_dfs_start_rdd(dev, band_idx);
+ /* start CAC */
+ err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, rdd_idx, 0);
if (err < 0)
return err;
- phy->rdd_state |= BIT(band_idx);
+ err = mt7996_dfs_start_rdd(dev, rdd_idx);
- if (chandef->width == NL80211_CHAN_WIDTH_160 ||
- chandef->width == NL80211_CHAN_WIDTH_80P80) {
- err = mt7996_dfs_start_rdd(dev, 1);
- if (err < 0)
- return err;
-
- phy->rdd_state |= BIT(1);
- }
-
- return 0;
+ return err;
}
static int
@@ -2427,12 +2540,12 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
{
struct mt7996_dev *dev = phy->dev;
enum mt76_dfs_state dfs_state, prev_state;
- int err;
+ int err, rdd_idx = mt7996_get_rdd_idx(phy, false);
prev_state = phy->mt76->dfs_state;
dfs_state = mt76_phy_dfs_state(phy->mt76);
- if (prev_state == dfs_state)
+ if (prev_state == dfs_state || rdd_idx < 0)
return 0;
if (prev_state == MT_DFS_STATE_UNKNOWN)
@@ -2456,8 +2569,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
if (dfs_state == MT_DFS_STATE_CAC)
return 0;
- err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END,
- phy->mt76->band_idx, MT_RX_SEL0, 0);
+ err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, rdd_idx, 0);
if (err < 0) {
phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
return err;
@@ -2467,8 +2579,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
return 0;
stop:
- err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START,
- phy->mt76->band_idx, MT_RX_SEL0, 0);
+ err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, rdd_idx, 0);
if (err < 0)
return err;
@@ -2553,7 +2664,7 @@ static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
}
static bool
-mt7996_mac_twt_param_equal(struct mt7996_sta *msta,
+mt7996_mac_twt_param_equal(struct mt7996_sta_link *msta_link,
struct ieee80211_twt_params *twt_agrt)
{
u16 type = le16_to_cpu(twt_agrt->req_type);
@@ -2564,10 +2675,10 @@ mt7996_mac_twt_param_equal(struct mt7996_sta *msta,
for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) {
struct mt7996_twt_flow *f;
- if (!(msta->twt.flowid_mask & BIT(i)))
+ if (!(msta_link->twt.flowid_mask & BIT(i)))
continue;
- f = &msta->twt.flow[i];
+ f = &msta_link->twt.flow[i];
if (f->duration == twt_agrt->min_twt_dur &&
f->mantissa == twt_agrt->mantissa &&
f->exp == exp &&
@@ -2587,6 +2698,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
+ struct mt7996_sta_link *msta_link = &msta->deflink;
u16 req_type = le16_to_cpu(twt_agrt->req_type);
enum ieee80211_twt_setup_cmd sta_setup_cmd;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
@@ -2601,7 +2713,8 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
goto unlock;
- if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
+ if (hweight8(msta_link->twt.flowid_mask) ==
+ ARRAY_SIZE(msta_link->twt.flow))
goto unlock;
if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) {
@@ -2610,10 +2723,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
goto unlock;
}
- if (mt7996_mac_twt_param_equal(msta, twt_agrt))
+ if (mt7996_mac_twt_param_equal(msta_link, twt_agrt))
goto unlock;
- flowid = ffs(~msta->twt.flowid_mask) - 1;
+ flowid = ffs(~msta_link->twt.flowid_mask) - 1;
twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID);
twt_agrt->req_type |= le16_encode_bits(flowid,
IEEE80211_TWT_REQTYPE_FLOWID);
@@ -2622,10 +2735,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
- flow = &msta->twt.flow[flowid];
+ flow = &msta_link->twt.flow[flowid];
memset(flow, 0, sizeof(*flow));
INIT_LIST_HEAD(&flow->list);
- flow->wcid = msta->wcid.idx;
+ flow->wcid = msta_link->wcid.idx;
flow->table_id = table_id;
flow->id = flowid;
flow->duration = twt_agrt->min_twt_dur;
@@ -2643,7 +2756,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
flow->sched = true;
flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
- curr_tsf = __mt7996_get_tsf(hw, msta->vif);
+ curr_tsf = __mt7996_get_tsf(hw, &msta->vif->deflink);
div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
flow_tsf = curr_tsf + interval - rem;
twt_agrt->twt = cpu_to_le64(flow_tsf);
@@ -2652,12 +2765,13 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
}
flow->tsf = le64_to_cpu(twt_agrt->twt);
- if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
+ if (mt7996_mcu_twt_agrt_update(dev, &msta->vif->deflink, flow,
+ MCU_TWT_AGRT_ADD))
goto unlock;
setup_cmd = TWT_SETUP_CMD_ACCEPT;
dev->twt.table_mask |= BIT(table_id);
- msta->twt.flowid_mask |= BIT(flowid);
+ msta_link->twt.flowid_mask |= BIT(flowid);
dev->twt.n_agrt++;
unlock:
@@ -2670,26 +2784,26 @@ out:
}
void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
- struct mt7996_sta *msta,
+ struct mt7996_vif_link *link,
+ struct mt7996_sta_link *msta_link,
u8 flowid)
{
struct mt7996_twt_flow *flow;
lockdep_assert_held(&dev->mt76.mutex);
- if (flowid >= ARRAY_SIZE(msta->twt.flow))
+ if (flowid >= ARRAY_SIZE(msta_link->twt.flow))
return;
- if (!(msta->twt.flowid_mask & BIT(flowid)))
+ if (!(msta_link->twt.flowid_mask & BIT(flowid)))
return;
- flow = &msta->twt.flow[flowid];
- if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
- MCU_TWT_AGRT_DELETE))
+ flow = &msta_link->twt.flow[flowid];
+ if (mt7996_mcu_twt_agrt_update(dev, link, flow, MCU_TWT_AGRT_DELETE))
return;
list_del_init(&flow->list);
- msta->twt.flowid_mask &= ~BIT(flowid);
+ msta_link->twt.flowid_mask &= ~BIT(flowid);
dev->twt.table_mask &= ~BIT(flow->table_id);
dev->twt.n_agrt--;
}