2020-04-25 03:32:27 +08:00
|
|
|
// SPDX-License-Identifier: ISC
|
|
|
|
|
/* Copyright (C) 2020 MediaTek Inc. */
|
|
|
|
|
|
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
|
#include <linux/timekeeping.h>
|
|
|
|
|
#include "mt7915.h"
|
|
|
|
|
#include "../dma.h"
|
|
|
|
|
#include "mac.h"
|
2021-09-23 16:29:32 +02:00
|
|
|
#include "mcu.h"
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
|
|
|
|
|
|
2020-04-25 03:32:33 +08:00
|
|
|
#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
|
|
|
|
|
#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
|
|
|
|
|
IEEE80211_RADIOTAP_HE_##f)
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
static const struct mt7915_dfs_radar_spec etsi_radar_specs = {
|
|
|
|
|
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
|
|
|
|
|
.radar_pattern = {
|
|
|
|
|
[5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 },
|
|
|
|
|
[6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 },
|
|
|
|
|
[7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 },
|
|
|
|
|
[8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 },
|
|
|
|
|
[9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
|
|
|
|
|
[10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
|
|
|
|
|
[11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 },
|
|
|
|
|
[12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct mt7915_dfs_radar_spec fcc_radar_specs = {
|
|
|
|
|
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
|
|
|
|
|
.radar_pattern = {
|
|
|
|
|
[0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 },
|
|
|
|
|
[1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 },
|
|
|
|
|
[2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 },
|
|
|
|
|
[3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 },
|
|
|
|
|
[4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct mt7915_dfs_radar_spec jp_radar_specs = {
|
|
|
|
|
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
|
|
|
|
|
.radar_pattern = {
|
|
|
|
|
[0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 },
|
|
|
|
|
[1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 },
|
|
|
|
|
[2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 },
|
|
|
|
|
[3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 },
|
|
|
|
|
[4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 },
|
|
|
|
|
[13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 },
|
|
|
|
|
[14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 },
|
|
|
|
|
[15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev,
|
|
|
|
|
u16 idx, bool unicast)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_sta *sta;
|
|
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
|
|
|
|
|
|
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
|
|
|
|
if (unicast || !wcid)
|
|
|
|
|
return wcid;
|
|
|
|
|
|
|
|
|
|
if (!wcid->sta)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
sta = container_of(wcid, struct mt7915_sta, wcid);
|
|
|
|
|
if (!sta->vif)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return &sta->vif->sta.wcid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
|
|
|
|
|
{
|
|
|
|
|
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
|
|
|
|
|
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
|
|
|
|
|
|
|
|
|
|
return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
|
|
|
|
|
0, 5000);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 04:57:55 +08:00
|
|
|
u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
|
|
|
|
|
FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
|
|
|
|
|
|
2021-07-14 17:18:50 +08:00
|
|
|
return MT_WTBL_LMAC_OFFS(wcid, dw);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2020-08-20 11:41:16 +02:00
|
|
|
static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
static const u8 ac_to_tid[] = {
|
|
|
|
|
[IEEE80211_AC_BE] = 0,
|
|
|
|
|
[IEEE80211_AC_BK] = 1,
|
|
|
|
|
[IEEE80211_AC_VI] = 4,
|
|
|
|
|
[IEEE80211_AC_VO] = 6
|
|
|
|
|
};
|
|
|
|
|
struct ieee80211_sta *sta;
|
|
|
|
|
struct mt7915_sta *msta;
|
2021-07-14 17:18:50 +08:00
|
|
|
struct rate_info *rate;
|
2020-04-25 03:32:27 +08:00
|
|
|
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
|
2020-08-20 11:41:16 +02:00
|
|
|
LIST_HEAD(sta_poll_list);
|
2020-04-25 03:32:27 +08:00
|
|
|
int i;
|
|
|
|
|
|
2020-08-20 11:41:16 +02:00
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
|
list_splice_init(&dev->sta_poll_list, &sta_poll_list);
|
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
bool clear = false;
|
2021-07-14 17:18:50 +08:00
|
|
|
u32 addr, val;
|
2020-04-25 03:32:27 +08:00
|
|
|
u16 idx;
|
2021-07-14 17:18:50 +08:00
|
|
|
u8 bw;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
2020-08-20 11:41:16 +02:00
|
|
|
if (list_empty(&sta_poll_list)) {
|
2020-04-25 03:32:27 +08:00
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-20 11:41:16 +02:00
|
|
|
msta = list_first_entry(&sta_poll_list,
|
2020-04-25 03:32:27 +08:00
|
|
|
struct mt7915_sta, poll_list);
|
|
|
|
|
list_del_init(&msta->poll_list);
|
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
|
2020-08-18 12:44:05 +02:00
|
|
|
idx = msta->wcid.idx;
|
2021-07-14 17:18:50 +08:00
|
|
|
addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20);
|
2020-08-18 12:44:05 +02:00
|
|
|
|
|
|
|
|
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
2020-04-25 03:32:27 +08:00
|
|
|
u32 tx_last = msta->airtime_ac[i];
|
2020-08-18 12:44:05 +02:00
|
|
|
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);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
tx_time[i] = msta->airtime_ac[i] - tx_last;
|
2020-08-18 12:44:05 +02:00
|
|
|
rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
if ((tx_last | rx_last) & BIT(30))
|
|
|
|
|
clear = true;
|
2020-08-18 12:44:05 +02:00
|
|
|
|
|
|
|
|
addr += 8;
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (clear) {
|
|
|
|
|
mt7915_mac_wtbl_update(dev, idx,
|
|
|
|
|
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
|
|
|
|
memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!msta->wcid.sta)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
sta = container_of((void *)msta, struct ieee80211_sta,
|
|
|
|
|
drv_priv);
|
|
|
|
|
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
2022-01-16 13:43:14 +01:00
|
|
|
u8 q = mt76_connac_lmac_mapping(i);
|
2020-09-01 23:41:30 +02:00
|
|
|
u32 tx_cur = tx_time[q];
|
|
|
|
|
u32 rx_cur = rx_time[q];
|
2020-04-25 03:32:27 +08:00
|
|
|
u8 tid = ac_to_tid[i];
|
|
|
|
|
|
|
|
|
|
if (!tx_cur && !rx_cur)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ieee80211_sta_register_airtime(sta, tid, tx_cur,
|
|
|
|
|
rx_cur);
|
|
|
|
|
}
|
2021-07-14 17:18:50 +08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We don't support reading GI info from txs packets.
|
|
|
|
|
* For accurate tx status reporting and AQL improvement,
|
|
|
|
|
* we need to make sure that flags match so polling GI
|
|
|
|
|
* from per-sta counters directly.
|
|
|
|
|
*/
|
|
|
|
|
rate = &msta->wcid.rate;
|
|
|
|
|
addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 7);
|
|
|
|
|
val = mt76_rr(dev, addr);
|
|
|
|
|
|
|
|
|
|
switch (rate->bw) {
|
|
|
|
|
case RATE_INFO_BW_160:
|
|
|
|
|
bw = IEEE80211_STA_RX_BW_160;
|
|
|
|
|
break;
|
|
|
|
|
case RATE_INFO_BW_80:
|
|
|
|
|
bw = IEEE80211_STA_RX_BW_80;
|
|
|
|
|
break;
|
|
|
|
|
case RATE_INFO_BW_40:
|
|
|
|
|
bw = IEEE80211_STA_RX_BW_40;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
bw = IEEE80211_STA_RX_BW_20;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
|
|
|
|
|
u8 offs = 24 + 2 * bw;
|
|
|
|
|
|
|
|
|
|
rate->he_gi = (val & (0x3 << offs)) >> offs;
|
|
|
|
|
} else if (rate->flags &
|
|
|
|
|
(RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
|
|
|
|
|
if (val & BIT(12 + bw))
|
|
|
|
|
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
|
|
|
|
else
|
|
|
|
|
rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-25 03:32:33 +08:00
|
|
|
static void
|
|
|
|
|
mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
|
2020-07-01 16:13:07 +08:00
|
|
|
struct ieee80211_radiotap_he *he,
|
|
|
|
|
__le32 *rxv)
|
2020-04-25 03:32:33 +08:00
|
|
|
{
|
|
|
|
|
u32 ru_h, ru_l;
|
|
|
|
|
u8 ru, offs = 0;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);
|
|
|
|
|
ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);
|
2020-04-25 03:32:33 +08:00
|
|
|
ru = (u8)(ru_l | ru_h << 4);
|
|
|
|
|
|
|
|
|
|
status->bw = RATE_INFO_BW_HE_RU;
|
|
|
|
|
|
|
|
|
|
switch (ru) {
|
|
|
|
|
case 0 ... 36:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
|
|
|
|
|
offs = ru;
|
|
|
|
|
break;
|
|
|
|
|
case 37 ... 52:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
|
|
|
|
|
offs = ru - 37;
|
|
|
|
|
break;
|
|
|
|
|
case 53 ... 60:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
|
|
|
|
|
offs = ru - 53;
|
|
|
|
|
break;
|
|
|
|
|
case 61 ... 64:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
|
|
|
|
|
offs = ru - 61;
|
|
|
|
|
break;
|
|
|
|
|
case 65 ... 66:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
|
|
|
|
|
offs = ru - 65;
|
|
|
|
|
break;
|
|
|
|
|
case 67:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
|
|
|
|
|
break;
|
|
|
|
|
case 68:
|
|
|
|
|
status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
|
|
|
|
|
he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
|
|
|
|
|
le16_encode_bits(offs,
|
|
|
|
|
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-23 01:35:39 +08:00
|
|
|
static void
|
2021-11-15 01:58:58 +08:00
|
|
|
mt7915_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
|
2021-06-23 01:35:39 +08:00
|
|
|
{
|
2021-11-15 01:58:58 +08:00
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
2021-06-23 01:35:39 +08:00
|
|
|
static const struct ieee80211_radiotap_he_mu mu_known = {
|
|
|
|
|
.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
|
|
|
|
|
HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
|
|
|
|
|
HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
|
|
|
|
|
HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
|
|
|
|
|
.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
|
|
|
|
|
};
|
|
|
|
|
struct ieee80211_radiotap_he_mu *he_mu = NULL;
|
|
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
status->flag |= RX_FLAG_RADIOTAP_HE_MU;
|
|
|
|
|
|
2021-06-23 01:35:39 +08:00
|
|
|
he_mu = skb_push(skb, sizeof(mu_known));
|
|
|
|
|
memcpy(he_mu, &mu_known, sizeof(mu_known));
|
|
|
|
|
|
|
|
|
|
#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
|
|
|
|
|
|
|
|
|
|
he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
|
|
|
|
|
if (status->he_dcm)
|
|
|
|
|
he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
|
|
|
|
|
|
|
|
|
|
he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
|
|
|
|
|
MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
|
|
|
|
|
le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
|
|
|
|
|
|
|
|
|
|
he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);
|
|
|
|
|
|
|
|
|
|
if (status->bw >= RATE_INFO_BW_40) {
|
|
|
|
|
he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
|
|
|
|
|
he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status->bw >= RATE_INFO_BW_80) {
|
|
|
|
|
he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2);
|
|
|
|
|
he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-25 03:32:33 +08:00
|
|
|
static void
|
2022-04-04 11:17:03 +02:00
|
|
|
mt7915_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
|
2020-04-25 03:32:33 +08:00
|
|
|
{
|
2021-11-15 01:58:58 +08:00
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
2020-04-25 03:32:33 +08:00
|
|
|
static const struct ieee80211_radiotap_he known = {
|
|
|
|
|
.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_DATA_DCM_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_STBC_KNOWN) |
|
2020-05-13 18:50:55 +08:00
|
|
|
HE_BITS(DATA1_CODING_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_DOPPLER_KNOWN) |
|
2021-06-23 01:35:39 +08:00
|
|
|
HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
|
2020-05-13 18:50:55 +08:00
|
|
|
HE_BITS(DATA1_BSS_COLOR_KNOWN),
|
2020-04-25 03:32:33 +08:00
|
|
|
.data2 = HE_BITS(DATA2_GI_KNOWN) |
|
2020-05-13 18:50:55 +08:00
|
|
|
HE_BITS(DATA2_TXBF_KNOWN) |
|
|
|
|
|
HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
|
|
|
|
|
HE_BITS(DATA2_TXOP_KNOWN),
|
2020-04-25 03:32:33 +08:00
|
|
|
};
|
|
|
|
|
struct ieee80211_radiotap_he *he = NULL;
|
2020-07-01 16:13:07 +08:00
|
|
|
u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
status->flag |= RX_FLAG_RADIOTAP_HE;
|
|
|
|
|
|
2020-04-25 03:32:33 +08:00
|
|
|
he = skb_push(skb, sizeof(known));
|
|
|
|
|
memcpy(he, &known, sizeof(known));
|
|
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
|
|
|
|
|
HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
|
2021-06-23 01:35:39 +08:00
|
|
|
he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
|
2020-07-01 16:13:07 +08:00
|
|
|
he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
|
2020-04-25 03:32:33 +08:00
|
|
|
le16_encode_bits(ltf_size,
|
|
|
|
|
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
|
2021-06-23 01:35:39 +08:00
|
|
|
if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
|
|
|
|
|
he->data5 |= HE_BITS(DATA5_TXBF);
|
2020-07-01 16:13:07 +08:00
|
|
|
he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
|
|
|
|
|
HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
switch (mode) {
|
2020-04-25 03:32:33 +08:00
|
|
|
case MT_PHY_TYPE_HE_SU:
|
|
|
|
|
he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
|
|
|
|
|
HE_BITS(DATA1_UL_DL_KNOWN) |
|
2022-03-16 00:24:34 +08:00
|
|
|
HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
|
|
|
|
|
HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
|
2020-04-25 03:32:33 +08:00
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HE_EXT_SU:
|
|
|
|
|
he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
|
2022-03-16 00:24:34 +08:00
|
|
|
HE_BITS(DATA1_UL_DL_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
|
2020-04-25 03:32:33 +08:00
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HE_MU:
|
|
|
|
|
he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
|
2021-06-23 01:35:39 +08:00
|
|
|
HE_BITS(DATA1_UL_DL_KNOWN);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
|
2021-06-23 01:35:39 +08:00
|
|
|
he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
mt7915_mac_decode_he_radiotap_ru(status, he, rxv);
|
2021-11-15 01:58:58 +08:00
|
|
|
mt7915_mac_decode_he_mu_radiotap(skb, rxv);
|
2020-04-25 03:32:33 +08:00
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HE_TB:
|
|
|
|
|
he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
|
|
|
|
|
HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
|
|
|
|
|
HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
|
|
|
|
|
|
2022-01-18 11:12:07 +01:00
|
|
|
he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |
|
|
|
|
|
HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
|
2020-07-01 16:13:07 +08:00
|
|
|
HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |
|
|
|
|
|
HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
mt7915_mac_decode_he_radiotap_ru(status, he, rxv);
|
2020-04-25 03:32:33 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 12:19:31 +08:00
|
|
|
/* The HW does not translate the mac header to 802.3 for mesh point */
|
|
|
|
|
static int mt7915_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
|
|
|
|
|
{
|
|
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
2022-01-11 16:10:05 +01:00
|
|
|
struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
|
2021-11-10 12:19:31 +08:00
|
|
|
struct mt7915_sta *msta = (struct mt7915_sta *)status->wcid;
|
2022-01-11 16:10:05 +01:00
|
|
|
__le32 *rxd = (__le32 *)skb->data;
|
2021-11-10 12:19:31 +08:00
|
|
|
struct ieee80211_sta *sta;
|
|
|
|
|
struct ieee80211_vif *vif;
|
|
|
|
|
struct ieee80211_hdr hdr;
|
2022-02-06 19:53:23 +01:00
|
|
|
u16 frame_control;
|
2021-11-10 12:19:31 +08:00
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
|
2021-11-10 12:19:31 +08:00
|
|
|
MT_RXD3_NORMAL_U2M)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (!msta || !msta->vif)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
|
|
|
|
|
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
|
|
|
|
|
|
|
|
|
|
/* store the info from RXD and ethhdr to avoid being overridden */
|
2022-02-06 19:53:23 +01:00
|
|
|
frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL);
|
|
|
|
|
hdr.frame_control = cpu_to_le16(frame_control);
|
|
|
|
|
hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL));
|
2021-11-10 12:19:31 +08:00
|
|
|
hdr.duration_id = 0;
|
2022-02-06 19:53:23 +01:00
|
|
|
|
2021-11-10 12:19:31 +08:00
|
|
|
ether_addr_copy(hdr.addr1, vif->addr);
|
|
|
|
|
ether_addr_copy(hdr.addr2, sta->addr);
|
2022-02-06 19:53:23 +01:00
|
|
|
switch (frame_control & (IEEE80211_FCTL_TODS |
|
|
|
|
|
IEEE80211_FCTL_FROMDS)) {
|
2021-11-10 12:19:31 +08:00
|
|
|
case 0:
|
|
|
|
|
ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
|
|
|
|
|
break;
|
|
|
|
|
case IEEE80211_FCTL_FROMDS:
|
2022-01-11 16:10:05 +01:00
|
|
|
ether_addr_copy(hdr.addr3, eth_hdr->h_source);
|
2021-11-10 12:19:31 +08:00
|
|
|
break;
|
|
|
|
|
case IEEE80211_FCTL_TODS:
|
2022-01-11 16:10:05 +01:00
|
|
|
ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
|
2021-11-10 12:19:31 +08:00
|
|
|
break;
|
|
|
|
|
case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
|
2022-01-11 16:10:05 +01:00
|
|
|
ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
|
|
|
|
|
ether_addr_copy(hdr.addr4, eth_hdr->h_source);
|
2021-11-10 12:19:31 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
|
2022-01-11 16:10:05 +01:00
|
|
|
if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
|
|
|
|
|
eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
|
2021-11-10 12:19:31 +08:00
|
|
|
ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
|
2022-02-06 19:53:23 +01:00
|
|
|
else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
|
2021-11-10 12:19:31 +08:00
|
|
|
ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
|
|
|
|
|
else
|
|
|
|
|
skb_pull(skb, 2);
|
|
|
|
|
|
|
|
|
|
if (ieee80211_has_order(hdr.frame_control))
|
2022-02-06 19:53:23 +01:00
|
|
|
memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9],
|
|
|
|
|
IEEE80211_HT_CTL_LEN);
|
|
|
|
|
if (ieee80211_is_data_qos(hdr.frame_control)) {
|
|
|
|
|
__le16 qos_ctrl;
|
|
|
|
|
|
|
|
|
|
qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL));
|
|
|
|
|
memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
|
|
|
|
|
IEEE80211_QOS_CTL_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 12:19:31 +08:00
|
|
|
if (ieee80211_has_a4(hdr.frame_control))
|
|
|
|
|
memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
|
|
|
|
|
else
|
|
|
|
|
memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 10:18:01 +08:00
|
|
|
static int
|
|
|
|
|
mt7915_mac_fill_rx_rate(struct mt7915_dev *dev,
|
|
|
|
|
struct mt76_rx_status *status,
|
|
|
|
|
struct ieee80211_supported_band *sband,
|
2022-04-04 11:17:03 +02:00
|
|
|
__le32 *rxv, u8 *mode)
|
2021-12-20 10:18:01 +08:00
|
|
|
{
|
|
|
|
|
u32 v0, v2;
|
2022-04-04 11:17:03 +02:00
|
|
|
u8 stbc, gi, bw, dcm, nss;
|
2021-12-20 10:18:01 +08:00
|
|
|
int i, idx;
|
|
|
|
|
bool cck = false;
|
|
|
|
|
|
|
|
|
|
v0 = le32_to_cpu(rxv[0]);
|
|
|
|
|
v2 = le32_to_cpu(rxv[2]);
|
|
|
|
|
|
|
|
|
|
idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0);
|
|
|
|
|
nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
|
|
|
|
|
|
|
|
|
|
if (!is_mt7915(&dev->mt76)) {
|
|
|
|
|
stbc = FIELD_GET(MT_PRXV_HT_STBC, v0);
|
|
|
|
|
gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v0);
|
2022-04-04 11:17:03 +02:00
|
|
|
*mode = FIELD_GET(MT_PRXV_TX_MODE, v0);
|
2021-12-20 10:18:01 +08:00
|
|
|
dcm = FIELD_GET(MT_PRXV_DCM, v0);
|
|
|
|
|
bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0);
|
|
|
|
|
} else {
|
|
|
|
|
stbc = FIELD_GET(MT_CRXV_HT_STBC, v2);
|
|
|
|
|
gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2);
|
2022-04-04 11:17:03 +02:00
|
|
|
*mode = FIELD_GET(MT_CRXV_TX_MODE, v2);
|
2021-12-20 10:18:01 +08:00
|
|
|
dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM);
|
|
|
|
|
bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-04 11:17:03 +02:00
|
|
|
switch (*mode) {
|
2021-12-20 10:18:01 +08:00
|
|
|
case MT_PHY_TYPE_CCK:
|
|
|
|
|
cck = true;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case MT_PHY_TYPE_OFDM:
|
|
|
|
|
i = mt76_get_rate(&dev->mt76, sband, i, cck);
|
|
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HT_GF:
|
|
|
|
|
case MT_PHY_TYPE_HT:
|
|
|
|
|
status->encoding = RX_ENC_HT;
|
|
|
|
|
if (gi)
|
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
|
|
|
|
if (i > 31)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_VHT:
|
|
|
|
|
status->nss = nss;
|
|
|
|
|
status->encoding = RX_ENC_VHT;
|
|
|
|
|
if (gi)
|
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
2022-03-25 21:14:26 +01:00
|
|
|
if (i > 11)
|
2021-12-20 10:18:01 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HE_MU:
|
|
|
|
|
case MT_PHY_TYPE_HE_SU:
|
|
|
|
|
case MT_PHY_TYPE_HE_EXT_SU:
|
|
|
|
|
case MT_PHY_TYPE_HE_TB:
|
|
|
|
|
status->nss = nss;
|
|
|
|
|
status->encoding = RX_ENC_HE;
|
|
|
|
|
i &= GENMASK(3, 0);
|
|
|
|
|
|
|
|
|
|
if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
|
|
|
|
|
status->he_gi = gi;
|
|
|
|
|
|
|
|
|
|
status->he_dcm = dcm;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
status->rate_idx = i;
|
|
|
|
|
|
|
|
|
|
switch (bw) {
|
|
|
|
|
case IEEE80211_STA_RX_BW_20:
|
|
|
|
|
break;
|
|
|
|
|
case IEEE80211_STA_RX_BW_40:
|
2022-04-04 11:17:03 +02:00
|
|
|
if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
|
2021-12-20 10:18:01 +08:00
|
|
|
(idx & MT_PRXV_TX_ER_SU_106T)) {
|
|
|
|
|
status->bw = RATE_INFO_BW_HE_RU;
|
|
|
|
|
status->he_ru =
|
|
|
|
|
NL80211_RATE_INFO_HE_RU_ALLOC_106;
|
|
|
|
|
} else {
|
|
|
|
|
status->bw = RATE_INFO_BW_40;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case IEEE80211_STA_RX_BW_80:
|
|
|
|
|
status->bw = RATE_INFO_BW_80;
|
|
|
|
|
break;
|
|
|
|
|
case IEEE80211_STA_RX_BW_160:
|
|
|
|
|
status->bw = RATE_INFO_BW_160;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
|
2022-04-04 11:17:03 +02:00
|
|
|
if (*mode < MT_PHY_TYPE_HE_SU && gi)
|
2021-12-20 10:18:01 +08:00
|
|
|
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-07 12:52:42 +02:00
|
|
|
static int
|
|
|
|
|
mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
|
|
|
|
struct mt76_phy *mphy = &dev->mt76.phy;
|
|
|
|
|
struct mt7915_phy *phy = &dev->phy;
|
|
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
|
|
__le32 *rxd = (__le32 *)skb->data;
|
2020-07-01 16:13:07 +08:00
|
|
|
__le32 *rxv = NULL;
|
2020-12-16 19:04:24 +01:00
|
|
|
u32 rxd0 = le32_to_cpu(rxd[0]);
|
2020-04-25 03:32:27 +08:00
|
|
|
u32 rxd1 = le32_to_cpu(rxd[1]);
|
|
|
|
|
u32 rxd2 = le32_to_cpu(rxd[2]);
|
|
|
|
|
u32 rxd3 = le32_to_cpu(rxd[3]);
|
2020-10-11 23:37:12 +02:00
|
|
|
u32 rxd4 = le32_to_cpu(rxd[4]);
|
2020-12-16 19:04:24 +01:00
|
|
|
u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
|
2020-04-25 03:32:27 +08:00
|
|
|
bool unicast, insert_ccmp_hdr = false;
|
2020-10-11 23:37:12 +02:00
|
|
|
u8 remove_pad, amsdu_info;
|
2022-04-04 11:17:03 +02:00
|
|
|
u8 mode = 0, qos_ctl = 0;
|
2020-12-16 21:13:13 +01:00
|
|
|
bool hdr_trans;
|
2021-11-10 12:19:31 +08:00
|
|
|
u16 hdr_gap;
|
2020-12-16 21:13:13 +01:00
|
|
|
u16 seq_ctrl = 0;
|
|
|
|
|
__le16 fc = 0;
|
2022-02-04 20:11:01 +01:00
|
|
|
int idx;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
memset(status, 0, sizeof(*status));
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->band_idx) {
|
2020-04-25 03:32:27 +08:00
|
|
|
mphy = dev->mt76.phy2;
|
|
|
|
|
if (!mphy)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
phy = mphy->priv;
|
|
|
|
|
status->ext_phy = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2020-10-11 23:37:12 +02:00
|
|
|
if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2021-11-19 14:37:06 +08:00
|
|
|
hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
|
|
|
|
|
if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
/* ICV error or CCMP/BIP/WPI MIC error */
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
|
|
|
|
|
status->flag |= RX_FLAG_ONLY_MONITOR;
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
|
|
|
|
|
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
|
|
|
|
|
status->wcid = mt7915_rx_get_wcid(dev, idx, unicast);
|
|
|
|
|
|
|
|
|
|
if (status->wcid) {
|
|
|
|
|
struct mt7915_sta *msta;
|
|
|
|
|
|
|
|
|
|
msta = container_of(status->wcid, struct mt7915_sta, wcid);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status->freq = mphy->chandef.chan->center_freq;
|
|
|
|
|
status->band = mphy->chandef.chan->band;
|
|
|
|
|
if (status->band == NL80211_BAND_5GHZ)
|
|
|
|
|
sband = &mphy->sband_5g.sband;
|
2022-03-07 15:10:26 +08:00
|
|
|
else if (status->band == NL80211_BAND_6GHZ)
|
|
|
|
|
sband = &mphy->sband_6g.sband;
|
2020-04-25 03:32:27 +08:00
|
|
|
else
|
|
|
|
|
sband = &mphy->sband_2g.sband;
|
|
|
|
|
|
|
|
|
|
if (!sband->channels)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2020-12-16 19:04:24 +01:00
|
|
|
if ((rxd0 & csum_mask) == csum_mask)
|
|
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
if (rxd1 & MT_RXD1_NORMAL_FCS_ERR)
|
|
|
|
|
status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
|
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
|
|
|
|
|
status->flag |= RX_FLAG_MMIC_ERROR;
|
|
|
|
|
|
|
|
|
|
if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 &&
|
|
|
|
|
!(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
|
|
|
|
|
status->flag |= RX_FLAG_DECRYPTED;
|
|
|
|
|
status->flag |= RX_FLAG_IV_STRIPPED;
|
|
|
|
|
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
|
|
|
|
|
|
|
|
|
|
if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
rxd += 6;
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
|
2020-12-16 21:13:13 +01:00
|
|
|
u32 v0 = le32_to_cpu(rxd[0]);
|
|
|
|
|
u32 v2 = le32_to_cpu(rxd[2]);
|
|
|
|
|
|
|
|
|
|
fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0));
|
|
|
|
|
qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2);
|
|
|
|
|
seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2);
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
rxd += 4;
|
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
|
|
|
|
|
u8 *data = (u8 *)rxd;
|
|
|
|
|
|
|
|
|
|
if (status->flag & RX_FLAG_DECRYPTED) {
|
2021-06-17 15:17:49 +08:00
|
|
|
switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) {
|
|
|
|
|
case MT_CIPHER_AES_CCMP:
|
|
|
|
|
case MT_CIPHER_CCMP_CCX:
|
|
|
|
|
case MT_CIPHER_CCMP_256:
|
|
|
|
|
insert_ccmp_hdr =
|
|
|
|
|
FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
|
|
|
|
|
fallthrough;
|
|
|
|
|
case MT_CIPHER_TKIP:
|
|
|
|
|
case MT_CIPHER_TKIP_NO_MIC:
|
|
|
|
|
case MT_CIPHER_GCMP:
|
|
|
|
|
case MT_CIPHER_GCMP_256:
|
|
|
|
|
status->iv[0] = data[5];
|
|
|
|
|
status->iv[1] = data[4];
|
|
|
|
|
status->iv[2] = data[3];
|
|
|
|
|
status->iv[3] = data[2];
|
|
|
|
|
status->iv[4] = data[1];
|
|
|
|
|
status->iv[5] = data[0];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
rxd += 4;
|
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
|
2021-03-30 01:25:00 +08:00
|
|
|
status->timestamp = le32_to_cpu(rxd[0]);
|
|
|
|
|
status->flag |= RX_FLAG_MACTIME_START;
|
|
|
|
|
|
|
|
|
|
if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
|
|
|
|
|
status->flag |= RX_FLAG_AMPDU_DETAILS;
|
|
|
|
|
|
|
|
|
|
/* all subframes of an A-MPDU have the same timestamp */
|
|
|
|
|
if (phy->rx_ampdu_ts != status->timestamp) {
|
|
|
|
|
if (!++phy->ampdu_ref)
|
|
|
|
|
phy->ampdu_ref++;
|
|
|
|
|
}
|
|
|
|
|
phy->rx_ampdu_ts = status->timestamp;
|
|
|
|
|
|
|
|
|
|
status->ampdu_ref = phy->ampdu_ref;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
rxd += 2;
|
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* RXD Group 3 - P-RXV */
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
|
2021-12-20 10:18:01 +08:00
|
|
|
u32 v0, v1;
|
|
|
|
|
int ret;
|
2020-05-19 02:07:38 +08:00
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
rxv = rxd;
|
2020-04-25 03:32:27 +08:00
|
|
|
rxd += 2;
|
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2020-07-01 16:13:07 +08:00
|
|
|
v0 = le32_to_cpu(rxv[0]);
|
|
|
|
|
v1 = le32_to_cpu(rxv[1]);
|
2020-05-19 02:07:38 +08:00
|
|
|
|
|
|
|
|
if (v0 & MT_PRXV_HT_AD_CODE)
|
2020-04-25 03:32:27 +08:00
|
|
|
status->enc_flags |= RX_ENC_FLAG_LDPC;
|
|
|
|
|
|
|
|
|
|
status->chains = mphy->antenna_mask;
|
2020-05-19 02:07:38 +08:00
|
|
|
status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1);
|
|
|
|
|
status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1);
|
|
|
|
|
status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1);
|
|
|
|
|
status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
/* RXD Group 5 - C-RXV */
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
|
|
|
|
|
rxd += 18;
|
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
|
return -EINVAL;
|
2021-12-20 10:18:01 +08:00
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-23 11:03:44 +08:00
|
|
|
if (!is_mt7915(&dev->mt76) || (rxd1 & MT_RXD1_NORMAL_GROUP_5)) {
|
2022-04-04 11:17:03 +02:00
|
|
|
ret = mt7915_mac_fill_rx_rate(dev, status, sband, rxv,
|
|
|
|
|
&mode);
|
2021-12-20 10:18:01 +08:00
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-11 23:37:12 +02:00
|
|
|
amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
|
|
|
|
|
status->amsdu = !!amsdu_info;
|
|
|
|
|
if (status->amsdu) {
|
|
|
|
|
status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
|
|
|
|
|
status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
|
2021-11-10 12:19:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
|
|
|
|
|
if (hdr_trans && ieee80211_has_morefrags(fc)) {
|
|
|
|
|
if (mt7915_reverse_frag0_hdr_trans(skb, hdr_gap))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
hdr_trans = false;
|
|
|
|
|
} else {
|
2021-11-23 11:37:47 +01:00
|
|
|
int pad_start = 0;
|
|
|
|
|
|
2021-11-10 12:19:31 +08:00
|
|
|
skb_pull(skb, hdr_gap);
|
|
|
|
|
if (!hdr_trans && status->amsdu) {
|
2021-11-23 11:37:47 +01:00
|
|
|
pad_start = ieee80211_get_hdrlen_from_skb(skb);
|
|
|
|
|
} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
|
|
|
|
|
/*
|
|
|
|
|
* When header translation failure is indicated,
|
|
|
|
|
* the hardware will insert an extra 2-byte field
|
|
|
|
|
* containing the data length after the protocol
|
|
|
|
|
* type field.
|
|
|
|
|
*/
|
|
|
|
|
pad_start = 12;
|
|
|
|
|
if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
|
|
|
|
|
pad_start += 4;
|
|
|
|
|
|
|
|
|
|
if (get_unaligned_be16(skb->data + pad_start) !=
|
|
|
|
|
skb->len - pad_start - 2)
|
|
|
|
|
pad_start = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pad_start) {
|
|
|
|
|
memmove(skb->data + 2, skb->data, pad_start);
|
2020-12-16 21:13:13 +01:00
|
|
|
skb_pull(skb, 2);
|
|
|
|
|
}
|
2020-10-11 23:37:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
if (!hdr_trans) {
|
2021-12-03 14:04:54 +08:00
|
|
|
struct ieee80211_hdr *hdr;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
if (insert_ccmp_hdr) {
|
|
|
|
|
u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
|
|
|
|
|
|
|
|
|
|
mt76_insert_ccmp_hdr(skb, key_id);
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-12-03 14:04:54 +08:00
|
|
|
hdr = mt76_skb_get_hdr(skb);
|
2020-12-16 21:13:13 +01:00
|
|
|
fc = hdr->frame_control;
|
|
|
|
|
if (ieee80211_is_data_qos(fc)) {
|
|
|
|
|
seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
|
|
|
|
|
qos_ctl = *ieee80211_get_qos_ctl(hdr);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
status->flag |= RX_FLAG_8023;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
|
|
|
|
|
mt7915_mac_decode_he_radiotap(skb, rxv, mode);
|
2020-04-25 03:32:33 +08:00
|
|
|
|
2020-12-16 21:13:13 +01:00
|
|
|
if (!status->wcid || !ieee80211_is_data_qos(fc))
|
2020-04-25 03:32:27 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
status->aggr = unicast &&
|
2020-12-16 21:13:13 +01:00
|
|
|
!ieee80211_is_qos_nullfunc(fc);
|
|
|
|
|
status->qos_ctl = qos_ctl;
|
|
|
|
|
status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-07 12:52:42 +02:00
|
|
|
static void
|
|
|
|
|
mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
|
2020-10-22 10:28:18 +08:00
|
|
|
{
|
2021-05-07 12:52:42 +02:00
|
|
|
#ifdef CONFIG_NL80211_TESTMODE
|
2020-12-04 17:36:58 +08:00
|
|
|
struct mt7915_phy *phy = &dev->phy;
|
2020-10-22 10:28:18 +08:00
|
|
|
__le32 *rxd = (__le32 *)skb->data;
|
2020-12-04 17:36:58 +08:00
|
|
|
__le32 *rxv_hdr = rxd + 2;
|
2020-10-22 10:28:18 +08:00
|
|
|
__le32 *rxv = rxd + 4;
|
|
|
|
|
u32 rcpi, ib_rssi, wb_rssi, v20, v21;
|
2022-02-09 14:11:57 +08:00
|
|
|
u8 band_idx;
|
2020-10-22 10:28:18 +08:00
|
|
|
s32 foe;
|
|
|
|
|
u8 snr;
|
|
|
|
|
int i;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
band_idx = le32_get_bits(rxv_hdr[1], MT_RXV_HDR_BAND_IDX);
|
2022-04-04 10:23:15 +02:00
|
|
|
if (band_idx && !phy->band_idx) {
|
2020-12-04 17:36:58 +08:00
|
|
|
phy = mt7915_ext_phy(dev);
|
2022-04-04 10:23:15 +02:00
|
|
|
if (!phy)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2020-12-04 17:36:58 +08:00
|
|
|
|
2020-10-22 10:28:18 +08:00
|
|
|
rcpi = le32_to_cpu(rxv[6]);
|
|
|
|
|
ib_rssi = le32_to_cpu(rxv[7]);
|
|
|
|
|
wb_rssi = le32_to_cpu(rxv[8]) >> 5;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++, rcpi >>= 8, ib_rssi >>= 8, wb_rssi >>= 9) {
|
|
|
|
|
if (i == 3)
|
|
|
|
|
wb_rssi = le32_to_cpu(rxv[9]);
|
|
|
|
|
|
2020-12-04 17:36:58 +08:00
|
|
|
phy->test.last_rcpi[i] = rcpi & 0xff;
|
|
|
|
|
phy->test.last_ib_rssi[i] = ib_rssi & 0xff;
|
|
|
|
|
phy->test.last_wb_rssi[i] = wb_rssi & 0xff;
|
2020-10-22 10:28:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v20 = le32_to_cpu(rxv[20]);
|
|
|
|
|
v21 = le32_to_cpu(rxv[21]);
|
|
|
|
|
|
|
|
|
|
foe = FIELD_GET(MT_CRXV_FOE_LO, v20) |
|
|
|
|
|
(FIELD_GET(MT_CRXV_FOE_HI, v21) << MT_CRXV_FOE_SHIFT);
|
|
|
|
|
|
|
|
|
|
snr = FIELD_GET(MT_CRXV_SNR, v20) - 16;
|
|
|
|
|
|
2020-12-04 17:36:58 +08:00
|
|
|
phy->test.last_freq_offset = foe;
|
|
|
|
|
phy->test.last_snr = snr;
|
2022-04-04 10:23:15 +02:00
|
|
|
out:
|
2021-05-07 12:52:42 +02:00
|
|
|
#endif
|
2020-10-22 10:28:18 +08:00
|
|
|
dev_kfree_skb(skb);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 10:28:17 +08:00
|
|
|
static void
|
2020-12-04 17:36:56 +08:00
|
|
|
mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
|
|
|
|
|
struct sk_buff *skb)
|
2020-10-22 10:28:17 +08:00
|
|
|
{
|
|
|
|
|
#ifdef CONFIG_NL80211_TESTMODE
|
2020-12-04 17:36:56 +08:00
|
|
|
struct mt76_testmode_data *td = &phy->mt76->test;
|
2021-04-12 13:39:54 +08:00
|
|
|
const struct ieee80211_rate *r;
|
|
|
|
|
u8 bw, mode, nss = td->tx_rate_nss;
|
2020-10-22 10:28:17 +08:00
|
|
|
u8 rate_idx = td->tx_rate_idx;
|
|
|
|
|
u16 rateval = 0;
|
|
|
|
|
u32 val;
|
2021-04-12 13:39:54 +08:00
|
|
|
bool cck = false;
|
|
|
|
|
int band;
|
2020-10-22 10:28:17 +08:00
|
|
|
|
2020-12-04 17:36:56 +08:00
|
|
|
if (skb != phy->mt76->test.tx_skb)
|
2020-10-22 10:28:17 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (td->tx_rate_mode) {
|
|
|
|
|
case MT76_TM_TX_MODE_HT:
|
|
|
|
|
nss = 1 + (rate_idx >> 3);
|
|
|
|
|
mode = MT_PHY_TYPE_HT;
|
|
|
|
|
break;
|
|
|
|
|
case MT76_TM_TX_MODE_VHT:
|
|
|
|
|
mode = MT_PHY_TYPE_VHT;
|
|
|
|
|
break;
|
|
|
|
|
case MT76_TM_TX_MODE_HE_SU:
|
|
|
|
|
mode = MT_PHY_TYPE_HE_SU;
|
|
|
|
|
break;
|
|
|
|
|
case MT76_TM_TX_MODE_HE_EXT_SU:
|
|
|
|
|
mode = MT_PHY_TYPE_HE_EXT_SU;
|
|
|
|
|
break;
|
|
|
|
|
case MT76_TM_TX_MODE_HE_TB:
|
|
|
|
|
mode = MT_PHY_TYPE_HE_TB;
|
|
|
|
|
break;
|
|
|
|
|
case MT76_TM_TX_MODE_HE_MU:
|
|
|
|
|
mode = MT_PHY_TYPE_HE_MU;
|
|
|
|
|
break;
|
2021-04-12 13:39:54 +08:00
|
|
|
case MT76_TM_TX_MODE_CCK:
|
|
|
|
|
cck = true;
|
|
|
|
|
fallthrough;
|
2020-10-22 10:28:17 +08:00
|
|
|
case MT76_TM_TX_MODE_OFDM:
|
2021-04-12 13:39:54 +08:00
|
|
|
band = phy->mt76->chandef.chan->band;
|
|
|
|
|
if (band == NL80211_BAND_2GHZ && !cck)
|
|
|
|
|
rate_idx += 4;
|
|
|
|
|
|
|
|
|
|
r = &phy->mt76->hw->wiphy->bands[band]->bitrates[rate_idx];
|
|
|
|
|
val = cck ? r->hw_value_short : r->hw_value;
|
|
|
|
|
|
|
|
|
|
mode = val >> 8;
|
|
|
|
|
rate_idx = val & 0xff;
|
|
|
|
|
break;
|
2020-10-22 10:28:17 +08:00
|
|
|
default:
|
|
|
|
|
mode = MT_PHY_TYPE_OFDM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 17:36:56 +08:00
|
|
|
switch (phy->mt76->chandef.width) {
|
2020-10-22 10:28:17 +08:00
|
|
|
case NL80211_CHAN_WIDTH_40:
|
|
|
|
|
bw = 1;
|
|
|
|
|
break;
|
|
|
|
|
case NL80211_CHAN_WIDTH_80:
|
|
|
|
|
bw = 2;
|
|
|
|
|
break;
|
|
|
|
|
case NL80211_CHAN_WIDTH_80P80:
|
|
|
|
|
case NL80211_CHAN_WIDTH_160:
|
|
|
|
|
bw = 3;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
bw = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (td->tx_rate_stbc && nss == 1) {
|
|
|
|
|
nss++;
|
|
|
|
|
rateval |= MT_TX_RATE_STBC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rateval |= FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
|
|
|
|
|
FIELD_PREP(MT_TX_RATE_MODE, mode) |
|
|
|
|
|
FIELD_PREP(MT_TX_RATE_NSS, nss - 1);
|
|
|
|
|
|
|
|
|
|
txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
|
|
|
|
|
|
|
|
|
|
le32p_replace_bits(&txwi[3], 1, MT_TXD3_REM_TX_COUNT);
|
|
|
|
|
if (td->tx_rate_mode < MT76_TM_TX_MODE_HT)
|
|
|
|
|
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
|
|
|
|
|
|
|
|
|
|
val = MT_TXD6_FIXED_BW |
|
|
|
|
|
FIELD_PREP(MT_TXD6_BW, bw) |
|
|
|
|
|
FIELD_PREP(MT_TXD6_TX_RATE, rateval) |
|
|
|
|
|
FIELD_PREP(MT_TXD6_SGI, td->tx_rate_sgi);
|
|
|
|
|
|
|
|
|
|
/* for HE_SU/HE_EXT_SU PPDU
|
|
|
|
|
* - 1x, 2x, 4x LTF + 0.8us GI
|
|
|
|
|
* - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
|
|
|
|
|
* for HE_MU PPDU
|
|
|
|
|
* - 2x, 4x LTF + 0.8us GI
|
|
|
|
|
* - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
|
|
|
|
|
* for HE_TB PPDU
|
|
|
|
|
* - 1x, 2x LTF + 1.6us GI
|
|
|
|
|
* - 4x LTF + 3.2us GI
|
|
|
|
|
*/
|
|
|
|
|
if (mode >= MT_PHY_TYPE_HE_SU)
|
|
|
|
|
val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
|
|
|
|
|
|
2021-04-12 13:39:54 +08:00
|
|
|
if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU))
|
2020-10-22 10:28:17 +08:00
|
|
|
val |= MT_TXD6_LDPC;
|
|
|
|
|
|
2021-04-12 13:39:54 +08:00
|
|
|
txwi[3] &= ~cpu_to_le32(MT_TXD3_SN_VALID);
|
2020-10-22 10:28:17 +08:00
|
|
|
txwi[6] |= cpu_to_le32(val);
|
|
|
|
|
txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX,
|
2020-12-04 17:36:58 +08:00
|
|
|
phy->test.spe_idx));
|
2020-10-22 10:28:17 +08:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-17 07:30:54 +02:00
|
|
|
static void
|
|
|
|
|
mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi,
|
|
|
|
|
struct sk_buff *skb, struct mt76_wcid *wcid)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
|
|
u8 fc_type, fc_stype;
|
2022-04-20 14:29:00 +02:00
|
|
|
u16 ethertype;
|
2020-08-17 07:30:54 +02:00
|
|
|
bool wmm = false;
|
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
|
|
if (wcid->sta) {
|
|
|
|
|
struct ieee80211_sta *sta;
|
|
|
|
|
|
|
|
|
|
sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
|
|
|
|
|
wmm = sta->wme;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
|
|
|
|
|
FIELD_PREP(MT_TXD1_TID, tid);
|
|
|
|
|
|
2022-04-20 14:29:00 +02:00
|
|
|
ethertype = get_unaligned_be16(&skb->data[12]);
|
|
|
|
|
if (ethertype >= ETH_P_802_3_MIN)
|
2020-08-17 07:30:54 +02:00
|
|
|
val |= MT_TXD1_ETH_802_3;
|
|
|
|
|
|
|
|
|
|
txwi[1] |= cpu_to_le32(val);
|
|
|
|
|
|
|
|
|
|
fc_type = IEEE80211_FTYPE_DATA >> 2;
|
|
|
|
|
fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
|
|
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
|
|
|
|
|
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
|
|
|
|
|
|
|
|
|
|
txwi[2] |= cpu_to_le32(val);
|
|
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
|
|
|
|
|
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
|
|
|
|
|
txwi[7] |= cpu_to_le32(val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
|
2021-07-21 10:03:52 +08:00
|
|
|
struct sk_buff *skb, struct ieee80211_key_conf *key,
|
|
|
|
|
bool *mcast)
|
2020-08-17 07:30:54 +02:00
|
|
|
{
|
|
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
|
|
__le16 fc = hdr->frame_control;
|
|
|
|
|
u8 fc_type, fc_stype;
|
|
|
|
|
u32 val;
|
|
|
|
|
|
2021-07-21 10:03:52 +08:00
|
|
|
*mcast = is_multicast_ether_addr(hdr->addr1);
|
|
|
|
|
|
2020-08-17 07:30:54 +02:00
|
|
|
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_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, tid);
|
|
|
|
|
txwi[1] |= cpu_to_le32(val);
|
|
|
|
|
|
|
|
|
|
fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
|
|
|
|
|
fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
|
|
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
|
|
|
|
|
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
|
2021-07-21 10:03:52 +08:00
|
|
|
FIELD_PREP(MT_TXD2_MULTICAST, *mcast);
|
2020-08-17 07:30:54 +02:00
|
|
|
|
2021-07-21 10:03:52 +08:00
|
|
|
if (key && *mcast && ieee80211_is_robust_mgmt_frame(skb) &&
|
2020-08-17 07:30:54 +02:00
|
|
|
key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
|
|
|
|
|
val |= MT_TXD2_BIP;
|
|
|
|
|
txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-21 10:03:52 +08:00
|
|
|
if (!ieee80211_is_data(fc) || *mcast ||
|
2021-07-17 13:05:48 +08:00
|
|
|
info->flags & IEEE80211_TX_CTL_USE_MINRATE)
|
2020-08-17 07:30:54 +02:00
|
|
|
val |= MT_TXD2_FIX_RATE;
|
|
|
|
|
|
|
|
|
|
txwi[2] |= cpu_to_le32(val);
|
|
|
|
|
|
|
|
|
|
if (ieee80211_is_beacon(fc)) {
|
|
|
|
|
txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
|
|
|
|
|
txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
|
2022-03-05 07:42:24 +08:00
|
|
|
txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, 0x18));
|
2020-08-17 07:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (info->flags & IEEE80211_TX_CTL_INJECTED) {
|
|
|
|
|
u16 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));
|
|
|
|
|
txwi[3] |= cpu_to_le32(val);
|
2022-02-04 16:47:30 +01:00
|
|
|
txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);
|
2020-08-17 07:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
|
|
|
|
|
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
|
|
|
|
|
txwi[7] |= cpu_to_le32(val);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-29 04:01:02 +08:00
|
|
|
static u16
|
|
|
|
|
mt7915_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif,
|
|
|
|
|
bool beacon, bool mcast)
|
|
|
|
|
{
|
|
|
|
|
u8 mode = 0, band = mphy->chandef.chan->band;
|
|
|
|
|
int rateidx = 0, mcast_rate;
|
|
|
|
|
|
|
|
|
|
if (beacon) {
|
|
|
|
|
struct cfg80211_bitrate_mask *mask;
|
|
|
|
|
|
|
|
|
|
mask = &vif->bss_conf.beacon_tx_rate;
|
|
|
|
|
if (hweight16(mask->control[band].he_mcs[0]) == 1) {
|
|
|
|
|
rateidx = ffs(mask->control[band].he_mcs[0]) - 1;
|
|
|
|
|
mode = MT_PHY_TYPE_HE_SU;
|
|
|
|
|
goto out;
|
|
|
|
|
} else if (hweight16(mask->control[band].vht_mcs[0]) == 1) {
|
|
|
|
|
rateidx = ffs(mask->control[band].vht_mcs[0]) - 1;
|
|
|
|
|
mode = MT_PHY_TYPE_VHT;
|
|
|
|
|
goto out;
|
|
|
|
|
} else if (hweight8(mask->control[band].ht_mcs[0]) == 1) {
|
|
|
|
|
rateidx = ffs(mask->control[band].ht_mcs[0]) - 1;
|
|
|
|
|
mode = MT_PHY_TYPE_HT;
|
|
|
|
|
goto out;
|
|
|
|
|
} else if (hweight32(mask->control[band].legacy) == 1) {
|
|
|
|
|
rateidx = ffs(mask->control[band].legacy) - 1;
|
|
|
|
|
goto legacy;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mcast_rate = vif->bss_conf.mcast_rate[band];
|
|
|
|
|
if (mcast && mcast_rate > 0)
|
|
|
|
|
rateidx = mcast_rate - 1;
|
|
|
|
|
else
|
|
|
|
|
rateidx = ffs(vif->bss_conf.basic_rates) - 1;
|
|
|
|
|
|
|
|
|
|
legacy:
|
|
|
|
|
rateidx = mt76_calculate_default_rate(mphy, rateidx);
|
|
|
|
|
mode = rateidx >> 8;
|
|
|
|
|
rateidx &= GENMASK(7, 0);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
|
|
|
|
|
FIELD_PREP(MT_TX_RATE_MODE, mode);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
2021-05-07 15:18:09 +02:00
|
|
|
struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
|
2022-04-26 10:23:35 +08:00
|
|
|
struct ieee80211_key_conf *key, u32 changed)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
|
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;
|
2022-02-09 14:11:57 +08:00
|
|
|
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0;
|
2020-08-17 07:30:54 +02:00
|
|
|
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
|
2021-07-21 10:03:52 +08:00
|
|
|
bool mcast = false;
|
2020-08-17 07:30:54 +02:00
|
|
|
u16 tx_count = 15;
|
2020-04-25 03:32:27 +08:00
|
|
|
u32 val;
|
2022-04-26 10:23:35 +08:00
|
|
|
bool beacon = !!(changed & (BSS_CHANGED_BEACON |
|
|
|
|
|
BSS_CHANGED_BEACON_ENABLED));
|
|
|
|
|
bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
|
|
|
|
|
BSS_CHANGED_FILS_DISCOVERY));
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
if (vif) {
|
|
|
|
|
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
|
|
|
|
|
|
2021-12-14 11:41:06 +01:00
|
|
|
omac_idx = mvif->mt76.omac_idx;
|
|
|
|
|
wmm_idx = mvif->mt76.wmm_idx;
|
2022-02-09 14:11:57 +08:00
|
|
|
band_idx = mvif->mt76.band_idx;
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ext_phy && dev->mt76.phy2)
|
|
|
|
|
mphy = dev->mt76.phy2;
|
|
|
|
|
|
2022-04-26 10:23:35 +08:00
|
|
|
if (inband_disc) {
|
|
|
|
|
p_fmt = MT_TX_TYPE_FW;
|
|
|
|
|
q_idx = MT_LMAC_ALTX0;
|
|
|
|
|
} else if (beacon) {
|
2020-04-25 03:32:27 +08:00
|
|
|
p_fmt = MT_TX_TYPE_FW;
|
2020-06-22 10:16:55 +08:00
|
|
|
q_idx = MT_LMAC_BCN0;
|
|
|
|
|
} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
|
|
|
|
|
p_fmt = MT_TX_TYPE_CT;
|
2020-04-25 03:32:27 +08:00
|
|
|
q_idx = MT_LMAC_ALTX0;
|
2020-06-22 10:16:55 +08:00
|
|
|
} else {
|
2020-04-25 03:32:27 +08:00
|
|
|
p_fmt = MT_TX_TYPE_CT;
|
2020-06-22 10:16:55 +08:00
|
|
|
q_idx = wmm_idx * MT7915_MAX_WMM_SETS +
|
2022-01-16 13:43:14 +01:00
|
|
|
mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
txwi[0] = cpu_to_le32(val);
|
|
|
|
|
|
2021-10-18 16:07:05 +08:00
|
|
|
val = MT_TXD1_LONG_FORMAT | MT_TXD1_VTA |
|
2020-04-25 03:32:27 +08:00
|
|
|
FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
|
|
|
|
|
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
|
2020-06-22 10:16:55 +08:00
|
|
|
|
2022-03-11 22:44:25 +08:00
|
|
|
if (ext_phy || band_idx)
|
2020-05-19 02:07:38 +08:00
|
|
|
val |= MT_TXD1_TGID;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
txwi[1] = cpu_to_le32(val);
|
|
|
|
|
|
2020-08-17 07:30:54 +02:00
|
|
|
txwi[2] = 0;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-08-17 07:30:54 +02:00
|
|
|
val = MT_TXD3_SW_POWER_MGMT |
|
|
|
|
|
FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
|
|
|
|
|
if (key)
|
|
|
|
|
val |= MT_TXD3_PROTECT_FRAME;
|
|
|
|
|
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
|
|
|
|
|
val |= MT_TXD3_NO_ACK;
|
|
|
|
|
|
|
|
|
|
txwi[3] = cpu_to_le32(val);
|
|
|
|
|
txwi[4] = 0;
|
2021-05-07 15:18:09 +02:00
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD5_PID, pid);
|
|
|
|
|
if (pid >= MT_PACKET_ID_FIRST)
|
|
|
|
|
val |= MT_TXD5_TX_STATUS_HOST;
|
|
|
|
|
txwi[5] = cpu_to_le32(val);
|
|
|
|
|
|
2020-08-17 07:30:54 +02:00
|
|
|
txwi[6] = 0;
|
|
|
|
|
txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
|
|
|
|
|
|
|
|
|
|
if (is_8023)
|
|
|
|
|
mt7915_mac_write_txwi_8023(dev, txwi, skb, wcid);
|
|
|
|
|
else
|
2021-07-21 10:03:52 +08:00
|
|
|
mt7915_mac_write_txwi_80211(dev, txwi, skb, key, &mcast);
|
2020-08-17 07:30:54 +02:00
|
|
|
|
|
|
|
|
if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {
|
2021-08-29 04:01:02 +08:00
|
|
|
u16 rate = mt7915_mac_tx_rate_val(mphy, vif, beacon, mcast);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
/* hardware won't add HTC for mgmt/ctrl frame */
|
2020-08-17 07:30:54 +02:00
|
|
|
txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
val = MT_TXD6_FIXED_BW |
|
|
|
|
|
FIELD_PREP(MT_TXD6_TX_RATE, rate);
|
|
|
|
|
txwi[6] |= cpu_to_le32(val);
|
|
|
|
|
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
|
|
|
|
|
}
|
2020-10-22 10:28:17 +08:00
|
|
|
|
2020-12-04 17:36:56 +08:00
|
|
|
if (mt76_testmode_enabled(mphy))
|
|
|
|
|
mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int mt7915_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 mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
|
|
|
|
|
struct ieee80211_key_conf *key = info->control.hw_key;
|
|
|
|
|
struct ieee80211_vif *vif = info->control.vif;
|
|
|
|
|
struct mt76_txwi_cache *t;
|
|
|
|
|
struct mt7915_txp *txp;
|
|
|
|
|
int id, i, nbuf = tx_info->nbuf - 1;
|
|
|
|
|
u8 *txwi = (u8 *)txwi_ptr;
|
2021-05-07 15:18:09 +02:00
|
|
|
int pid;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-12-29 12:15:30 +08:00
|
|
|
if (unlikely(tx_info->skb->len <= ETH_HLEN))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
if (!wcid)
|
|
|
|
|
wcid = &dev->mt76.global_wcid;
|
|
|
|
|
|
2021-07-14 17:18:50 +08:00
|
|
|
if (sta) {
|
|
|
|
|
struct mt7915_sta *msta;
|
|
|
|
|
|
|
|
|
|
msta = (struct mt7915_sta *)sta->drv_priv;
|
|
|
|
|
|
2021-07-14 17:18:51 +08:00
|
|
|
if (time_after(jiffies, msta->jiffies + HZ / 4)) {
|
2021-07-14 17:18:50 +08:00
|
|
|
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
2021-07-14 17:18:51 +08:00
|
|
|
msta->jiffies = jiffies;
|
2021-07-14 17:18:50 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-22 18:34:03 +01:00
|
|
|
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
|
|
|
|
|
t->skb = tx_info->skb;
|
|
|
|
|
|
|
|
|
|
id = mt76_token_consume(mdev, &t);
|
|
|
|
|
if (id < 0)
|
|
|
|
|
return id;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-11-22 18:34:03 +01:00
|
|
|
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
|
2022-04-26 10:23:35 +08:00
|
|
|
mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, 0);
|
2020-08-17 07:30:54 +02:00
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
|
|
|
|
|
for (i = 0; i < nbuf; i++) {
|
|
|
|
|
txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
|
|
|
|
|
txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
|
|
|
|
|
}
|
|
|
|
|
txp->nbuf = nbuf;
|
|
|
|
|
|
2020-08-21 08:42:46 +02:00
|
|
|
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
if (!key)
|
|
|
|
|
txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
|
|
|
|
|
|
2020-08-17 07:30:54 +02:00
|
|
|
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
|
|
|
|
|
ieee80211_is_mgmt(hdr->frame_control))
|
2020-04-25 03:32:27 +08:00
|
|
|
txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
|
|
|
|
|
|
|
|
|
|
if (vif) {
|
|
|
|
|
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
|
|
|
|
|
|
2021-12-14 11:41:06 +01:00
|
|
|
txp->bss_idx = mvif->mt76.idx;
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
txp->token = cpu_to_le16(id);
|
2020-08-21 08:42:46 +02:00
|
|
|
if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
|
|
|
|
|
txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
|
|
|
|
|
else
|
|
|
|
|
txp->rept_wds_wcid = cpu_to_le16(0x3ff);
|
2020-04-25 03:32:27 +08:00
|
|
|
tx_info->skb = DMA_DUMMY_DATA;
|
|
|
|
|
|
2021-02-16 14:51:19 +01:00
|
|
|
/* 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;
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_txp *txp = ptr + MT_TXD_SIZE;
|
|
|
|
|
__le32 *txwi = ptr;
|
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
|
|
memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp));
|
|
|
|
|
|
|
|
|
|
val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) |
|
|
|
|
|
FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT);
|
|
|
|
|
txwi[0] = cpu_to_le32(val);
|
|
|
|
|
|
|
|
|
|
val = MT_TXD1_LONG_FORMAT |
|
|
|
|
|
FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3);
|
|
|
|
|
txwi[1] = cpu_to_le32(val);
|
|
|
|
|
|
|
|
|
|
txp->token = cpu_to_le16(token_id);
|
|
|
|
|
txp->nbuf = 1;
|
|
|
|
|
txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp));
|
|
|
|
|
|
|
|
|
|
return MT_TXD_SIZE + sizeof(*txp);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
static void
|
2020-07-28 23:30:08 +02:00
|
|
|
mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
struct mt7915_sta *msta;
|
2020-07-28 23:30:08 +02:00
|
|
|
u16 fc, tid;
|
|
|
|
|
u32 val;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
mac80211: prepare sta handling for MLO support
Currently in mac80211 each STA object is represented
using sta_info datastructure with the associated
STA specific information and drivers access ieee80211_sta
part of it.
With MLO (Multi Link Operation) support being added
in 802.11be standard, though the association is logically
with a single Multi Link capable STA, at the physical level
communication can happen via different advertised
links (uniquely identified by Channel, operating class,
BSSID) and hence the need to handle multiple link
STA parameters within a composite sta_info object
called the MLD STA. The different link STA part of
MLD STA are identified using the link address which can
be same or different as the MLD STA address and unique
link id based on the link vif.
To support extension of such a model, the sta_info
datastructure is modified to hold multiple link STA
objects with link specific params currently within
sta_info moved to this new structure. Similarly this is
done for ieee80211_sta as well which will be accessed
within mac80211 as well as by drivers, hence trivial
driver changes are expected to support this.
For current non MLO supported drivers, only one link STA
is present and link information is accessed via 'deflink'
member.
For MLO drivers, we still need to define the APIs etc. to
get the correct link ID and access the correct part of
the station info.
Currently in mac80211, all link STA info are accessed directly
via deflink. These will be updated to access via link pointers
indexed by link id with MLO support patches, with link id
being 0 for non MLO supported cases.
Except for couple of macro related changes, below spatch takes
care of updating mac80211 and driver code to access to the
link STA info via deflink.
@ieee80211_sta@
struct ieee80211_sta *s;
struct sta_info *si;
identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr};
@@
(
s->
- var
+ deflink.var
|
si->sta.
- var
+ deflink.var
)
@sta_info@
struct sta_info *si;
identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth};
@@
(
si->
- var
+ deflink.var
)
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com
[remove MLO-drivers notes from commit message, not clear yet; run spatch]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 21:11:23 +05:30
|
|
|
if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
|
2020-04-25 03:32:27 +08:00
|
|
|
return;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
tid = le32_get_bits(txwi[1], MT_TXD1_TID);
|
2020-07-28 23:30:08 +02:00
|
|
|
if (tid >= 6) /* skip VO queue */
|
2020-04-25 03:32:27 +08:00
|
|
|
return;
|
|
|
|
|
|
2020-07-28 23:30:08 +02:00
|
|
|
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)))
|
2020-04-25 03:32:27 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
msta = (struct mt7915_sta *)sta->drv_priv;
|
2020-07-28 23:30:08 +02:00
|
|
|
if (!test_and_set_bit(tid, &msta->ampdu_state))
|
2020-04-25 03:32:27 +08:00
|
|
|
ieee80211_start_tx_ba_session(sta, tid, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 17:46:19 +02:00
|
|
|
static void
|
2021-05-07 18:51:41 +02:00
|
|
|
mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
2021-05-07 18:51:41 +02:00
|
|
|
struct mt7915_txp *txp;
|
|
|
|
|
int i;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-05-07 18:51:41 +02:00
|
|
|
txp = mt7915_txwi_to_txp(dev, t);
|
|
|
|
|
for (i = 0; i < txp->nbuf; i++)
|
2021-12-06 13:45:54 +01:00
|
|
|
dma_unmap_single(dev->dma_dev, le32_to_cpu(txp->buf[i]),
|
2021-05-07 18:51:41 +02:00
|
|
|
le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-05-07 18:51:41 +02:00
|
|
|
static void
|
|
|
|
|
mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
|
|
|
|
|
struct ieee80211_sta *sta, struct list_head *free_list)
|
|
|
|
|
{
|
|
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
2021-12-06 13:45:54 +01:00
|
|
|
struct mt7915_sta *msta;
|
2021-05-07 18:51:41 +02:00
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
|
__le32 *txwi;
|
|
|
|
|
u16 wcid_idx;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-05-07 18:51:41 +02:00
|
|
|
mt7915_txp_skb_unmap(mdev, t);
|
|
|
|
|
if (!t->skb)
|
|
|
|
|
goto out;
|
2020-10-22 10:28:17 +08:00
|
|
|
|
2021-05-07 18:51:41 +02:00
|
|
|
txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
|
|
|
|
|
if (sta) {
|
|
|
|
|
wcid = (struct mt76_wcid *)sta->drv_priv;
|
|
|
|
|
wcid_idx = wcid->idx;
|
|
|
|
|
} else {
|
2022-03-09 14:29:24 +08:00
|
|
|
wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
|
2021-12-06 13:45:54 +01:00
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[wcid_idx]);
|
|
|
|
|
|
|
|
|
|
if (wcid && wcid->sta) {
|
|
|
|
|
msta = container_of(wcid, struct mt7915_sta, wcid);
|
|
|
|
|
sta = container_of((void *)msta, struct ieee80211_sta,
|
|
|
|
|
drv_priv);
|
|
|
|
|
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);
|
|
|
|
|
}
|
2020-10-22 10:28:17 +08:00
|
|
|
}
|
|
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
|
|
|
|
mt7915_tx_check_aggr(sta, txwi);
|
|
|
|
|
|
2021-05-07 18:51:41 +02:00
|
|
|
__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
t->skb = NULL;
|
|
|
|
|
mt76_put_txwi(mdev, t);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
static void
|
|
|
|
|
mt7915_mac_tx_free_prepare(struct mt7915_dev *dev)
|
|
|
|
|
{
|
|
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
|
|
|
|
struct mt76_phy *mphy_ext = mdev->phy2;
|
|
|
|
|
|
|
|
|
|
/* clean DMA queues and unmap buffers first */
|
|
|
|
|
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
|
|
|
|
|
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
|
|
|
|
|
if (mphy_ext) {
|
|
|
|
|
mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false);
|
|
|
|
|
mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mt7915_mac_tx_free_done(struct mt7915_dev *dev,
|
|
|
|
|
struct list_head *free_list, bool wake)
|
|
|
|
|
{
|
|
|
|
|
struct sk_buff *skb, *tmp;
|
|
|
|
|
|
|
|
|
|
mt7915_mac_sta_poll(dev);
|
|
|
|
|
|
|
|
|
|
if (wake)
|
|
|
|
|
mt76_set_tx_blocked(&dev->mt76, false);
|
|
|
|
|
|
|
|
|
|
mt76_worker_schedule(&dev->mt76.tx_worker);
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(skb, tmp, free_list, list) {
|
|
|
|
|
skb_list_del_init(skb);
|
|
|
|
|
napi_consume_skb(skb, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-07 12:52:42 +02:00
|
|
|
static void
|
2021-12-03 18:02:41 +01:00
|
|
|
mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
2021-12-03 18:02:41 +01:00
|
|
|
struct mt7915_tx_free *free = (struct mt7915_tx_free *)data;
|
2020-04-25 03:32:27 +08:00
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
|
|
|
|
struct mt76_txwi_cache *txwi;
|
|
|
|
|
struct ieee80211_sta *sta = NULL;
|
2020-09-01 17:46:19 +02:00
|
|
|
LIST_HEAD(free_list);
|
2021-12-03 18:02:41 +01:00
|
|
|
void *end = data + len;
|
2021-12-20 10:18:00 +08:00
|
|
|
bool v3, wake = false;
|
|
|
|
|
u16 total, count = 0;
|
|
|
|
|
u32 txd = le32_to_cpu(free->txd);
|
2022-02-11 18:14:00 +01:00
|
|
|
__le32 *cur_info;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
mt7915_mac_tx_free_prepare(dev);
|
2020-08-22 14:41:42 +02:00
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT);
|
2021-12-20 10:18:00 +08:00
|
|
|
v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4);
|
|
|
|
|
if (WARN_ON_ONCE((void *)&free->info[total >> v3] > end))
|
2021-12-03 18:02:41 +01:00
|
|
|
return;
|
|
|
|
|
|
2021-12-20 10:18:00 +08:00
|
|
|
for (cur_info = &free->info[0]; count < total; cur_info++) {
|
|
|
|
|
u32 msdu, info = le32_to_cpu(*cur_info);
|
|
|
|
|
u8 i;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 1'b1: new wcid pair.
|
|
|
|
|
* 1'b0: msdu_id with the same 'wcid pair' as above.
|
|
|
|
|
*/
|
|
|
|
|
if (info & MT_TX_FREE_PAIR) {
|
|
|
|
|
struct mt7915_sta *msta;
|
|
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
|
u16 idx;
|
|
|
|
|
|
|
|
|
|
idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
|
|
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
|
|
|
|
sta = wcid_to_sta(wcid);
|
|
|
|
|
if (!sta)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
msta = container_of(wcid, struct mt7915_sta, wcid);
|
2020-07-26 20:45:58 +02:00
|
|
|
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);
|
2020-09-27 16:36:25 +02:00
|
|
|
continue;
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2021-12-20 10:18:00 +08:00
|
|
|
if (v3 && (info & MT_TX_FREE_MPDU_HEADER))
|
2020-04-25 03:32:27 +08:00
|
|
|
continue;
|
|
|
|
|
|
2021-12-20 10:18:00 +08:00
|
|
|
for (i = 0; i < 1 + v3; i++) {
|
|
|
|
|
if (v3) {
|
|
|
|
|
msdu = (info >> (15 * i)) & MT_TX_FREE_MSDU_ID_V3;
|
|
|
|
|
if (msdu == MT_TX_FREE_MSDU_ID_V3)
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
|
|
|
|
|
}
|
|
|
|
|
count++;
|
|
|
|
|
txwi = mt76_token_release(mdev, msdu, &wake);
|
|
|
|
|
if (!txwi)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
mt7915_txwi_free(dev, txwi, sta, &free_list);
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
2020-08-20 11:41:16 +02:00
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
mt7915_mac_tx_free_done(dev, &free_list, wake);
|
|
|
|
|
}
|
2020-11-21 16:00:14 +01:00
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
static void
|
|
|
|
|
mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_tx_free *free = (struct mt7915_tx_free *)data;
|
|
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
|
|
|
|
__le16 *info = (__le16 *)free->info;
|
|
|
|
|
void *end = data + len;
|
|
|
|
|
LIST_HEAD(free_list);
|
|
|
|
|
bool wake = false;
|
|
|
|
|
u8 i, count;
|
2020-11-21 16:00:14 +01:00
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
mt7915_mac_tx_free_prepare(dev);
|
2020-09-01 17:46:19 +02:00
|
|
|
|
2021-12-06 13:45:54 +01:00
|
|
|
count = FIELD_GET(MT_TX_FREE_MSDU_CNT_V0, le16_to_cpu(free->ctrl));
|
|
|
|
|
if (WARN_ON_ONCE((void *)&info[count] > end))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
struct mt76_txwi_cache *txwi;
|
|
|
|
|
u16 msdu = le16_to_cpu(info[i]);
|
|
|
|
|
|
|
|
|
|
txwi = mt76_token_release(mdev, msdu, &wake);
|
|
|
|
|
if (!txwi)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
mt7915_txwi_free(dev, txwi, NULL, &free_list);
|
2020-09-01 17:46:19 +02:00
|
|
|
}
|
2021-12-06 13:45:54 +01:00
|
|
|
|
|
|
|
|
mt7915_mac_tx_free_done(dev, &free_list, wake);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-07 15:18:09 +02:00
|
|
|
static bool
|
|
|
|
|
mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid,
|
2021-10-19 12:12:23 +02:00
|
|
|
__le32 *txs_data, struct mt76_sta_stats *stats)
|
2021-05-07 15:18:09 +02:00
|
|
|
{
|
2021-07-14 17:18:50 +08:00
|
|
|
struct ieee80211_supported_band *sband;
|
2021-05-07 15:18:09 +02:00
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
2021-07-14 17:18:50 +08:00
|
|
|
struct mt76_phy *mphy;
|
2021-05-07 15:18:09 +02:00
|
|
|
struct ieee80211_tx_info *info;
|
|
|
|
|
struct sk_buff_head list;
|
2021-07-14 17:18:50 +08:00
|
|
|
struct rate_info rate = {};
|
2021-05-07 15:18:09 +02:00
|
|
|
struct sk_buff *skb;
|
2021-07-14 17:18:50 +08:00
|
|
|
bool cck = false;
|
2021-08-04 06:43:30 -07:00
|
|
|
u32 txrate, txs, mode;
|
2021-05-07 15:18:09 +02:00
|
|
|
|
|
|
|
|
mt76_tx_status_lock(mdev, &list);
|
|
|
|
|
skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
|
|
|
|
|
if (!skb)
|
2021-08-19 13:49:43 -07:00
|
|
|
goto out_no_skb;
|
2021-05-07 15:18:09 +02:00
|
|
|
|
2021-07-14 17:18:50 +08:00
|
|
|
txs = le32_to_cpu(txs_data[0]);
|
|
|
|
|
|
2021-05-07 15:18:09 +02:00
|
|
|
info = IEEE80211_SKB_CB(skb);
|
2021-07-14 17:18:50 +08:00
|
|
|
if (!(txs & MT_TXS0_ACK_ERROR_MASK))
|
2021-05-07 15:18:09 +02:00
|
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
|
|
|
|
|
|
|
|
info->status.ampdu_len = 1;
|
|
|
|
|
info->status.ampdu_ack_len = !!(info->flags &
|
|
|
|
|
IEEE80211_TX_STAT_ACK);
|
|
|
|
|
|
|
|
|
|
info->status.rates[0].idx = -1;
|
2021-07-14 17:18:50 +08:00
|
|
|
|
|
|
|
|
txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
|
|
|
|
|
|
|
|
|
|
rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
|
|
|
|
|
rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
|
|
|
|
|
|
2021-08-04 06:43:30 -07:00
|
|
|
if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
|
|
|
|
|
stats->tx_nss[rate.nss - 1]++;
|
|
|
|
|
if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
|
|
|
|
|
stats->tx_mcs[rate.mcs]++;
|
|
|
|
|
|
|
|
|
|
mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
|
|
|
|
|
switch (mode) {
|
2021-07-14 17:18:50 +08:00
|
|
|
case MT_PHY_TYPE_CCK:
|
|
|
|
|
cck = true;
|
|
|
|
|
fallthrough;
|
|
|
|
|
case MT_PHY_TYPE_OFDM:
|
|
|
|
|
mphy = &dev->mphy;
|
|
|
|
|
if (wcid->ext_phy && dev->mt76.phy2)
|
|
|
|
|
mphy = dev->mt76.phy2;
|
|
|
|
|
|
|
|
|
|
if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
|
|
|
|
|
sband = &mphy->sband_5g.sband;
|
2022-03-07 15:10:26 +08:00
|
|
|
else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
|
|
|
|
|
sband = &mphy->sband_6g.sband;
|
2021-07-14 17:18:50 +08:00
|
|
|
else
|
|
|
|
|
sband = &mphy->sband_2g.sband;
|
|
|
|
|
|
|
|
|
|
rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
|
|
|
|
|
rate.legacy = sband->bitrates[rate.mcs].bitrate;
|
|
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HT:
|
|
|
|
|
case MT_PHY_TYPE_HT_GF:
|
|
|
|
|
if (rate.mcs > 31)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rate.flags = RATE_INFO_FLAGS_MCS;
|
|
|
|
|
if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
|
|
|
|
|
rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
|
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_VHT:
|
|
|
|
|
if (rate.mcs > 9)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rate.flags = RATE_INFO_FLAGS_VHT_MCS;
|
|
|
|
|
break;
|
|
|
|
|
case MT_PHY_TYPE_HE_SU:
|
|
|
|
|
case MT_PHY_TYPE_HE_EXT_SU:
|
|
|
|
|
case MT_PHY_TYPE_HE_TB:
|
|
|
|
|
case MT_PHY_TYPE_HE_MU:
|
|
|
|
|
if (rate.mcs > 11)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rate.he_gi = wcid->rate.he_gi;
|
|
|
|
|
rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
|
|
|
|
|
rate.flags = RATE_INFO_FLAGS_HE_MCS;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-04 06:43:30 -07:00
|
|
|
stats->tx_mode[mode]++;
|
|
|
|
|
|
2021-07-14 17:18:50 +08:00
|
|
|
switch (FIELD_GET(MT_TXS0_BW, txs)) {
|
|
|
|
|
case IEEE80211_STA_RX_BW_160:
|
|
|
|
|
rate.bw = RATE_INFO_BW_160;
|
2021-08-04 06:43:30 -07:00
|
|
|
stats->tx_bw[3]++;
|
2021-07-14 17:18:50 +08:00
|
|
|
break;
|
|
|
|
|
case IEEE80211_STA_RX_BW_80:
|
|
|
|
|
rate.bw = RATE_INFO_BW_80;
|
2021-08-04 06:43:30 -07:00
|
|
|
stats->tx_bw[2]++;
|
2021-07-14 17:18:50 +08:00
|
|
|
break;
|
|
|
|
|
case IEEE80211_STA_RX_BW_40:
|
|
|
|
|
rate.bw = RATE_INFO_BW_40;
|
2021-08-04 06:43:30 -07:00
|
|
|
stats->tx_bw[1]++;
|
2021-07-14 17:18:50 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
rate.bw = RATE_INFO_BW_20;
|
2021-08-04 06:43:30 -07:00
|
|
|
stats->tx_bw[0]++;
|
2021-07-14 17:18:50 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
wcid->rate = rate;
|
2021-05-07 15:18:09 +02:00
|
|
|
|
|
|
|
|
out:
|
2021-07-14 17:18:50 +08:00
|
|
|
mt76_tx_status_skb_done(mdev, skb, &list);
|
2021-08-19 13:49:43 -07:00
|
|
|
|
|
|
|
|
out_no_skb:
|
2021-05-07 15:18:09 +02:00
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
|
|
|
|
|
|
|
|
|
return !!skb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_sta *msta = NULL;
|
|
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
|
__le32 *txs_data = data;
|
|
|
|
|
u16 wcidx;
|
|
|
|
|
u8 pid;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
|
2021-05-07 15:18:09 +02:00
|
|
|
return;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
|
|
|
|
|
pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
|
2021-05-07 15:18:09 +02:00
|
|
|
|
|
|
|
|
if (pid < MT_PACKET_ID_FIRST)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-12-20 10:17:59 +08:00
|
|
|
if (wcidx >= mt7915_wtbl_size(dev))
|
2021-05-07 15:18:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
|
|
|
|
if (!wcid)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2021-08-04 06:43:30 -07:00
|
|
|
msta = container_of(wcid, struct mt7915_sta, wcid);
|
|
|
|
|
|
|
|
|
|
mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats);
|
2021-05-07 15:18:09 +02:00
|
|
|
|
|
|
|
|
if (!wcid->sta)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-03 18:02:41 +01:00
|
|
|
bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
|
|
|
|
__le32 *rxd = (__le32 *)data;
|
|
|
|
|
__le32 *end = (__le32 *)&rxd[len / 4];
|
|
|
|
|
enum rx_pkt_type type;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
|
|
|
|
|
|
2021-12-03 18:02:41 +01:00
|
|
|
switch (type) {
|
|
|
|
|
case PKT_TYPE_TXRX_NOTIFY:
|
|
|
|
|
mt7915_mac_tx_free(dev, data, len);
|
|
|
|
|
return false;
|
2021-12-06 13:45:54 +01:00
|
|
|
case PKT_TYPE_TXRX_NOTIFY_V0:
|
|
|
|
|
mt7915_mac_tx_free_v0(dev, data, len);
|
|
|
|
|
return false;
|
2021-12-03 18:02:41 +01:00
|
|
|
case PKT_TYPE_TXS:
|
|
|
|
|
for (rxd += 2; rxd + 8 <= end; rxd += 8)
|
|
|
|
|
mt7915_mac_add_txs(dev, rxd);
|
|
|
|
|
return false;
|
2021-12-26 22:18:32 +01:00
|
|
|
case PKT_TYPE_RX_FW_MONITOR:
|
|
|
|
|
mt7915_debugfs_rx_fw_monitor(dev, data, len);
|
|
|
|
|
return false;
|
2021-12-03 18:02:41 +01:00
|
|
|
default:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-07 12:52:42 +02:00
|
|
|
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|
|
|
|
struct sk_buff *skb)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
|
|
|
|
__le32 *rxd = (__le32 *)skb->data;
|
2021-05-07 15:18:09 +02:00
|
|
|
__le32 *end = (__le32 *)&skb->data[skb->len];
|
2021-05-07 12:52:42 +02:00
|
|
|
enum rx_pkt_type type;
|
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
|
2021-05-07 12:52:42 +02:00
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case PKT_TYPE_TXRX_NOTIFY:
|
2021-12-03 18:02:41 +01:00
|
|
|
mt7915_mac_tx_free(dev, skb->data, skb->len);
|
|
|
|
|
napi_consume_skb(skb, 1);
|
2021-05-07 12:52:42 +02:00
|
|
|
break;
|
2021-12-06 13:45:54 +01:00
|
|
|
case PKT_TYPE_TXRX_NOTIFY_V0:
|
|
|
|
|
mt7915_mac_tx_free_v0(dev, skb->data, skb->len);
|
|
|
|
|
napi_consume_skb(skb, 1);
|
|
|
|
|
break;
|
2021-05-07 12:52:42 +02:00
|
|
|
case PKT_TYPE_RX_EVENT:
|
|
|
|
|
mt7915_mcu_rx_event(dev, skb);
|
|
|
|
|
break;
|
|
|
|
|
case PKT_TYPE_TXRXV:
|
|
|
|
|
mt7915_mac_fill_rx_vector(dev, skb);
|
|
|
|
|
break;
|
2021-05-07 15:18:09 +02:00
|
|
|
case PKT_TYPE_TXS:
|
|
|
|
|
for (rxd += 2; rxd + 8 <= end; rxd += 8)
|
|
|
|
|
mt7915_mac_add_txs(dev, rxd);
|
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
|
break;
|
2021-12-26 22:18:32 +01:00
|
|
|
case PKT_TYPE_RX_FW_MONITOR:
|
|
|
|
|
mt7915_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
|
2022-02-08 21:12:30 +08:00
|
|
|
dev_kfree_skb(skb);
|
2021-12-26 22:18:32 +01:00
|
|
|
break;
|
2021-05-07 12:52:42 +02:00
|
|
|
case PKT_TYPE_NORMAL:
|
|
|
|
|
if (!mt7915_mac_fill_rx(dev, skb)) {
|
|
|
|
|
mt76_rx(&dev->mt76, q, skb);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fallthrough;
|
|
|
|
|
default:
|
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-23 15:08:02 +02:00
|
|
|
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
if (!e->txwi) {
|
|
|
|
|
dev_kfree_skb_any(e->skb);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* error path */
|
|
|
|
|
if (e->skb == DMA_DUMMY_DATA) {
|
|
|
|
|
struct mt76_txwi_cache *t;
|
|
|
|
|
struct mt7915_txp *txp;
|
|
|
|
|
|
|
|
|
|
txp = mt7915_txwi_to_txp(mdev, e->txwi);
|
2021-04-20 23:05:32 +02:00
|
|
|
t = mt76_token_put(mdev, le16_to_cpu(txp->token));
|
2020-04-25 03:32:27 +08:00
|
|
|
e->skb = t ? t->skb : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-07 18:51:41 +02:00
|
|
|
if (e->skb)
|
|
|
|
|
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
2022-02-09 14:11:57 +08:00
|
|
|
u32 reg = MT_WF_PHY_RX_CTRL1(phy->band_idx);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-04-09 00:36:31 +08:00
|
|
|
mt76_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN);
|
|
|
|
|
mt76_set(dev, reg, BIT(11) | BIT(9));
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mt7915_mac_reset_counters(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
2022-02-09 14:11:57 +08:00
|
|
|
mt76_rr(dev, MT_TX_AGG_CNT(phy->band_idx, i));
|
|
|
|
|
mt76_rr(dev, MT_TX_AGG_CNT2(phy->band_idx, i));
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
i = 0;
|
|
|
|
|
phy->mt76->survey_time = ktime_get_boottime();
|
|
|
|
|
if (phy->band_idx)
|
2020-04-25 03:32:27 +08:00
|
|
|
i = ARRAY_SIZE(dev->mt76.aggr_stats) / 2;
|
2022-02-09 14:11:57 +08:00
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2);
|
|
|
|
|
|
|
|
|
|
/* reset airtime counters */
|
2022-02-09 14:11:57 +08:00
|
|
|
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(phy->band_idx),
|
2020-04-25 03:32:27 +08:00
|
|
|
MT_WF_RMAC_MIB_RXTIME_CLR);
|
2021-05-15 12:17:29 +08:00
|
|
|
|
|
|
|
|
mt7915_mcu_get_chan_mib_info(phy, true);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mt7915_mac_set_timing(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
s16 coverage_class = phy->coverage_class;
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
2022-02-09 14:11:57 +08:00
|
|
|
struct mt7915_phy *ext_phy = mt7915_ext_phy(dev);
|
2020-04-25 03:32:27 +08:00
|
|
|
u32 val, reg_offset;
|
|
|
|
|
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
|
|
|
|
|
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
|
|
|
|
|
u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
|
|
|
|
|
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
|
2021-08-16 08:32:26 +08:00
|
|
|
int offset;
|
2022-03-07 15:10:26 +08:00
|
|
|
bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
|
|
|
|
|
return;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
if (ext_phy)
|
2020-04-25 03:32:27 +08:00
|
|
|
coverage_class = max_t(s16, dev->phy.coverage_class,
|
2022-02-09 14:11:57 +08:00
|
|
|
ext_phy->coverage_class);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
mt76_set(dev, MT_ARB_SCR(phy->band_idx),
|
2020-04-25 03:32:27 +08:00
|
|
|
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
|
|
|
|
|
udelay(1);
|
|
|
|
|
|
|
|
|
|
offset = 3 * coverage_class;
|
|
|
|
|
reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
|
|
|
|
|
FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
mt76_wr(dev, MT_TMAC_CDTR(phy->band_idx), cck + reg_offset);
|
|
|
|
|
mt76_wr(dev, MT_TMAC_ODTR(phy->band_idx), ofdm + reg_offset);
|
|
|
|
|
mt76_wr(dev, MT_TMAC_ICR0(phy->band_idx),
|
2022-03-07 15:10:26 +08:00
|
|
|
FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) |
|
2020-04-25 03:32:27 +08:00
|
|
|
FIELD_PREP(MT_IFS_RIFS, 2) |
|
2021-08-16 08:32:26 +08:00
|
|
|
FIELD_PREP(MT_IFS_SIFS, 10) |
|
2020-04-25 03:32:27 +08:00
|
|
|
FIELD_PREP(MT_IFS_SLOT, phy->slottime));
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
mt76_wr(dev, MT_TMAC_ICR1(phy->band_idx),
|
2021-08-16 08:32:26 +08:00
|
|
|
FIELD_PREP(MT_IFS_EIFS_CCK, 314));
|
|
|
|
|
|
2022-03-07 15:10:26 +08:00
|
|
|
if (phy->slottime < 20 || a_band)
|
2020-04-25 03:32:27 +08:00
|
|
|
val = MT7915_CFEND_RATE_DEFAULT;
|
|
|
|
|
else
|
|
|
|
|
val = MT7915_CFEND_RATE_11B;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
mt76_rmw_field(dev, MT_AGG_ACR0(phy->band_idx), MT_AGG_ACR_CFEND_RATE, val);
|
|
|
|
|
mt76_clear(dev, MT_ARB_SCR(phy->band_idx),
|
2020-04-25 03:32:27 +08:00
|
|
|
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 23:23:13 +08:00
|
|
|
void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy)
|
|
|
|
|
{
|
2022-02-08 18:21:07 +08:00
|
|
|
u32 reg;
|
|
|
|
|
|
|
|
|
|
reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RXTD12(ext_phy) :
|
|
|
|
|
MT_WF_PHY_RXTD12_MT7916(ext_phy);
|
|
|
|
|
mt76_set(dev, reg,
|
2021-04-09 00:36:31 +08:00
|
|
|
MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY |
|
|
|
|
|
MT_WF_PHY_RXTD12_IRPI_SW_CLR);
|
2020-09-24 23:23:13 +08:00
|
|
|
|
2022-02-08 18:21:07 +08:00
|
|
|
reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RX_CTRL1(ext_phy) :
|
|
|
|
|
MT_WF_PHY_RX_CTRL1_MT7916(ext_phy);
|
|
|
|
|
mt76_set(dev, reg, FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5));
|
2020-09-24 23:23:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u8
|
|
|
|
|
mt7915_phy_get_nf(struct mt7915_phy *phy, int idx)
|
|
|
|
|
{
|
|
|
|
|
static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
u32 val, sum = 0, n = 0;
|
|
|
|
|
int nss, i;
|
|
|
|
|
|
2021-01-05 02:00:06 +08:00
|
|
|
for (nss = 0; nss < hweight8(phy->mt76->chainmask); nss++) {
|
2022-02-08 18:21:07 +08:00
|
|
|
u32 reg = is_mt7915(&dev->mt76) ?
|
|
|
|
|
MT_WF_IRPI_NSS(0, nss + (idx << dev->dbdc_support)) :
|
|
|
|
|
MT_WF_IRPI_NSS_MT7916(idx, nss);
|
2020-09-24 23:23:13 +08:00
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
|
2021-04-09 00:36:31 +08:00
|
|
|
val = mt76_rr(dev, reg);
|
2020-09-24 23:23:13 +08:00
|
|
|
sum += val * nf_power[i];
|
|
|
|
|
n += val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return sum / n;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
void mt7915_update_channel(struct mt76_phy *mphy)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
2020-09-24 23:23:13 +08:00
|
|
|
struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv;
|
2021-05-15 12:17:29 +08:00
|
|
|
struct mt76_channel_state *state = mphy->chan_state;
|
2020-09-24 23:23:13 +08:00
|
|
|
int nf;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-05-15 12:17:29 +08:00
|
|
|
mt7915_mcu_get_chan_mib_info(phy, false);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
nf = mt7915_phy_get_nf(phy, phy->band_idx);
|
2020-09-24 23:23:13 +08:00
|
|
|
if (!phy->noise)
|
|
|
|
|
phy->noise = nf << 4;
|
|
|
|
|
else if (nf)
|
|
|
|
|
phy->noise += nf - (phy->noise >> 4);
|
|
|
|
|
|
|
|
|
|
state->noise = -(phy->noise >> 4);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state)
|
|
|
|
|
{
|
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
|
|
ret = wait_event_timeout(dev->reset_wait,
|
|
|
|
|
(READ_ONCE(dev->reset_state) & state),
|
|
|
|
|
MT7915_RESET_TIMEOUT);
|
|
|
|
|
|
|
|
|
|
WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|
|
|
|
{
|
|
|
|
|
struct ieee80211_hw *hw = priv;
|
|
|
|
|
|
2020-12-05 07:37:14 +08:00
|
|
|
switch (vif->type) {
|
|
|
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
|
|
|
case NL80211_IFTYPE_ADHOC:
|
|
|
|
|
case NL80211_IFTYPE_AP:
|
2022-04-26 10:23:35 +08:00
|
|
|
mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon,
|
|
|
|
|
BSS_CHANGED_BEACON_ENABLED);
|
2020-12-05 07:37:14 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mt7915_update_beacons(struct mt7915_dev *dev)
|
|
|
|
|
{
|
|
|
|
|
ieee80211_iterate_active_interfaces(dev->mt76.hw,
|
|
|
|
|
IEEE80211_IFACE_ITER_RESUME_ALL,
|
|
|
|
|
mt7915_update_vif_beacon, dev->mt76.hw);
|
|
|
|
|
|
|
|
|
|
if (!dev->mt76.phy2)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw,
|
|
|
|
|
IEEE80211_IFACE_ITER_RESUME_ALL,
|
|
|
|
|
mt7915_update_vif_beacon, dev->mt76.phy2->hw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-26 02:28:56 +08:00
|
|
|
mt7915_dma_reset(struct mt7915_dev *dev)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
2020-11-13 11:11:31 +01:00
|
|
|
struct mt76_phy *mphy_ext = dev->mt76.phy2;
|
2021-12-20 10:17:54 +08:00
|
|
|
u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
|
2020-04-25 03:32:27 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
|
2022-02-09 14:11:56 +08:00
|
|
|
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
|
|
|
|
|
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
|
|
|
|
|
|
|
|
|
if (is_mt7915(&dev->mt76))
|
|
|
|
|
mt76_clear(dev, MT_WFDMA1_GLO_CFG,
|
|
|
|
|
MT_WFDMA1_GLO_CFG_TX_DMA_EN |
|
|
|
|
|
MT_WFDMA1_GLO_CFG_RX_DMA_EN);
|
2021-01-19 17:41:04 +01:00
|
|
|
if (dev->hif2) {
|
|
|
|
|
mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
|
2022-02-09 14:11:56 +08:00
|
|
|
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
|
|
|
|
|
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
|
|
|
|
|
|
|
|
|
if (is_mt7915(&dev->mt76))
|
|
|
|
|
mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
|
|
|
|
|
MT_WFDMA1_GLO_CFG_TX_DMA_EN |
|
|
|
|
|
MT_WFDMA1_GLO_CFG_RX_DMA_EN);
|
2021-01-19 17:41:04 +01:00
|
|
|
}
|
2021-03-26 02:28:56 +08:00
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
usleep_range(1000, 2000);
|
|
|
|
|
|
2020-11-13 11:11:31 +01:00
|
|
|
for (i = 0; i < __MT_TXQ_MAX; i++) {
|
2021-03-26 02:28:56 +08:00
|
|
|
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
|
2020-11-13 11:11:31 +01:00
|
|
|
if (mphy_ext)
|
|
|
|
|
mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-03-26 02:28:56 +08:00
|
|
|
for (i = 0; i < __MT_MCUQ_MAX; i++)
|
|
|
|
|
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
|
|
|
|
|
|
|
|
|
|
mt76_for_each_q_rx(&dev->mt76, i)
|
2020-04-25 03:32:27 +08:00
|
|
|
mt76_queue_rx_reset(dev, i);
|
|
|
|
|
|
2021-09-13 11:25:03 +02:00
|
|
|
mt76_tx_status_check(&dev->mt76, true);
|
2021-04-13 20:09:33 +02:00
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
/* re-init prefetch settings after reset */
|
|
|
|
|
mt7915_dma_prefetch(dev);
|
|
|
|
|
|
|
|
|
|
mt76_set(dev, MT_WFDMA0_GLO_CFG,
|
|
|
|
|
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
2022-02-09 14:11:56 +08:00
|
|
|
if (is_mt7915(&dev->mt76))
|
|
|
|
|
mt76_set(dev, MT_WFDMA1_GLO_CFG,
|
|
|
|
|
MT_WFDMA1_GLO_CFG_TX_DMA_EN |
|
2021-06-01 22:26:31 +02:00
|
|
|
MT_WFDMA1_GLO_CFG_RX_DMA_EN |
|
|
|
|
|
MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
|
2022-02-09 14:11:56 +08:00
|
|
|
MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
|
|
|
|
|
if (dev->hif2) {
|
|
|
|
|
mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
|
|
|
|
|
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
|
|
|
|
|
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
|
|
|
|
|
|
|
|
|
if (is_mt7915(&dev->mt76))
|
|
|
|
|
mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
|
|
|
|
|
MT_WFDMA1_GLO_CFG_TX_DMA_EN |
|
|
|
|
|
MT_WFDMA1_GLO_CFG_RX_DMA_EN |
|
|
|
|
|
MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
|
|
|
|
|
MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
|
2021-01-19 17:41:04 +01:00
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2020-12-11 02:51:37 +08:00
|
|
|
void mt7915_tx_token_put(struct mt7915_dev *dev)
|
|
|
|
|
{
|
|
|
|
|
struct mt76_txwi_cache *txwi;
|
|
|
|
|
int id;
|
|
|
|
|
|
2021-04-20 23:05:31 +02:00
|
|
|
spin_lock_bh(&dev->mt76.token_lock);
|
|
|
|
|
idr_for_each_entry(&dev->mt76.token, txwi, id) {
|
2021-05-07 18:51:41 +02:00
|
|
|
mt7915_txwi_free(dev, txwi, NULL, NULL);
|
2021-04-20 23:05:31 +02:00
|
|
|
dev->mt76.token_count--;
|
2020-12-11 02:51:37 +08:00
|
|
|
}
|
2021-04-20 23:05:31 +02:00
|
|
|
spin_unlock_bh(&dev->mt76.token_lock);
|
|
|
|
|
idr_destroy(&dev->mt76.token);
|
2020-12-11 02:51:37 +08:00
|
|
|
}
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
/* system error recovery */
|
|
|
|
|
void mt7915_mac_reset_work(struct work_struct *work)
|
|
|
|
|
{
|
2020-05-12 00:06:38 +08:00
|
|
|
struct mt7915_phy *phy2;
|
|
|
|
|
struct mt76_phy *ext_phy;
|
2020-04-25 03:32:27 +08:00
|
|
|
struct mt7915_dev *dev;
|
|
|
|
|
|
|
|
|
|
dev = container_of(work, struct mt7915_dev, reset_work);
|
2020-05-12 00:06:38 +08:00
|
|
|
ext_phy = dev->mt76.phy2;
|
|
|
|
|
phy2 = ext_phy ? ext_phy->priv : NULL;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ieee80211_stop_queues(mt76_hw(dev));
|
2020-05-12 00:06:38 +08:00
|
|
|
if (ext_phy)
|
|
|
|
|
ieee80211_stop_queues(ext_phy->hw);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
set_bit(MT76_RESET, &dev->mphy.state);
|
|
|
|
|
set_bit(MT76_MCU_RESET, &dev->mphy.state);
|
|
|
|
|
wake_up(&dev->mt76.mcu.wait);
|
2021-01-05 02:00:05 +08:00
|
|
|
cancel_delayed_work_sync(&dev->mphy.mac_work);
|
2021-02-27 15:39:45 +08:00
|
|
|
if (phy2) {
|
|
|
|
|
set_bit(MT76_RESET, &phy2->mt76->state);
|
2021-01-05 02:00:05 +08:00
|
|
|
cancel_delayed_work_sync(&phy2->mt76->mac_work);
|
2021-02-27 15:39:45 +08:00
|
|
|
}
|
2020-07-24 16:11:52 +02:00
|
|
|
mt76_worker_disable(&dev->mt76.tx_worker);
|
2020-04-25 03:32:27 +08:00
|
|
|
napi_disable(&dev->mt76.napi[0]);
|
|
|
|
|
napi_disable(&dev->mt76.napi[1]);
|
|
|
|
|
napi_disable(&dev->mt76.napi[2]);
|
|
|
|
|
napi_disable(&dev->mt76.tx_napi);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev->mt76.mutex);
|
|
|
|
|
|
|
|
|
|
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
|
|
|
|
|
|
|
|
|
|
if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
|
2021-03-26 02:28:56 +08:00
|
|
|
mt7915_dma_reset(dev);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-04-13 15:26:20 +08:00
|
|
|
mt7915_tx_token_put(dev);
|
2021-04-20 23:05:31 +02:00
|
|
|
idr_init(&dev->mt76.token);
|
2021-04-13 15:26:20 +08:00
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
|
|
|
|
|
mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
|
|
|
|
|
clear_bit(MT76_RESET, &dev->mphy.state);
|
2021-02-27 15:39:45 +08:00
|
|
|
if (phy2)
|
|
|
|
|
clear_bit(MT76_RESET, &phy2->mt76->state);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-09-24 17:54:40 +02:00
|
|
|
local_bh_disable();
|
2020-04-25 03:32:27 +08:00
|
|
|
napi_enable(&dev->mt76.napi[0]);
|
|
|
|
|
napi_schedule(&dev->mt76.napi[0]);
|
|
|
|
|
|
|
|
|
|
napi_enable(&dev->mt76.napi[1]);
|
|
|
|
|
napi_schedule(&dev->mt76.napi[1]);
|
|
|
|
|
|
|
|
|
|
napi_enable(&dev->mt76.napi[2]);
|
|
|
|
|
napi_schedule(&dev->mt76.napi[2]);
|
2021-09-24 17:54:40 +02:00
|
|
|
local_bh_enable();
|
|
|
|
|
|
2021-06-01 22:26:31 +02:00
|
|
|
tasklet_schedule(&dev->irq_tasklet);
|
|
|
|
|
|
|
|
|
|
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
|
|
|
|
|
mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
|
|
|
|
|
|
|
|
|
|
mt76_worker_enable(&dev->mt76.tx_worker);
|
|
|
|
|
|
|
|
|
|
napi_enable(&dev->mt76.tx_napi);
|
|
|
|
|
napi_schedule(&dev->mt76.tx_napi);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
ieee80211_wake_queues(mt76_hw(dev));
|
2020-05-12 00:06:38 +08:00
|
|
|
if (ext_phy)
|
|
|
|
|
ieee80211_wake_queues(ext_phy->hw);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
mutex_unlock(&dev->mt76.mutex);
|
|
|
|
|
|
|
|
|
|
mt7915_update_beacons(dev);
|
|
|
|
|
|
2021-01-05 02:00:05 +08:00
|
|
|
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
|
2020-04-25 03:32:27 +08:00
|
|
|
MT7915_WATCHDOG_TIME);
|
2020-05-12 00:06:38 +08:00
|
|
|
if (phy2)
|
2021-01-05 02:00:05 +08:00
|
|
|
ieee80211_queue_delayed_work(ext_phy->hw,
|
|
|
|
|
&phy2->mt76->mac_work,
|
2020-05-12 00:06:38 +08:00
|
|
|
MT7915_WATCHDOG_TIME);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2021-10-19 12:12:25 +02:00
|
|
|
void mt7915_mac_update_stats(struct mt7915_phy *phy)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
struct mib_stats *mib = &phy->mib;
|
2021-08-04 06:43:32 -07:00
|
|
|
int i, aggr0, aggr1, cnt;
|
2021-12-20 10:17:54 +08:00
|
|
|
u32 val;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR3(phy->band_idx));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->fcs_err_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) :
|
|
|
|
|
FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt);
|
2021-08-04 06:43:34 -07:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR4(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR5(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_mpdu_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR6(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR7(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_vector_mismatch_cnt += FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR8(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_delimiter_fail_cnt += FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR11(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_len_mismatch_cnt += FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR12(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->tx_ampdu_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR13(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->tx_stop_q_empty_cnt += FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR14(phy->band_idx));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->tx_mpdu_attempts_cnt += is_mt7915(&dev->mt76) ?
|
|
|
|
|
FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt) :
|
|
|
|
|
FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK_MT7916, cnt);
|
2021-08-04 06:43:34 -07:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR15(phy->band_idx));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->tx_mpdu_success_cnt += is_mt7915(&dev->mt76) ?
|
|
|
|
|
FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt) :
|
|
|
|
|
FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916, cnt);
|
2021-08-04 06:43:34 -07:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR22(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_ampdu_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR23(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_ampdu_bytes_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR24(phy->band_idx));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->rx_ampdu_valid_subframe_cnt += is_mt7915(&dev->mt76) ?
|
|
|
|
|
FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt) :
|
|
|
|
|
FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK_MT7916, cnt);
|
2021-08-04 06:43:34 -07:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR25(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR27(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR28(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR29(phy->band_idx));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->rx_pfdrop_cnt += is_mt7915(&dev->mt76) ?
|
|
|
|
|
FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt) :
|
|
|
|
|
FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK_MT7916, cnt);
|
2021-08-04 06:43:34 -07:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDRVEC(phy->band_idx));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->rx_vec_queue_overflow_drop_cnt += is_mt7915(&dev->mt76) ?
|
|
|
|
|
FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt) :
|
|
|
|
|
FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK_MT7916, cnt);
|
2021-08-04 06:43:34 -07:00
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR31(phy->band_idx));
|
2021-08-04 06:43:34 -07:00
|
|
|
mib->rx_ba_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDRMUBF(phy->band_idx));
|
2021-08-04 06:43:32 -07:00
|
|
|
mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_DR8(phy->band_idx));
|
2021-08-04 06:43:32 -07:00
|
|
|
mib->tx_mu_mpdu_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_DR9(phy->band_idx));
|
2021-08-04 06:43:32 -07:00
|
|
|
mib->tx_mu_acked_mpdu_cnt += cnt;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
cnt = mt76_rr(dev, MT_MIB_DR11(phy->band_idx));
|
2021-08-04 06:43:32 -07:00
|
|
|
mib->tx_su_acked_mpdu_cnt += cnt;
|
|
|
|
|
|
2022-03-11 22:44:26 +08:00
|
|
|
cnt = mt76_rr(dev, MT_ETBF_PAR_RPT0(phy->band_idx));
|
|
|
|
|
mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_PAR_RPT0_FB_BW, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NC, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NR, cnt);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-10-19 12:12:26 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
|
|
|
|
|
cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
|
|
|
|
|
mib->tx_amsdu[i] += cnt;
|
|
|
|
|
mib->tx_amsdu_cnt += cnt;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
aggr0 = phy->band_idx ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
|
2021-12-20 10:17:54 +08:00
|
|
|
if (is_mt7915(&dev->mt76)) {
|
|
|
|
|
for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) {
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_MIB_MB_SDR1(phy->band_idx, (i << 4)));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val);
|
|
|
|
|
mib->ack_fail_cnt +=
|
|
|
|
|
FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_MIB_MB_SDR0(phy->band_idx, (i << 4)));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val);
|
|
|
|
|
mib->rts_retries_cnt +=
|
|
|
|
|
FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val);
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_TX_AGG_CNT(phy->band_idx, i));
|
2021-12-20 10:17:54 +08:00
|
|
|
dev->mt76.aggr_stats[aggr0++] += val & 0xffff;
|
|
|
|
|
dev->mt76.aggr_stats[aggr0++] += val >> 16;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_TX_AGG_CNT2(phy->band_idx, i));
|
2021-12-20 10:17:54 +08:00
|
|
|
dev->mt76.aggr_stats[aggr1++] += val & 0xffff;
|
|
|
|
|
dev->mt76.aggr_stats[aggr1++] += val >> 16;
|
|
|
|
|
}
|
2022-03-11 22:44:26 +08:00
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR32(phy->band_idx));
|
|
|
|
|
mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR33(phy->band_idx));
|
|
|
|
|
mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(phy->band_idx));
|
|
|
|
|
mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt);
|
|
|
|
|
mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(phy->band_idx));
|
|
|
|
|
mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_ETBF_TX_FB_CPL, cnt);
|
|
|
|
|
mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_ETBF_TX_FB_TRI, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(phy->band_idx));
|
|
|
|
|
mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, cnt);
|
2021-12-20 10:17:54 +08:00
|
|
|
} else {
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
|
/* rts count */
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_MIB_MB_SDR0(phy->band_idx, (i << 2)));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->rts_cnt += FIELD_GET(GENMASK(15, 0), val);
|
|
|
|
|
mib->rts_cnt += FIELD_GET(GENMASK(31, 16), val);
|
|
|
|
|
|
|
|
|
|
/* rts retry count */
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_MIB_MB_SDR1(phy->band_idx, (i << 2)));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->rts_retries_cnt += FIELD_GET(GENMASK(15, 0), val);
|
|
|
|
|
mib->rts_retries_cnt += FIELD_GET(GENMASK(31, 16), val);
|
|
|
|
|
|
|
|
|
|
/* ba miss count */
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_MIB_MB_SDR2(phy->band_idx, (i << 2)));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->ba_miss_cnt += FIELD_GET(GENMASK(15, 0), val);
|
|
|
|
|
mib->ba_miss_cnt += FIELD_GET(GENMASK(31, 16), val);
|
|
|
|
|
|
|
|
|
|
/* ack fail count */
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_MIB_MB_BFTF(phy->band_idx, (i << 2)));
|
2021-12-20 10:17:54 +08:00
|
|
|
mib->ack_fail_cnt += FIELD_GET(GENMASK(15, 0), val);
|
|
|
|
|
mib->ack_fail_cnt += FIELD_GET(GENMASK(31, 16), val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
2022-02-09 14:11:57 +08:00
|
|
|
val = mt76_rr(dev, MT_TX_AGG_CNT(phy->band_idx, i));
|
2021-12-20 10:17:54 +08:00
|
|
|
dev->mt76.aggr_stats[aggr0++] += FIELD_GET(GENMASK(15, 0), val);
|
|
|
|
|
dev->mt76.aggr_stats[aggr0++] += FIELD_GET(GENMASK(31, 16), val);
|
|
|
|
|
}
|
2022-03-11 22:44:26 +08:00
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_SDR32(phy->band_idx));
|
|
|
|
|
mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt);
|
|
|
|
|
mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt);
|
|
|
|
|
mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt);
|
|
|
|
|
mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_BFCR7(phy->band_idx));
|
|
|
|
|
mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_MIB_BFCR7_BFEE_TX_FB_CPL, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_BFCR2(phy->band_idx));
|
|
|
|
|
mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_MIB_BFCR2_BFEE_TX_FB_TRIG, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_BFCR0(phy->band_idx));
|
|
|
|
|
mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt);
|
|
|
|
|
|
|
|
|
|
cnt = mt76_rr(dev, MT_MIB_BFCR1(phy->band_idx));
|
|
|
|
|
mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt);
|
|
|
|
|
mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-05 15:08:35 +08:00
|
|
|
static void mt7915_mac_severe_check(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
bool ext_phy = phy != &dev->phy;
|
|
|
|
|
u32 trb;
|
|
|
|
|
|
|
|
|
|
if (!phy->omac_mask)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* In rare cases, TRB pointers might be out of sync leads to RMAC
|
|
|
|
|
* stopping Rx, so check status periodically to see if TRB hardware
|
|
|
|
|
* requires minimal recovery.
|
|
|
|
|
*/
|
|
|
|
|
trb = mt76_rr(dev, MT_TRB_RXPSR0(phy->band_idx));
|
|
|
|
|
|
|
|
|
|
if ((FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, trb) !=
|
|
|
|
|
FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, trb)) &&
|
|
|
|
|
(FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, phy->trb_ts) !=
|
|
|
|
|
FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, phy->trb_ts)) &&
|
|
|
|
|
trb == phy->trb_ts)
|
|
|
|
|
mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L3_RX_ABORT,
|
|
|
|
|
ext_phy);
|
|
|
|
|
|
|
|
|
|
phy->trb_ts = trb;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-26 20:45:58 +02:00
|
|
|
void mt7915_mac_sta_rc_work(struct work_struct *work)
|
2020-04-25 03:32:27 +08:00
|
|
|
{
|
2020-07-26 20:45:58 +02:00
|
|
|
struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
|
2020-04-25 03:32:27 +08:00
|
|
|
struct ieee80211_sta *sta;
|
|
|
|
|
struct ieee80211_vif *vif;
|
|
|
|
|
struct mt7915_sta *msta;
|
2020-07-26 20:45:58 +02:00
|
|
|
u32 changed;
|
|
|
|
|
LIST_HEAD(list);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-07-26 20:45:58 +02:00
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
|
list_splice_init(&dev->sta_rc_list, &list);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-07-26 20:45:58 +02:00
|
|
|
while (!list_empty(&list)) {
|
|
|
|
|
msta = list_first_entry(&list, struct mt7915_sta, rc_list);
|
|
|
|
|
list_del_init(&msta->rc_list);
|
2021-07-14 17:18:51 +08:00
|
|
|
changed = msta->changed;
|
|
|
|
|
msta->changed = 0;
|
2020-07-26 20:45:58 +02:00
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-07-26 20:45:58 +02:00
|
|
|
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
|
|
|
|
|
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-07-26 20:45:58 +02:00
|
|
|
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
|
2020-04-25 03:32:27 +08:00
|
|
|
IEEE80211_RC_NSS_CHANGED |
|
2021-10-21 04:57:54 +08:00
|
|
|
IEEE80211_RC_BW_CHANGED))
|
|
|
|
|
mt7915_mcu_add_rate_ctrl(dev, vif, sta, true);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2020-07-26 20:45:58 +02:00
|
|
|
if (changed & IEEE80211_RC_SMPS_CHANGED)
|
|
|
|
|
mt7915_mcu_add_smps(dev, vif, sta);
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mt7915_mac_work(struct work_struct *work)
|
|
|
|
|
{
|
2020-05-12 00:06:38 +08:00
|
|
|
struct mt7915_phy *phy;
|
2021-01-05 02:00:05 +08:00
|
|
|
struct mt76_phy *mphy;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-01-05 02:00:05 +08:00
|
|
|
mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
|
|
|
|
|
mac_work.work);
|
|
|
|
|
phy = mphy->priv;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-01-05 02:00:05 +08:00
|
|
|
mutex_lock(&mphy->dev->mutex);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
mt76_update_survey(mphy);
|
2021-01-05 02:00:05 +08:00
|
|
|
if (++mphy->mac_work_count == 5) {
|
|
|
|
|
mphy->mac_work_count = 0;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-05-15 12:17:29 +08:00
|
|
|
mt7915_mac_update_stats(phy);
|
2022-05-05 15:08:35 +08:00
|
|
|
mt7915_mac_severe_check(phy);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2021-01-05 02:00:05 +08:00
|
|
|
mutex_unlock(&mphy->dev->mutex);
|
2020-05-12 00:06:38 +08:00
|
|
|
|
2021-09-13 11:25:03 +02:00
|
|
|
mt76_tx_status_check(mphy->dev, false);
|
2021-05-07 15:18:09 +02:00
|
|
|
|
2021-01-05 02:00:05 +08:00
|
|
|
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
|
2020-04-25 03:32:27 +08:00
|
|
|
MT7915_WATCHDOG_TIME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
|
|
|
|
|
if (phy->rdd_state & BIT(0))
|
2021-12-24 11:58:11 +01:00
|
|
|
mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0,
|
|
|
|
|
MT_RX_SEL0, 0);
|
2020-04-25 03:32:27 +08:00
|
|
|
if (phy->rdd_state & BIT(1))
|
2021-12-24 11:58:11 +01:00
|
|
|
mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1,
|
|
|
|
|
MT_RX_SEL0, 0);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain)
|
|
|
|
|
{
|
2022-03-01 13:29:10 +08:00
|
|
|
int err, region;
|
|
|
|
|
|
|
|
|
|
switch (dev->mt76.region) {
|
|
|
|
|
case NL80211_DFS_ETSI:
|
|
|
|
|
region = 0;
|
|
|
|
|
break;
|
|
|
|
|
case NL80211_DFS_JP:
|
|
|
|
|
region = 2;
|
|
|
|
|
break;
|
|
|
|
|
case NL80211_DFS_FCC:
|
|
|
|
|
default:
|
|
|
|
|
region = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2021-12-24 11:58:11 +01:00
|
|
|
err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain,
|
2022-03-01 13:29:10 +08:00
|
|
|
MT_RX_SEL0, region);
|
2020-04-25 03:32:27 +08:00
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
2021-12-24 11:58:11 +01:00
|
|
|
return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain,
|
|
|
|
|
MT_RX_SEL0, 1);
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
/* start CAC */
|
2022-02-09 14:11:57 +08:00
|
|
|
err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, phy->band_idx,
|
2021-12-24 11:58:11 +01:00
|
|
|
MT_RX_SEL0, 0);
|
2020-04-25 03:32:27 +08:00
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
err = mt7915_dfs_start_rdd(dev, phy->band_idx);
|
2020-04-25 03:32:27 +08:00
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
2022-02-09 14:11:57 +08:00
|
|
|
phy->rdd_state |= BIT(phy->band_idx);
|
|
|
|
|
|
|
|
|
|
if (!is_mt7915(&dev->mt76))
|
|
|
|
|
return 0;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
|
|
|
|
if (chandef->width == NL80211_CHAN_WIDTH_160 ||
|
|
|
|
|
chandef->width == NL80211_CHAN_WIDTH_80P80) {
|
|
|
|
|
err = mt7915_dfs_start_rdd(dev, 1);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
phy->rdd_state |= BIT(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mt7915_dfs_init_radar_specs(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
const struct mt7915_dfs_radar_spec *radar_specs;
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
|
|
|
|
int err, i;
|
|
|
|
|
|
|
|
|
|
switch (dev->mt76.region) {
|
|
|
|
|
case NL80211_DFS_FCC:
|
|
|
|
|
radar_specs = &fcc_radar_specs;
|
|
|
|
|
err = mt7915_mcu_set_fcc5_lpn(dev, 8);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
break;
|
|
|
|
|
case NL80211_DFS_ETSI:
|
|
|
|
|
radar_specs = &etsi_radar_specs;
|
|
|
|
|
break;
|
|
|
|
|
case NL80211_DFS_JP:
|
|
|
|
|
radar_specs = &jp_radar_specs;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
|
|
|
|
|
err = mt7915_mcu_set_radar_th(dev, i,
|
|
|
|
|
&radar_specs->radar_pattern[i]);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mt7915_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_dev *dev = phy->dev;
|
2022-02-02 23:11:58 +01:00
|
|
|
enum mt76_dfs_state dfs_state, prev_state;
|
2020-04-25 03:32:27 +08:00
|
|
|
int err;
|
|
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
prev_state = phy->mt76->dfs_state;
|
|
|
|
|
dfs_state = mt76_phy_dfs_state(phy->mt76);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
if (prev_state == dfs_state)
|
2020-04-25 03:32:27 +08:00
|
|
|
return 0;
|
|
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
if (prev_state == MT_DFS_STATE_UNKNOWN)
|
|
|
|
|
mt7915_dfs_stop_radar_detector(phy);
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
if (dfs_state == MT_DFS_STATE_DISABLED)
|
2020-04-25 03:32:27 +08:00
|
|
|
goto stop;
|
|
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
if (prev_state <= MT_DFS_STATE_DISABLED) {
|
|
|
|
|
err = mt7915_dfs_init_radar_specs(phy);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
err = mt7915_dfs_start_radar_detector(phy);
|
|
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
phy->mt76->dfs_state = MT_DFS_STATE_CAC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dfs_state == MT_DFS_STATE_CAC)
|
|
|
|
|
return 0;
|
2020-04-25 03:32:27 +08:00
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END,
|
2022-02-09 14:11:57 +08:00
|
|
|
phy->band_idx, MT_RX_SEL0, 0);
|
2022-02-02 23:11:58 +01:00
|
|
|
if (err < 0) {
|
|
|
|
|
phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
|
|
|
|
|
return err;
|
2020-04-25 03:32:27 +08:00
|
|
|
}
|
|
|
|
|
|
2022-02-02 23:11:58 +01:00
|
|
|
phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
stop:
|
2022-02-09 14:11:57 +08:00
|
|
|
err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START,
|
|
|
|
|
phy->band_idx, MT_RX_SEL0, 0);
|
2020-04-25 03:32:27 +08:00
|
|
|
if (err < 0)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
mt7915_dfs_stop_radar_detector(phy);
|
2022-02-02 23:11:58 +01:00
|
|
|
phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
|
|
|
|
|
|
2020-04-25 03:32:27 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2021-09-23 16:29:32 +02:00
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mt7915_mac_twt_duration_align(int duration)
|
|
|
|
|
{
|
|
|
|
|
return duration << 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u64
|
|
|
|
|
mt7915_mac_twt_sched_list_add(struct mt7915_dev *dev,
|
|
|
|
|
struct mt7915_twt_flow *flow)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_twt_flow *iter, *iter_next;
|
|
|
|
|
u32 duration = flow->duration << 8;
|
|
|
|
|
u64 start_tsf;
|
|
|
|
|
|
|
|
|
|
iter = list_first_entry_or_null(&dev->twt_list,
|
|
|
|
|
struct mt7915_twt_flow, list);
|
|
|
|
|
if (!iter || !iter->sched || iter->start_tsf > duration) {
|
|
|
|
|
/* add flow as first entry in the list */
|
|
|
|
|
list_add(&flow->list, &dev->twt_list);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
|
|
|
|
|
start_tsf = iter->start_tsf +
|
|
|
|
|
mt7915_mac_twt_duration_align(iter->duration);
|
|
|
|
|
if (list_is_last(&iter->list, &dev->twt_list))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!iter_next->sched ||
|
|
|
|
|
iter_next->start_tsf > start_tsf + duration) {
|
|
|
|
|
list_add(&flow->list, &iter->list);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add flow as last entry in the list */
|
|
|
|
|
list_add_tail(&flow->list, &dev->twt_list);
|
|
|
|
|
out:
|
|
|
|
|
return start_tsf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int mt7915_mac_check_twt_req(struct ieee80211_twt_setup *twt)
|
|
|
|
|
{
|
|
|
|
|
struct ieee80211_twt_params *twt_agrt;
|
|
|
|
|
u64 interval, duration;
|
|
|
|
|
u16 mantissa;
|
|
|
|
|
u8 exp;
|
|
|
|
|
|
|
|
|
|
/* only individual agreement supported */
|
|
|
|
|
if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
/* only 256us unit supported */
|
|
|
|
|
if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
twt_agrt = (struct ieee80211_twt_params *)twt->params;
|
|
|
|
|
|
|
|
|
|
/* explicit agreement not supported */
|
|
|
|
|
if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
|
|
|
|
|
le16_to_cpu(twt_agrt->req_type));
|
|
|
|
|
mantissa = le16_to_cpu(twt_agrt->mantissa);
|
|
|
|
|
duration = twt_agrt->min_twt_dur << 8;
|
|
|
|
|
|
|
|
|
|
interval = (u64)mantissa << exp;
|
|
|
|
|
if (interval < duration)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-05 16:25:53 +08:00
|
|
|
static bool
|
|
|
|
|
mt7915_mac_twt_param_equal(struct mt7915_sta *msta,
|
|
|
|
|
struct ieee80211_twt_params *twt_agrt)
|
|
|
|
|
{
|
|
|
|
|
u16 type = le16_to_cpu(twt_agrt->req_type);
|
|
|
|
|
u8 exp;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type);
|
|
|
|
|
for (i = 0; i < MT7915_MAX_STA_TWT_AGRT; i++) {
|
|
|
|
|
struct mt7915_twt_flow *f;
|
|
|
|
|
|
|
|
|
|
if (!(msta->twt.flowid_mask & BIT(i)))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
f = &msta->twt.flow[i];
|
|
|
|
|
if (f->duration == twt_agrt->min_twt_dur &&
|
|
|
|
|
f->mantissa == twt_agrt->mantissa &&
|
|
|
|
|
f->exp == exp &&
|
|
|
|
|
f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) &&
|
|
|
|
|
f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) &&
|
|
|
|
|
f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 16:29:32 +02:00
|
|
|
void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw,
|
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
|
struct ieee80211_twt_setup *twt)
|
|
|
|
|
{
|
|
|
|
|
enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
|
|
|
|
|
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
|
|
|
|
struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
|
|
|
|
|
u16 req_type = le16_to_cpu(twt_agrt->req_type);
|
|
|
|
|
enum ieee80211_twt_setup_cmd sta_setup_cmd;
|
|
|
|
|
struct mt7915_dev *dev = mt7915_hw_dev(hw);
|
|
|
|
|
struct mt7915_twt_flow *flow;
|
|
|
|
|
int flowid, table_id;
|
|
|
|
|
u8 exp;
|
|
|
|
|
|
|
|
|
|
if (mt7915_mac_check_twt_req(twt))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev->mt76.mutex);
|
|
|
|
|
|
|
|
|
|
if (dev->twt.n_agrt == MT7915_MAX_TWT_AGRT)
|
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
|
|
if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
|
|
|
|
|
goto unlock;
|
|
|
|
|
|
2022-05-05 16:25:54 +08:00
|
|
|
if (twt_agrt->min_twt_dur < MT7915_MIN_TWT_DUR) {
|
|
|
|
|
setup_cmd = TWT_SETUP_CMD_DICTATE;
|
|
|
|
|
twt_agrt->min_twt_dur = MT7915_MIN_TWT_DUR;
|
|
|
|
|
goto unlock;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 16:29:32 +02:00
|
|
|
flowid = ffs(~msta->twt.flowid_mask) - 1;
|
|
|
|
|
le16p_replace_bits(&twt_agrt->req_type, flowid,
|
|
|
|
|
IEEE80211_TWT_REQTYPE_FLOWID);
|
|
|
|
|
|
|
|
|
|
table_id = ffs(~dev->twt.table_mask) - 1;
|
|
|
|
|
exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
|
|
|
|
|
sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
|
|
|
|
|
|
2022-05-05 16:25:53 +08:00
|
|
|
if (mt7915_mac_twt_param_equal(msta, twt_agrt))
|
|
|
|
|
goto unlock;
|
|
|
|
|
|
2021-09-23 16:29:32 +02:00
|
|
|
flow = &msta->twt.flow[flowid];
|
|
|
|
|
memset(flow, 0, sizeof(*flow));
|
|
|
|
|
INIT_LIST_HEAD(&flow->list);
|
|
|
|
|
flow->wcid = msta->wcid.idx;
|
|
|
|
|
flow->table_id = table_id;
|
|
|
|
|
flow->id = flowid;
|
|
|
|
|
flow->duration = twt_agrt->min_twt_dur;
|
|
|
|
|
flow->mantissa = twt_agrt->mantissa;
|
|
|
|
|
flow->exp = exp;
|
|
|
|
|
flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
|
|
|
|
|
flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
|
|
|
|
|
flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
|
|
|
|
|
|
|
|
|
|
if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
|
|
|
|
|
sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
|
|
|
|
|
u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
|
|
|
|
|
u64 flow_tsf, curr_tsf;
|
|
|
|
|
u32 rem;
|
|
|
|
|
|
|
|
|
|
flow->sched = true;
|
|
|
|
|
flow->start_tsf = mt7915_mac_twt_sched_list_add(dev, flow);
|
|
|
|
|
curr_tsf = __mt7915_get_tsf(hw, msta->vif);
|
|
|
|
|
div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
|
|
|
|
|
flow_tsf = curr_tsf + interval - rem;
|
|
|
|
|
twt_agrt->twt = cpu_to_le64(flow_tsf);
|
|
|
|
|
} else {
|
|
|
|
|
list_add_tail(&flow->list, &dev->twt_list);
|
|
|
|
|
}
|
|
|
|
|
flow->tsf = le64_to_cpu(twt_agrt->twt);
|
|
|
|
|
|
|
|
|
|
if (mt7915_mcu_twt_agrt_update(dev, msta->vif, 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);
|
|
|
|
|
dev->twt.n_agrt++;
|
|
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
|
mutex_unlock(&dev->mt76.mutex);
|
|
|
|
|
out:
|
|
|
|
|
le16p_replace_bits(&twt_agrt->req_type, setup_cmd,
|
|
|
|
|
IEEE80211_TWT_REQTYPE_SETUP_CMD);
|
|
|
|
|
twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) |
|
|
|
|
|
(twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev,
|
|
|
|
|
struct mt7915_sta *msta,
|
|
|
|
|
u8 flowid)
|
|
|
|
|
{
|
|
|
|
|
struct mt7915_twt_flow *flow;
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held(&dev->mt76.mutex);
|
|
|
|
|
|
|
|
|
|
if (flowid >= ARRAY_SIZE(msta->twt.flow))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!(msta->twt.flowid_mask & BIT(flowid)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
flow = &msta->twt.flow[flowid];
|
|
|
|
|
if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow,
|
|
|
|
|
MCU_TWT_AGRT_DELETE))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_del_init(&flow->list);
|
|
|
|
|
msta->twt.flowid_mask &= ~BIT(flowid);
|
|
|
|
|
dev->twt.table_mask &= ~BIT(flow->table_id);
|
|
|
|
|
dev->twt.n_agrt--;
|
|
|
|
|
}
|