2019-07-24 01:58:20 -07:00
|
|
|
// SPDX-License-Identifier: ISC
|
2018-08-29 04:16:36 -07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
|
|
|
|
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
|
|
|
|
*/
|
|
|
|
|
2018-10-05 01:00:33 -07:00
|
|
|
#include "mt76x02.h"
|
2018-10-05 01:28:34 -07:00
|
|
|
#include "mt76x02_trace.h"
|
2019-12-29 03:03:06 -07:00
|
|
|
#include "trace.h"
|
2018-08-29 04:16:36 -07:00
|
|
|
|
2019-09-12 02:06:35 -07:00
|
|
|
void mt76x02_mac_reset_counters(struct mt76x02_dev *dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
mt76_rr(dev, MT_RX_STAT_0);
|
|
|
|
mt76_rr(dev, MT_RX_STAT_1);
|
|
|
|
mt76_rr(dev, MT_RX_STAT_2);
|
|
|
|
mt76_rr(dev, MT_TX_STA_0);
|
|
|
|
mt76_rr(dev, MT_TX_STA_1);
|
|
|
|
mt76_rr(dev, MT_TX_STA_2);
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
mt76_rr(dev, MT_TX_AGG_CNT(i));
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
mt76_rr(dev, MT_TX_STAT_FIFO);
|
|
|
|
|
2022-11-02 15:29:15 -07:00
|
|
|
memset(dev->mphy.aggr_stats, 0, sizeof(dev->mphy.aggr_stats));
|
2019-09-12 02:06:35 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters);
|
|
|
|
|
2018-10-17 04:10:16 -07:00
|
|
|
static enum mt76x02_cipher_type
|
2018-08-29 04:16:36 -07:00
|
|
|
mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
|
|
|
|
{
|
|
|
|
memset(key_data, 0, 32);
|
|
|
|
if (!key)
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_NONE;
|
2018-08-29 04:16:36 -07:00
|
|
|
|
|
|
|
if (key->keylen > 32)
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_NONE;
|
2018-08-29 04:16:36 -07:00
|
|
|
|
|
|
|
memcpy(key_data, key->key, key->keylen);
|
|
|
|
|
|
|
|
switch (key->cipher) {
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_WEP40;
|
2018-08-29 04:16:36 -07:00
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_WEP104;
|
2018-08-29 04:16:36 -07:00
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_TKIP;
|
2018-08-29 04:16:36 -07:00
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_AES_CCMP;
|
2018-08-29 04:16:36 -07:00
|
|
|
default:
|
2021-06-17 00:17:49 -07:00
|
|
|
return MT76X02_CIPHER_NONE;
|
2018-08-29 04:16:36 -07:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 04:16:38 -07:00
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
|
|
|
|
u8 key_idx, struct ieee80211_key_conf *key)
|
2018-08-29 04:16:38 -07:00
|
|
|
{
|
|
|
|
enum mt76x02_cipher_type cipher;
|
|
|
|
u8 key_data[32];
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
cipher = mt76x02_mac_get_key_info(key, key_data);
|
2021-06-17 00:17:49 -07:00
|
|
|
if (cipher == MT76X02_CIPHER_NONE && key)
|
2018-08-29 04:16:38 -07:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
|
2018-08-29 04:16:38 -07:00
|
|
|
val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
|
|
|
|
val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
|
2018-08-29 04:16:38 -07:00
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data,
|
|
|
|
sizeof(key_data));
|
2018-08-29 04:16:38 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup);
|
2018-08-29 04:16:39 -07:00
|
|
|
|
2019-02-27 11:42:39 -07:00
|
|
|
void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx,
|
|
|
|
struct ieee80211_key_conf *key)
|
|
|
|
{
|
|
|
|
enum mt76x02_cipher_type cipher;
|
|
|
|
u8 key_data[32];
|
|
|
|
u32 iv, eiv;
|
|
|
|
u64 pn;
|
|
|
|
|
|
|
|
cipher = mt76x02_mac_get_key_info(key, key_data);
|
|
|
|
iv = mt76_rr(dev, MT_WCID_IV(idx));
|
|
|
|
eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4);
|
|
|
|
|
|
|
|
pn = (u64)eiv << 16;
|
2021-06-17 00:17:49 -07:00
|
|
|
if (cipher == MT76X02_CIPHER_TKIP) {
|
2019-02-27 11:42:39 -07:00
|
|
|
pn |= (iv >> 16) & 0xff;
|
|
|
|
pn |= (iv & 0xff) << 8;
|
2021-06-17 00:17:49 -07:00
|
|
|
} else if (cipher >= MT76X02_CIPHER_AES_CCMP) {
|
2019-02-27 11:42:39 -07:00
|
|
|
pn |= iv & 0xffff;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic64_set(&key->tx_pn, pn);
|
|
|
|
}
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
|
|
|
|
struct ieee80211_key_conf *key)
|
2018-08-29 04:16:39 -07:00
|
|
|
{
|
|
|
|
enum mt76x02_cipher_type cipher;
|
|
|
|
u8 key_data[32];
|
|
|
|
u8 iv_data[8];
|
2019-02-27 11:40:27 -07:00
|
|
|
u64 pn;
|
2018-08-29 04:16:39 -07:00
|
|
|
|
|
|
|
cipher = mt76x02_mac_get_key_info(key, key_data);
|
2021-06-17 00:17:49 -07:00
|
|
|
if (cipher == MT76X02_CIPHER_NONE && key)
|
2018-08-29 04:16:39 -07:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
|
|
|
|
mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher);
|
2018-08-29 04:16:39 -07:00
|
|
|
|
|
|
|
memset(iv_data, 0, sizeof(iv_data));
|
|
|
|
if (key) {
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE,
|
|
|
|
!!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
|
2019-02-27 11:40:27 -07:00
|
|
|
|
|
|
|
pn = atomic64_read(&key->tx_pn);
|
|
|
|
|
2018-08-29 04:16:39 -07:00
|
|
|
iv_data[3] = key->keyidx << 6;
|
2021-06-17 00:17:49 -07:00
|
|
|
if (cipher >= MT76X02_CIPHER_TKIP) {
|
2018-08-29 04:16:39 -07:00
|
|
|
iv_data[3] |= 0x20;
|
2019-02-27 11:40:27 -07:00
|
|
|
put_unaligned_le32(pn >> 16, &iv_data[4]);
|
|
|
|
}
|
|
|
|
|
2021-06-17 00:17:49 -07:00
|
|
|
if (cipher == MT76X02_CIPHER_TKIP) {
|
2019-02-27 11:40:27 -07:00
|
|
|
iv_data[0] = (pn >> 8) & 0xff;
|
|
|
|
iv_data[1] = (iv_data[0] | 0x20) & 0x7f;
|
|
|
|
iv_data[2] = pn & 0xff;
|
2021-06-17 00:17:49 -07:00
|
|
|
} else if (cipher >= MT76X02_CIPHER_AES_CCMP) {
|
2019-02-27 11:40:27 -07:00
|
|
|
put_unaligned_le16((pn & 0xffff), &iv_data[0]);
|
|
|
|
}
|
2018-08-29 04:16:39 -07:00
|
|
|
}
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
|
2018-08-29 04:16:39 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-08-29 04:16:40 -07:00
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx,
|
|
|
|
u8 vif_idx, u8 *mac)
|
2018-08-29 04:16:40 -07:00
|
|
|
{
|
|
|
|
struct mt76_wcid_addr addr = {};
|
|
|
|
u32 attr;
|
|
|
|
|
|
|
|
attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
|
|
|
|
FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr(dev, MT_WCID_ATTR(idx), attr);
|
2018-08-29 04:16:40 -07:00
|
|
|
|
|
|
|
if (idx >= 128)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mac)
|
|
|
|
memcpy(addr.macaddr, mac, ETH_ALEN);
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr));
|
2018-08-29 04:16:40 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup);
|
2018-08-29 04:16:41 -07:00
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)
|
2018-08-29 04:16:41 -07:00
|
|
|
{
|
2018-10-07 02:45:22 -07:00
|
|
|
u32 val = mt76_rr(dev, MT_WCID_DROP(idx));
|
2018-08-29 04:16:41 -07:00
|
|
|
u32 bit = MT_WCID_DROP_MASK(idx);
|
|
|
|
|
|
|
|
/* prevent unnecessary writes */
|
|
|
|
if ((val & bit) != (bit * drop))
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
|
2018-08-29 04:16:41 -07:00
|
|
|
}
|
2018-08-29 04:16:44 -07:00
|
|
|
|
2021-06-22 00:48:30 -07:00
|
|
|
static u16
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
|
|
|
|
const struct ieee80211_tx_rate *rate, u8 *nss_val)
|
2018-09-04 07:41:07 -07:00
|
|
|
{
|
2018-12-28 03:00:47 -07:00
|
|
|
u8 phy, rate_idx, nss, bw = 0;
|
2018-09-04 07:41:07 -07:00
|
|
|
u16 rateval;
|
|
|
|
|
|
|
|
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
|
|
|
|
rate_idx = rate->idx;
|
|
|
|
nss = 1 + (rate->idx >> 4);
|
|
|
|
phy = MT_PHY_TYPE_VHT;
|
|
|
|
if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
|
|
|
|
bw = 2;
|
|
|
|
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
|
|
|
bw = 1;
|
|
|
|
} else if (rate->flags & IEEE80211_TX_RC_MCS) {
|
|
|
|
rate_idx = rate->idx;
|
|
|
|
nss = 1 + (rate->idx >> 3);
|
|
|
|
phy = MT_PHY_TYPE_HT;
|
|
|
|
if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
|
|
|
|
phy = MT_PHY_TYPE_HT_GF;
|
|
|
|
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
|
|
|
bw = 1;
|
|
|
|
} else {
|
|
|
|
const struct ieee80211_rate *r;
|
2019-10-12 10:46:40 -07:00
|
|
|
int band = dev->mphy.chandef.chan->band;
|
2018-09-04 07:41:07 -07:00
|
|
|
u16 val;
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx];
|
2018-09-04 07:41:07 -07:00
|
|
|
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
|
|
|
val = r->hw_value_short;
|
|
|
|
else
|
|
|
|
val = r->hw_value;
|
|
|
|
|
|
|
|
phy = val >> 8;
|
|
|
|
rate_idx = val & 0xff;
|
2018-12-28 03:00:47 -07:00
|
|
|
nss = 1;
|
2018-09-04 07:41:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx);
|
|
|
|
rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
|
|
|
|
rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
|
|
|
|
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
|
|
|
|
rateval |= MT_RXWI_RATE_SGI;
|
|
|
|
|
|
|
|
*nss_val = nss;
|
2021-06-22 00:48:30 -07:00
|
|
|
return rateval;
|
2018-09-04 07:41:07 -07:00
|
|
|
}
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
|
|
|
|
const struct ieee80211_tx_rate *rate)
|
2018-09-04 07:41:07 -07:00
|
|
|
{
|
2019-03-13 06:20:06 -07:00
|
|
|
s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
|
2021-06-22 00:48:30 -07:00
|
|
|
u16 rateval;
|
2019-03-13 06:20:06 -07:00
|
|
|
u32 tx_info;
|
|
|
|
s8 nss;
|
|
|
|
|
|
|
|
rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss);
|
|
|
|
tx_info = FIELD_PREP(MT_WCID_TX_INFO_RATE, rateval) |
|
|
|
|
FIELD_PREP(MT_WCID_TX_INFO_NSS, nss) |
|
|
|
|
FIELD_PREP(MT_WCID_TX_INFO_TXPWR_ADJ, max_txpwr_adj) |
|
|
|
|
MT_WCID_TX_INFO_SET;
|
|
|
|
wcid->tx_info = tx_info;
|
2018-09-04 07:41:07 -07:00
|
|
|
}
|
2018-09-04 07:41:09 -07:00
|
|
|
|
2018-10-19 05:56:24 -07:00
|
|
|
void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable)
|
|
|
|
{
|
|
|
|
if (enable)
|
|
|
|
mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
|
|
|
|
else
|
|
|
|
mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
|
|
|
|
}
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev,
|
|
|
|
struct mt76x02_tx_status *stat)
|
2018-09-04 07:41:09 -07:00
|
|
|
{
|
|
|
|
u32 stat1, stat2;
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
|
|
|
|
stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
|
2018-09-04 07:41:09 -07:00
|
|
|
|
|
|
|
stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
|
|
|
|
if (!stat->valid)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
|
|
|
|
stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
|
|
|
|
stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
|
|
|
|
stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
|
|
|
|
stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
|
|
|
|
|
|
|
|
stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
|
|
|
|
stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
|
|
|
|
|
2018-10-17 15:35:32 -07:00
|
|
|
trace_mac_txstat_fetch(dev, stat);
|
|
|
|
|
2018-09-04 07:41:09 -07:00
|
|
|
return true;
|
|
|
|
}
|
2018-09-04 07:41:10 -07:00
|
|
|
|
|
|
|
static int
|
|
|
|
mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
|
2019-07-24 01:58:18 -07:00
|
|
|
enum nl80211_band band)
|
2018-09-04 07:41:10 -07:00
|
|
|
{
|
|
|
|
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
|
|
|
|
|
|
|
|
txrate->idx = 0;
|
|
|
|
txrate->flags = 0;
|
|
|
|
txrate->count = 1;
|
|
|
|
|
|
|
|
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
|
|
|
|
case MT_PHY_TYPE_OFDM:
|
|
|
|
if (band == NL80211_BAND_2GHZ)
|
|
|
|
idx += 4;
|
|
|
|
|
|
|
|
txrate->idx = idx;
|
|
|
|
return 0;
|
|
|
|
case MT_PHY_TYPE_CCK:
|
|
|
|
if (idx >= 8)
|
|
|
|
idx -= 8;
|
|
|
|
|
|
|
|
txrate->idx = idx;
|
|
|
|
return 0;
|
|
|
|
case MT_PHY_TYPE_HT_GF:
|
|
|
|
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
2020-09-01 10:33:41 -07:00
|
|
|
fallthrough;
|
2018-09-04 07:41:10 -07:00
|
|
|
case MT_PHY_TYPE_HT:
|
|
|
|
txrate->flags |= IEEE80211_TX_RC_MCS;
|
|
|
|
txrate->idx = idx;
|
|
|
|
break;
|
|
|
|
case MT_PHY_TYPE_VHT:
|
|
|
|
txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
|
|
|
|
txrate->idx = idx;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
|
|
|
|
case MT_PHY_BW_20:
|
|
|
|
break;
|
|
|
|
case MT_PHY_BW_40:
|
|
|
|
txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
|
|
|
break;
|
|
|
|
case MT_PHY_BW_80:
|
|
|
|
txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rate & MT_RXWI_RATE_SGI)
|
|
|
|
txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
|
2018-10-01 09:58:19 -07:00
|
|
|
struct sk_buff *skb, struct mt76_wcid *wcid,
|
|
|
|
struct ieee80211_sta *sta, int len)
|
|
|
|
{
|
2018-10-07 02:57:21 -07:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
2018-10-01 09:58:19 -07:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
struct ieee80211_tx_rate *rate = &info->control.rates[0];
|
|
|
|
struct ieee80211_key_conf *key = info->control.hw_key;
|
2019-03-13 06:20:06 -07:00
|
|
|
u32 wcid_tx_info;
|
2018-10-01 09:58:19 -07:00
|
|
|
u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
|
2021-06-22 00:48:30 -07:00
|
|
|
u16 txwi_flags = 0, rateval;
|
2018-10-01 09:58:19 -07:00
|
|
|
u8 nss;
|
|
|
|
s8 txpwr_adj, max_txpwr_adj;
|
2021-01-04 11:00:06 -07:00
|
|
|
u8 ccmp_pn[8], nstreams = dev->mphy.chainmask & 0xf;
|
2018-10-01 09:58:19 -07:00
|
|
|
|
|
|
|
memset(txwi, 0, sizeof(*txwi));
|
|
|
|
|
2020-07-28 11:41:09 -07:00
|
|
|
mt76_tx_check_agg_ssn(sta, skb);
|
|
|
|
|
2019-01-31 13:01:24 -07:00
|
|
|
if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff &&
|
|
|
|
ieee80211_has_protected(hdr->frame_control)) {
|
|
|
|
wcid = NULL;
|
|
|
|
ieee80211_get_tx_rates(info->control.vif, sta, skb,
|
2019-07-24 01:58:18 -07:00
|
|
|
info->control.rates, 1);
|
2019-01-31 13:01:24 -07:00
|
|
|
}
|
|
|
|
|
2018-10-01 09:58:19 -07:00
|
|
|
if (wcid)
|
|
|
|
txwi->wcid = wcid->idx;
|
|
|
|
else
|
|
|
|
txwi->wcid = 0xff;
|
|
|
|
|
|
|
|
if (wcid && wcid->sw_iv && key) {
|
|
|
|
u64 pn = atomic64_inc_return(&key->tx_pn);
|
2019-07-24 01:58:18 -07:00
|
|
|
|
2018-10-01 09:58:19 -07:00
|
|
|
ccmp_pn[0] = pn;
|
|
|
|
ccmp_pn[1] = pn >> 8;
|
|
|
|
ccmp_pn[2] = 0;
|
|
|
|
ccmp_pn[3] = 0x20 | (key->keyidx << 6);
|
|
|
|
ccmp_pn[4] = pn >> 16;
|
|
|
|
ccmp_pn[5] = pn >> 24;
|
|
|
|
ccmp_pn[6] = pn >> 32;
|
|
|
|
ccmp_pn[7] = pn >> 40;
|
|
|
|
txwi->iv = *((__le32 *)&ccmp_pn[0]);
|
2019-01-25 09:59:06 -07:00
|
|
|
txwi->eiv = *((__le32 *)&ccmp_pn[4]);
|
2018-10-01 09:58:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (wcid && (rate->idx < 0 || !rate->count)) {
|
2019-03-13 06:20:06 -07:00
|
|
|
wcid_tx_info = wcid->tx_info;
|
2021-06-22 00:48:30 -07:00
|
|
|
rateval = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
|
2019-03-13 06:20:06 -07:00
|
|
|
max_txpwr_adj = FIELD_GET(MT_WCID_TX_INFO_TXPWR_ADJ,
|
|
|
|
wcid_tx_info);
|
|
|
|
nss = FIELD_GET(MT_WCID_TX_INFO_NSS, wcid_tx_info);
|
2018-10-01 09:58:19 -07:00
|
|
|
} else {
|
2021-06-22 00:48:30 -07:00
|
|
|
rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss);
|
2018-10-07 02:45:23 -07:00
|
|
|
max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
|
2018-10-01 09:58:19 -07:00
|
|
|
}
|
2021-06-22 00:48:30 -07:00
|
|
|
txwi->rate = cpu_to_le16(rateval);
|
2018-10-01 09:58:19 -07:00
|
|
|
|
2019-10-16 03:36:16 -07:00
|
|
|
txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf,
|
2018-10-05 01:28:31 -07:00
|
|
|
max_txpwr_adj);
|
|
|
|
txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj);
|
2018-10-01 09:58:19 -07:00
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4)
|
2018-10-01 09:58:19 -07:00
|
|
|
txwi->txstream = 0x13;
|
2018-10-07 02:45:22 -07:00
|
|
|
else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 &&
|
2018-10-01 09:58:19 -07:00
|
|
|
!(txwi->rate & cpu_to_le16(rate_ht_mask)))
|
|
|
|
txwi->txstream = 0x93;
|
|
|
|
|
2018-10-07 02:57:21 -07:00
|
|
|
if (is_mt76x2(dev) && (info->flags & IEEE80211_TX_CTL_LDPC))
|
|
|
|
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC);
|
|
|
|
if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
|
|
|
|
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC);
|
2022-09-02 07:12:41 -07:00
|
|
|
if (nss > 1 && sta && sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC)
|
2018-10-07 02:57:21 -07:00
|
|
|
txwi_flags |= MT_TXWI_FLAGS_MMPS;
|
|
|
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
|
|
|
txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
|
|
|
|
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
|
|
|
|
txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
|
|
|
|
if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
|
|
|
|
u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
|
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 08:41:23 -07:00
|
|
|
u8 ampdu_density = sta->deflink.ht_cap.ampdu_density;
|
2018-10-07 02:57:21 -07: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 08:41:23 -07:00
|
|
|
ba_size <<= sta->deflink.ht_cap.ampdu_factor;
|
2018-10-07 02:57:21 -07:00
|
|
|
ba_size = min_t(int, 63, ba_size - 1);
|
|
|
|
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
|
|
|
|
ba_size = 0;
|
|
|
|
txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
|
|
|
|
|
2020-04-20 07:34:16 -07:00
|
|
|
if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4)
|
|
|
|
ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
|
|
|
|
|
2018-10-07 02:57:21 -07:00
|
|
|
txwi_flags |= MT_TXWI_FLAGS_AMPDU |
|
2020-04-20 07:34:16 -07:00
|
|
|
FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, ampdu_density);
|
2018-10-07 02:57:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ieee80211_is_probe_resp(hdr->frame_control) ||
|
|
|
|
ieee80211_is_beacon(hdr->frame_control))
|
|
|
|
txwi_flags |= MT_TXWI_FLAGS_TS;
|
|
|
|
|
|
|
|
txwi->flags |= cpu_to_le16(txwi_flags);
|
|
|
|
txwi->len_ctl = cpu_to_le16(len);
|
2018-10-01 09:58:19 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
|
|
|
|
|
2018-09-04 07:41:10 -07:00
|
|
|
static void
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
mt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy)
|
|
|
|
{
|
|
|
|
u8 mcs, nss;
|
|
|
|
|
|
|
|
if (!idx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rates += idx - 1;
|
|
|
|
rates[1] = rates[0];
|
|
|
|
switch (phy) {
|
|
|
|
case MT_PHY_TYPE_VHT:
|
|
|
|
mcs = ieee80211_rate_get_vht_mcs(rates);
|
|
|
|
nss = ieee80211_rate_get_vht_nss(rates);
|
|
|
|
|
|
|
|
if (mcs == 0)
|
|
|
|
nss = max_t(int, nss - 1, 1);
|
|
|
|
else
|
|
|
|
mcs--;
|
|
|
|
|
|
|
|
ieee80211_rate_set_vht(rates + 1, mcs, nss);
|
|
|
|
break;
|
|
|
|
case MT_PHY_TYPE_HT_GF:
|
|
|
|
case MT_PHY_TYPE_HT:
|
|
|
|
/* MCS 8 falls back to MCS 0 */
|
|
|
|
if (rates[0].idx == 8) {
|
2019-07-24 01:58:18 -07:00
|
|
|
rates[1].idx = 0;
|
|
|
|
break;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
}
|
2020-09-01 10:33:41 -07:00
|
|
|
fallthrough;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
default:
|
|
|
|
rates[1].idx = max_t(int, rates[0].idx - 1, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
|
2018-10-07 02:45:22 -07:00
|
|
|
struct ieee80211_tx_info *info,
|
|
|
|
struct mt76x02_tx_status *st, int n_frames)
|
2018-09-04 07:41:10 -07:00
|
|
|
{
|
|
|
|
struct ieee80211_tx_rate *rate = info->status.rates;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
struct ieee80211_tx_rate last_rate;
|
|
|
|
u16 first_rate;
|
|
|
|
int retry = st->retry;
|
|
|
|
int phy;
|
2018-09-04 07:41:10 -07:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!n_frames)
|
|
|
|
return;
|
|
|
|
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
|
|
|
|
|
|
|
|
if (st->pktid & MT_PACKET_ID_HAS_RATE) {
|
2019-09-06 01:19:19 -07:00
|
|
|
first_rate = st->rate & ~MT_PKTID_RATE;
|
|
|
|
first_rate |= st->pktid & MT_PKTID_RATE;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
|
|
|
|
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
|
2019-10-12 10:46:40 -07:00
|
|
|
dev->mphy.chandef.chan->band);
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
} else if (rate[0].idx < 0) {
|
|
|
|
if (!msta)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
|
2019-10-12 10:46:40 -07:00
|
|
|
dev->mphy.chandef.chan->band);
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mt76x02_mac_process_tx_rate(&last_rate, st->rate,
|
2019-10-12 10:46:40 -07:00
|
|
|
dev->mphy.chandef.chan->band);
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
|
|
|
|
retry--;
|
|
|
|
if (i + 1 == ARRAY_SIZE(info->status.rates)) {
|
|
|
|
info->status.rates[i] = last_rate;
|
|
|
|
info->status.rates[i].count = max_t(int, retry, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mt76x02_tx_rate_fallback(info->status.rates, i, phy);
|
|
|
|
if (info->status.rates[i].idx == last_rate.idx)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i + 1 < ARRAY_SIZE(info->status.rates)) {
|
|
|
|
info->status.rates[i + 1].idx = -1;
|
|
|
|
info->status.rates[i + 1].count = 0;
|
2018-09-04 07:41:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
info->status.ampdu_len = n_frames;
|
|
|
|
info->status.ampdu_ack_len = st->success ? n_frames : 0;
|
|
|
|
|
|
|
|
if (st->aggr)
|
|
|
|
info->flags |= IEEE80211_TX_CTL_AMPDU |
|
|
|
|
IEEE80211_TX_STAT_AMPDU;
|
|
|
|
|
|
|
|
if (!st->ack_req)
|
|
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
|
|
|
else if (st->success)
|
|
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
|
|
}
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|
|
|
struct mt76x02_tx_status *stat, u8 *update)
|
2018-09-04 07:41:10 -07:00
|
|
|
{
|
|
|
|
struct ieee80211_tx_info info = {};
|
2018-10-25 07:11:34 -07:00
|
|
|
struct ieee80211_tx_status status = {
|
|
|
|
.info = &info
|
|
|
|
};
|
2019-09-06 01:19:19 -07:00
|
|
|
static const u8 ac_to_tid[4] = {
|
|
|
|
[IEEE80211_AC_BE] = 0,
|
|
|
|
[IEEE80211_AC_BK] = 1,
|
|
|
|
[IEEE80211_AC_VI] = 4,
|
|
|
|
[IEEE80211_AC_VO] = 6
|
|
|
|
};
|
2018-09-04 07:41:10 -07:00
|
|
|
struct mt76_wcid *wcid = NULL;
|
|
|
|
struct mt76x02_sta *msta = NULL;
|
2018-10-25 07:11:34 -07:00
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
2018-11-05 13:11:39 -07:00
|
|
|
struct sk_buff_head list;
|
2019-09-06 01:19:19 -07:00
|
|
|
u32 duration = 0;
|
|
|
|
u8 cur_pktid;
|
|
|
|
u32 ac = 0;
|
|
|
|
int len = 0;
|
2018-10-25 07:11:34 -07:00
|
|
|
|
|
|
|
if (stat->pktid == MT_PACKET_ID_NO_ACK)
|
|
|
|
return;
|
2018-09-04 07:41:10 -07:00
|
|
|
|
|
|
|
rcu_read_lock();
|
2018-10-25 07:11:34 -07:00
|
|
|
|
2020-05-19 23:04:47 -07:00
|
|
|
if (stat->wcid < MT76x02_N_WCIDS)
|
2018-10-07 02:45:22 -07:00
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]);
|
2018-09-04 07:41:10 -07:00
|
|
|
|
2018-10-25 05:23:13 -07:00
|
|
|
if (wcid && wcid->sta) {
|
2018-09-04 07:41:10 -07:00
|
|
|
void *priv;
|
|
|
|
|
|
|
|
priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
|
2018-10-25 07:11:34 -07:00
|
|
|
status.sta = container_of(priv, struct ieee80211_sta,
|
|
|
|
drv_priv);
|
|
|
|
}
|
|
|
|
|
2019-04-05 04:42:56 -07:00
|
|
|
mt76_tx_status_lock(mdev, &list);
|
|
|
|
|
2018-10-25 07:11:34 -07:00
|
|
|
if (wcid) {
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
if (mt76_is_skb_pktid(stat->pktid))
|
2018-10-25 07:11:34 -07:00
|
|
|
status.skb = mt76_tx_status_skb_get(mdev, wcid,
|
2018-11-05 13:11:39 -07:00
|
|
|
stat->pktid, &list);
|
2018-10-25 07:11:34 -07:00
|
|
|
if (status.skb)
|
|
|
|
status.info = IEEE80211_SKB_CB(status.skb);
|
2018-09-04 07:41:10 -07:00
|
|
|
}
|
|
|
|
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
|
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
2019-09-06 01:19:19 -07:00
|
|
|
goto out;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
}
|
|
|
|
|
2019-09-06 01:19:19 -07:00
|
|
|
|
2018-10-25 07:11:34 -07:00
|
|
|
if (msta && stat->aggr && !status.skb) {
|
2018-09-04 07:41:10 -07:00
|
|
|
u32 stat_val, stat_cache;
|
|
|
|
|
|
|
|
stat_val = stat->rate;
|
2019-07-24 01:58:18 -07:00
|
|
|
stat_val |= ((u32)stat->retry) << 16;
|
2018-09-04 07:41:10 -07:00
|
|
|
stat_cache = msta->status.rate;
|
2019-07-24 01:58:18 -07:00
|
|
|
stat_cache |= ((u32)msta->status.retry) << 16;
|
2018-09-04 07:41:10 -07:00
|
|
|
|
|
|
|
if (*update == 0 && stat_val == stat_cache &&
|
|
|
|
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
|
|
|
|
msta->n_frames++;
|
2019-04-05 04:42:56 -07:00
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
2019-09-06 01:19:19 -07:00
|
|
|
goto out;
|
2018-09-04 07:41:10 -07:00
|
|
|
}
|
|
|
|
|
2019-09-06 01:19:19 -07:00
|
|
|
cur_pktid = msta->status.pktid;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
mt76x02_mac_fill_tx_status(dev, msta, status.info,
|
|
|
|
&msta->status, msta->n_frames);
|
2018-09-04 07:41:10 -07:00
|
|
|
|
|
|
|
msta->status = *stat;
|
|
|
|
msta->n_frames = 1;
|
|
|
|
*update = 0;
|
|
|
|
} else {
|
2019-09-06 01:19:19 -07:00
|
|
|
cur_pktid = stat->pktid;
|
mt76: mt76x02: fix tx status reporting issues
When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.
To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).
To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.
This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2019-06-05 11:50:52 -07:00
|
|
|
mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
|
2018-09-04 07:41:10 -07:00
|
|
|
*update = 1;
|
|
|
|
}
|
|
|
|
|
2019-09-06 01:19:19 -07:00
|
|
|
if (status.skb) {
|
|
|
|
info = *status.info;
|
|
|
|
len = status.skb->len;
|
|
|
|
ac = skb_get_queue_mapping(status.skb);
|
2018-11-05 13:11:39 -07:00
|
|
|
mt76_tx_status_skb_done(mdev, status.skb, &list);
|
2019-09-06 01:19:19 -07:00
|
|
|
} else if (msta) {
|
|
|
|
len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen);
|
|
|
|
ac = FIELD_GET(MT_PKTID_AC, cur_pktid);
|
|
|
|
}
|
|
|
|
|
2018-11-05 13:11:39 -07:00
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
2019-04-05 04:42:56 -07:00
|
|
|
|
2023-04-14 05:10:54 -07:00
|
|
|
if (!status.skb) {
|
|
|
|
spin_lock_bh(&dev->mt76.rx_lock);
|
2019-04-05 04:42:56 -07:00
|
|
|
ieee80211_tx_status_ext(mt76_hw(dev), &status);
|
2023-04-14 05:10:54 -07:00
|
|
|
spin_unlock_bh(&dev->mt76.rx_lock);
|
|
|
|
}
|
2019-09-06 01:19:19 -07:00
|
|
|
|
|
|
|
if (!len)
|
|
|
|
goto out;
|
|
|
|
|
2019-12-09 09:53:04 -07:00
|
|
|
duration = ieee80211_calc_tx_airtime(mt76_hw(dev), &info, len);
|
2019-09-06 01:19:19 -07:00
|
|
|
|
|
|
|
spin_lock_bh(&dev->mt76.cc_lock);
|
|
|
|
dev->tx_airtime += duration;
|
|
|
|
spin_unlock_bh(&dev->mt76.cc_lock);
|
|
|
|
|
|
|
|
if (msta)
|
|
|
|
ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0);
|
|
|
|
|
|
|
|
out:
|
2018-09-04 07:41:10 -07:00
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
2018-09-04 07:41:12 -07:00
|
|
|
|
2018-10-24 08:57:10 -07:00
|
|
|
static int
|
2019-01-19 08:00:26 -07:00
|
|
|
mt76x02_mac_process_rate(struct mt76x02_dev *dev,
|
|
|
|
struct mt76_rx_status *status,
|
|
|
|
u16 rate)
|
2018-09-04 07:41:12 -07:00
|
|
|
{
|
|
|
|
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
|
|
|
|
|
|
|
|
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
|
|
|
|
case MT_PHY_TYPE_OFDM:
|
|
|
|
if (idx >= 8)
|
|
|
|
idx = 0;
|
|
|
|
|
|
|
|
if (status->band == NL80211_BAND_2GHZ)
|
|
|
|
idx += 4;
|
|
|
|
|
|
|
|
status->rate_idx = idx;
|
|
|
|
return 0;
|
|
|
|
case MT_PHY_TYPE_CCK:
|
|
|
|
if (idx >= 8) {
|
|
|
|
idx -= 8;
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx >= 4)
|
|
|
|
idx = 0;
|
|
|
|
|
|
|
|
status->rate_idx = idx;
|
|
|
|
return 0;
|
|
|
|
case MT_PHY_TYPE_HT_GF:
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_HT_GF;
|
2020-09-01 10:33:41 -07:00
|
|
|
fallthrough;
|
2018-09-04 07:41:12 -07:00
|
|
|
case MT_PHY_TYPE_HT:
|
|
|
|
status->encoding = RX_ENC_HT;
|
|
|
|
status->rate_idx = idx;
|
|
|
|
break;
|
2019-01-19 08:00:26 -07:00
|
|
|
case MT_PHY_TYPE_VHT: {
|
2021-01-04 11:00:06 -07:00
|
|
|
u8 n_rxstream = dev->mphy.chainmask & 0xf;
|
2019-01-19 08:00:26 -07:00
|
|
|
|
2018-09-04 07:41:12 -07:00
|
|
|
status->encoding = RX_ENC_VHT;
|
|
|
|
status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
|
2019-01-19 08:00:26 -07:00
|
|
|
status->nss = min_t(u8, n_rxstream,
|
|
|
|
FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1);
|
2018-09-04 07:41:12 -07:00
|
|
|
break;
|
2019-01-19 08:00:26 -07:00
|
|
|
}
|
2018-09-04 07:41:12 -07:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rate & MT_RXWI_RATE_LDPC)
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_LDPC;
|
|
|
|
|
|
|
|
if (rate & MT_RXWI_RATE_SGI)
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
|
|
|
|
|
|
|
if (rate & MT_RXWI_RATE_STBC)
|
|
|
|
status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
|
|
|
|
|
|
|
|
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
|
|
|
|
case MT_PHY_BW_20:
|
|
|
|
break;
|
|
|
|
case MT_PHY_BW_40:
|
|
|
|
status->bw = RATE_INFO_BW_40;
|
|
|
|
break;
|
|
|
|
case MT_PHY_BW_80:
|
|
|
|
status->bw = RATE_INFO_BW_80;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-09-20 02:11:53 -07:00
|
|
|
|
2019-01-30 09:02:15 -07:00
|
|
|
void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)
|
2018-09-20 02:11:53 -07:00
|
|
|
{
|
2019-01-30 09:02:15 -07:00
|
|
|
static const u8 null_addr[ETH_ALEN] = {};
|
|
|
|
int i;
|
|
|
|
|
2020-11-13 03:11:30 -07:00
|
|
|
ether_addr_copy(dev->mphy.macaddr, addr);
|
2018-09-20 02:11:53 -07:00
|
|
|
|
2020-11-13 03:11:30 -07:00
|
|
|
if (!is_valid_ether_addr(dev->mphy.macaddr)) {
|
|
|
|
eth_random_addr(dev->mphy.macaddr);
|
2018-10-07 02:45:22 -07:00
|
|
|
dev_info(dev->mt76.dev,
|
2018-09-20 02:11:53 -07:00
|
|
|
"Invalid MAC address, using random address %pM\n",
|
2020-11-13 03:11:30 -07:00
|
|
|
dev->mphy.macaddr);
|
2018-09-20 02:11:53 -07:00
|
|
|
}
|
|
|
|
|
2020-11-13 03:11:30 -07:00
|
|
|
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mphy.macaddr));
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76_wr(dev, MT_MAC_ADDR_DW1,
|
2020-11-13 03:11:30 -07:00
|
|
|
get_unaligned_le16(dev->mphy.macaddr + 4) |
|
2018-10-07 02:45:22 -07:00
|
|
|
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
|
2019-01-30 09:02:15 -07:00
|
|
|
|
|
|
|
mt76_wr(dev, MT_MAC_BSSID_DW0,
|
2020-11-13 03:11:30 -07:00
|
|
|
get_unaligned_le32(dev->mphy.macaddr));
|
2019-01-30 09:02:15 -07:00
|
|
|
mt76_wr(dev, MT_MAC_BSSID_DW1,
|
2020-11-13 03:11:30 -07:00
|
|
|
get_unaligned_le16(dev->mphy.macaddr + 4) |
|
2019-01-30 09:02:15 -07:00
|
|
|
FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */
|
|
|
|
MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT);
|
2019-12-18 09:07:50 -07:00
|
|
|
/* enable 7 additional beacon slots and control them with bypass mask */
|
|
|
|
mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, 7);
|
2019-01-30 09:02:15 -07:00
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
mt76x02_mac_set_bssid(dev, i, null_addr);
|
2018-09-20 02:11:53 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr);
|
2018-10-04 14:53:10 -07:00
|
|
|
|
|
|
|
static int
|
|
|
|
mt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain)
|
|
|
|
{
|
|
|
|
struct mt76x02_rx_freq_cal *cal = &dev->cal.rx;
|
|
|
|
|
|
|
|
rssi += cal->rssi_offset[chain];
|
|
|
|
rssi -= cal->lna_gain;
|
|
|
|
|
|
|
|
return rssi;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
|
|
|
|
void *rxi)
|
|
|
|
{
|
2019-07-24 01:58:18 -07:00
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
2020-12-16 08:05:51 -07:00
|
|
|
struct ieee80211_hdr *hdr;
|
2018-10-04 14:53:10 -07:00
|
|
|
struct mt76x02_rxwi *rxwi = rxi;
|
|
|
|
struct mt76x02_sta *sta;
|
|
|
|
u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
|
|
|
|
u32 ctl = le32_to_cpu(rxwi->ctl);
|
|
|
|
u16 rate = le16_to_cpu(rxwi->rate);
|
|
|
|
u16 tid_sn = le16_to_cpu(rxwi->tid_sn);
|
|
|
|
bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST);
|
2021-01-04 11:00:06 -07:00
|
|
|
int pad_len = 0, nstreams = dev->mphy.chainmask & 0xf;
|
2018-10-04 14:53:10 -07:00
|
|
|
s8 signal;
|
|
|
|
u8 pn_len;
|
|
|
|
u8 wcid;
|
|
|
|
int len;
|
|
|
|
|
2019-10-16 03:09:22 -07:00
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
|
2018-10-04 14:53:10 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (rxinfo & MT_RXINFO_L2PAD)
|
|
|
|
pad_len += 2;
|
|
|
|
|
|
|
|
if (rxinfo & MT_RXINFO_DECRYPT) {
|
|
|
|
status->flag |= RX_FLAG_DECRYPTED;
|
|
|
|
status->flag |= RX_FLAG_MMIC_STRIPPED;
|
|
|
|
status->flag |= RX_FLAG_MIC_STRIPPED;
|
|
|
|
status->flag |= RX_FLAG_IV_STRIPPED;
|
|
|
|
}
|
|
|
|
|
|
|
|
wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
|
|
|
|
sta = mt76x02_rx_get_sta(&dev->mt76, wcid);
|
|
|
|
status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast);
|
|
|
|
|
|
|
|
len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
|
|
|
|
pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
|
|
|
|
if (pn_len) {
|
|
|
|
int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
|
|
|
|
u8 *data = skb->data + offset;
|
|
|
|
|
|
|
|
status->iv[0] = data[7];
|
|
|
|
status->iv[1] = data[6];
|
|
|
|
status->iv[2] = data[5];
|
|
|
|
status->iv[3] = data[4];
|
|
|
|
status->iv[4] = data[1];
|
|
|
|
status->iv[5] = data[0];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Driver CCMP validation can't deal with fragments.
|
|
|
|
* Let mac80211 take care of it.
|
|
|
|
*/
|
|
|
|
if (rxinfo & MT_RXINFO_FRAG) {
|
|
|
|
status->flag &= ~RX_FLAG_IV_STRIPPED;
|
|
|
|
} else {
|
|
|
|
pad_len += pn_len << 2;
|
|
|
|
len -= pn_len << 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mt76x02_remove_hdr_pad(skb, pad_len);
|
|
|
|
|
|
|
|
if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
|
|
|
|
status->aggr = true;
|
|
|
|
|
2019-08-28 02:28:36 -07:00
|
|
|
if (rxinfo & MT_RXINFO_AMPDU) {
|
|
|
|
status->flag |= RX_FLAG_AMPDU_DETAILS;
|
2019-11-06 12:04:56 -07:00
|
|
|
status->ampdu_ref = dev->ampdu_ref;
|
2019-08-28 02:28:36 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* When receiving an A-MPDU subframe and RSSI info is not valid,
|
|
|
|
* we can assume that more subframes belonging to the same A-MPDU
|
|
|
|
* are coming. The last one will have valid RSSI info
|
|
|
|
*/
|
2019-09-04 08:45:02 -07:00
|
|
|
if (rxinfo & MT_RXINFO_RSSI) {
|
2019-11-06 12:04:56 -07:00
|
|
|
if (!++dev->ampdu_ref)
|
|
|
|
dev->ampdu_ref++;
|
2019-08-28 02:28:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-04 14:53:10 -07:00
|
|
|
if (WARN_ON_ONCE(len > skb->len))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-07-17 07:50:08 -07:00
|
|
|
if (pskb_trim(skb, len))
|
|
|
|
return -EINVAL;
|
2018-10-04 14:53:10 -07:00
|
|
|
|
|
|
|
status->chains = BIT(0);
|
|
|
|
signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0);
|
2019-02-18 12:29:11 -07:00
|
|
|
status->chain_signal[0] = signal;
|
|
|
|
if (nstreams > 1) {
|
|
|
|
status->chains |= BIT(1);
|
|
|
|
status->chain_signal[1] = mt76x02_mac_get_rssi(dev,
|
|
|
|
rxwi->rssi[1],
|
|
|
|
1);
|
2018-10-04 14:53:10 -07:00
|
|
|
}
|
2019-10-12 10:46:40 -07:00
|
|
|
status->freq = dev->mphy.chandef.chan->center_freq;
|
|
|
|
status->band = dev->mphy.chandef.chan->band;
|
2018-10-04 14:53:10 -07:00
|
|
|
|
2020-12-16 08:05:51 -07:00
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
|
status->qos_ctl = *ieee80211_get_qos_ctl(hdr);
|
2018-10-04 14:53:10 -07:00
|
|
|
status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn);
|
|
|
|
|
2019-01-19 08:00:26 -07:00
|
|
|
return mt76x02_mac_process_rate(dev, status, rate);
|
2018-10-04 14:53:10 -07:00
|
|
|
}
|
2018-10-05 01:28:34 -07:00
|
|
|
|
|
|
|
void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq)
|
|
|
|
{
|
|
|
|
struct mt76x02_tx_status stat = {};
|
|
|
|
u8 update = 1;
|
|
|
|
bool ret;
|
|
|
|
|
2019-10-16 03:09:22 -07:00
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
|
2018-10-05 01:28:34 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
trace_mac_txstat_poll(dev);
|
|
|
|
|
|
|
|
while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
|
2019-01-31 14:38:28 -07:00
|
|
|
if (!spin_trylock(&dev->txstatus_fifo_lock))
|
|
|
|
break;
|
|
|
|
|
2018-10-07 02:45:22 -07:00
|
|
|
ret = mt76x02_mac_load_tx_status(dev, &stat);
|
2019-01-31 14:38:28 -07:00
|
|
|
spin_unlock(&dev->txstatus_fifo_lock);
|
2018-10-05 01:28:34 -07:00
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!irq) {
|
2018-10-07 02:45:22 -07:00
|
|
|
mt76x02_send_tx_status(dev, &stat, &update);
|
2018-10-05 01:28:34 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfifo_put(&dev->txstatus_fifo, stat);
|
|
|
|
}
|
|
|
|
}
|
2018-10-05 01:28:35 -07:00
|
|
|
|
2020-08-23 06:08:02 -07:00
|
|
|
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
2018-10-05 01:28:35 -07:00
|
|
|
{
|
|
|
|
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
|
2018-10-25 07:11:34 -07:00
|
|
|
struct mt76x02_txwi *txwi;
|
2019-04-02 02:47:56 -07:00
|
|
|
u8 *txwi_ptr;
|
2018-10-05 01:28:35 -07:00
|
|
|
|
2018-10-25 07:11:34 -07:00
|
|
|
if (!e->txwi) {
|
2018-10-05 01:28:35 -07:00
|
|
|
dev_kfree_skb_any(e->skb);
|
2018-10-25 07:11:34 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mt76x02_mac_poll_tx_status(dev, false);
|
|
|
|
|
2019-04-02 02:47:56 -07:00
|
|
|
txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi);
|
|
|
|
txwi = (struct mt76x02_txwi *)txwi_ptr;
|
2019-12-29 03:03:06 -07:00
|
|
|
trace_mac_txdone(mdev, txwi->wcid, txwi->pktid);
|
2018-10-25 07:11:34 -07:00
|
|
|
|
2020-08-23 12:22:20 -07:00
|
|
|
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
2018-10-05 01:28:35 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
|
2018-10-15 02:33:11 -07:00
|
|
|
|
2018-12-10 03:53:55 -07:00
|
|
|
void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val)
|
2018-10-20 03:40:54 -07:00
|
|
|
{
|
|
|
|
u32 data = 0;
|
|
|
|
|
|
|
|
if (val != ~0)
|
|
|
|
data = FIELD_PREP(MT_PROT_CFG_CTRL, 1) |
|
|
|
|
MT_PROT_CFG_RTS_THRESH;
|
|
|
|
|
|
|
|
mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, val);
|
|
|
|
|
|
|
|
mt76_rmw(dev, MT_CCK_PROT_CFG,
|
|
|
|
MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data);
|
|
|
|
mt76_rmw(dev, MT_OFDM_PROT_CFG,
|
|
|
|
MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data);
|
|
|
|
}
|
|
|
|
|
2018-12-10 03:53:57 -07:00
|
|
|
void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot,
|
|
|
|
int ht_mode)
|
|
|
|
{
|
|
|
|
int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
|
|
|
|
bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
|
|
|
|
u32 prot[6];
|
|
|
|
u32 vht_prot[3];
|
|
|
|
int i;
|
|
|
|
u16 rts_thr;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(prot); i++) {
|
|
|
|
prot[i] = mt76_rr(dev, MT_CCK_PROT_CFG + i * 4);
|
|
|
|
prot[i] &= ~MT_PROT_CFG_CTRL;
|
|
|
|
if (i >= 2)
|
|
|
|
prot[i] &= ~MT_PROT_CFG_RATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vht_prot); i++) {
|
|
|
|
vht_prot[i] = mt76_rr(dev, MT_TX_PROT_CFG6 + i * 4);
|
|
|
|
vht_prot[i] &= ~(MT_PROT_CFG_CTRL | MT_PROT_CFG_RATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
rts_thr = mt76_get_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH);
|
|
|
|
|
|
|
|
if (rts_thr != 0xffff)
|
|
|
|
prot[0] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
|
|
|
|
if (legacy_prot) {
|
|
|
|
prot[1] |= MT_PROT_CTRL_CTS2SELF;
|
|
|
|
|
|
|
|
prot[2] |= MT_PROT_RATE_CCK_11;
|
|
|
|
prot[3] |= MT_PROT_RATE_CCK_11;
|
|
|
|
prot[4] |= MT_PROT_RATE_CCK_11;
|
|
|
|
prot[5] |= MT_PROT_RATE_CCK_11;
|
|
|
|
|
|
|
|
vht_prot[0] |= MT_PROT_RATE_CCK_11;
|
|
|
|
vht_prot[1] |= MT_PROT_RATE_CCK_11;
|
|
|
|
vht_prot[2] |= MT_PROT_RATE_CCK_11;
|
|
|
|
} else {
|
|
|
|
if (rts_thr != 0xffff)
|
|
|
|
prot[1] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
|
|
|
|
prot[2] |= MT_PROT_RATE_OFDM_24;
|
|
|
|
prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
|
|
|
|
prot[4] |= MT_PROT_RATE_OFDM_24;
|
|
|
|
prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
|
|
|
|
|
|
|
|
vht_prot[0] |= MT_PROT_RATE_OFDM_24;
|
|
|
|
vht_prot[1] |= MT_PROT_RATE_DUP_OFDM_24;
|
|
|
|
vht_prot[2] |= MT_PROT_RATE_SGI_OFDM_24;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
|
|
|
|
case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
|
|
|
|
prot[2] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
prot[3] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
prot[4] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
prot[5] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
vht_prot[0] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
vht_prot[1] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
vht_prot[2] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
break;
|
|
|
|
case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
|
|
|
|
prot[3] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
prot[5] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
vht_prot[1] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
vht_prot[2] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (non_gf) {
|
|
|
|
prot[4] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
prot[5] |= MT_PROT_CTRL_RTS_CTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(prot); i++)
|
|
|
|
mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vht_prot); i++)
|
|
|
|
mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]);
|
|
|
|
}
|
|
|
|
|
2021-06-10 11:43:45 -07:00
|
|
|
void mt76x02_update_channel(struct mt76_phy *mphy)
|
2018-10-15 02:33:11 -07:00
|
|
|
{
|
2021-06-10 11:43:45 -07:00
|
|
|
struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76);
|
2018-10-15 02:33:11 -07:00
|
|
|
struct mt76_channel_state *state;
|
|
|
|
|
2021-06-10 11:43:45 -07:00
|
|
|
state = mphy->chan_state;
|
2019-09-05 09:29:13 -07:00
|
|
|
state->cc_busy += mt76_rr(dev, MT_CH_BUSY);
|
2019-10-15 08:16:43 -07:00
|
|
|
|
|
|
|
spin_lock_bh(&dev->mt76.cc_lock);
|
2019-09-06 01:19:19 -07:00
|
|
|
state->cc_tx += dev->tx_airtime;
|
|
|
|
dev->tx_airtime = 0;
|
2019-10-15 08:16:43 -07:00
|
|
|
spin_unlock_bh(&dev->mt76.cc_lock);
|
2018-10-15 02:33:11 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_update_channel);
|
2018-10-15 02:33:12 -07:00
|
|
|
|
2018-10-15 02:33:15 -07:00
|
|
|
static void mt76x02_check_mac_err(struct mt76x02_dev *dev)
|
|
|
|
{
|
2022-01-31 03:35:34 -07:00
|
|
|
if (dev->mt76.beacon_mask) {
|
|
|
|
if (mt76_rr(dev, MT_TX_STA_0) & MT_TX_STA_0_BEACONS) {
|
|
|
|
dev->beacon_hang_check = 0;
|
|
|
|
return;
|
|
|
|
}
|
2018-10-15 02:33:15 -07:00
|
|
|
|
2022-06-23 02:39:58 -07:00
|
|
|
if (dev->beacon_hang_check < 10)
|
2022-01-31 03:35:34 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
u32 val = mt76_rr(dev, 0x10f4);
|
|
|
|
if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_err(dev->mt76.dev, "MAC error detected\n");
|
2018-10-15 02:33:15 -07:00
|
|
|
|
2022-01-31 03:35:34 -07:00
|
|
|
mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
|
2022-06-23 02:39:58 -07:00
|
|
|
if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) {
|
|
|
|
dev_err(dev->mt76.dev, "MAC stop failed\n");
|
|
|
|
goto out;
|
|
|
|
}
|
2018-10-15 02:33:15 -07:00
|
|
|
|
2022-06-23 02:39:58 -07:00
|
|
|
dev->beacon_hang_check = 0;
|
2018-10-15 02:33:15 -07:00
|
|
|
mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
|
|
|
|
udelay(10);
|
2022-06-23 02:39:58 -07:00
|
|
|
|
|
|
|
out:
|
2018-12-06 04:40:23 -07:00
|
|
|
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
|
|
|
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
|
2018-10-15 02:33:15 -07:00
|
|
|
}
|
|
|
|
|
2018-12-12 14:51:55 -07:00
|
|
|
static void
|
|
|
|
mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable)
|
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
u32 data;
|
|
|
|
|
|
|
|
mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
|
|
|
|
mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN);
|
|
|
|
/* enable pa-lna */
|
|
|
|
data = mt76_rr(dev, MT_TX_PIN_CFG);
|
|
|
|
data |= MT_TX_PIN_CFG_TXANT |
|
|
|
|
MT_TX_PIN_CFG_RXANT |
|
|
|
|
MT_TX_PIN_RFTR_EN |
|
|
|
|
MT_TX_PIN_TRSW_EN;
|
|
|
|
mt76_wr(dev, MT_TX_PIN_CFG, data);
|
|
|
|
} else {
|
|
|
|
mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
|
|
|
|
mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN);
|
|
|
|
/* disable pa-lna */
|
|
|
|
mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT);
|
|
|
|
mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_RXANT);
|
|
|
|
}
|
|
|
|
dev->ed_tx_blocked = !enable;
|
|
|
|
}
|
|
|
|
|
2019-05-11 03:17:51 -07:00
|
|
|
void mt76x02_edcca_init(struct mt76x02_dev *dev)
|
2018-12-12 14:51:55 -07:00
|
|
|
{
|
|
|
|
dev->ed_trigger = 0;
|
|
|
|
dev->ed_silent = 0;
|
|
|
|
|
2019-05-11 03:17:51 -07:00
|
|
|
if (dev->ed_monitor) {
|
2019-10-12 10:46:40 -07:00
|
|
|
struct ieee80211_channel *chan = dev->mphy.chandef.chan;
|
2018-12-12 14:51:55 -07:00
|
|
|
u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20;
|
|
|
|
|
|
|
|
mt76_clear(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN);
|
|
|
|
mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
|
|
|
|
mt76_rmw(dev, MT_BBP(AGC, 2), GENMASK(15, 0),
|
|
|
|
ed_th << 8 | ed_th);
|
2019-02-25 10:37:42 -07:00
|
|
|
mt76_set(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN);
|
2018-12-12 14:51:55 -07:00
|
|
|
} else {
|
|
|
|
mt76_set(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN);
|
|
|
|
mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
|
|
|
|
if (is_mt76x2(dev)) {
|
|
|
|
mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070);
|
2019-02-25 10:37:42 -07:00
|
|
|
mt76_set(dev, MT_TXOP_HLDR_ET,
|
|
|
|
MT_TXOP_HLDR_TX40M_BLK_EN);
|
2018-12-12 14:51:55 -07:00
|
|
|
} else {
|
|
|
|
mt76_wr(dev, MT_BBP(AGC, 2), 0x003a6464);
|
|
|
|
mt76_clear(dev, MT_TXOP_HLDR_ET,
|
|
|
|
MT_TXOP_HLDR_TX40M_BLK_EN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mt76x02_edcca_tx_enable(dev, true);
|
2019-03-02 10:19:20 -07:00
|
|
|
dev->ed_monitor_learning = true;
|
2019-02-03 06:15:58 -07:00
|
|
|
|
|
|
|
/* clear previous CCA timer value */
|
|
|
|
mt76_rr(dev, MT_ED_CCA_TIMER);
|
2019-02-03 06:41:22 -07:00
|
|
|
dev->ed_time = ktime_get_boottime();
|
2018-12-12 14:51:55 -07:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_edcca_init);
|
|
|
|
|
2019-02-03 12:35:31 -07:00
|
|
|
#define MT_EDCCA_TH 92
|
2018-12-12 14:51:55 -07:00
|
|
|
#define MT_EDCCA_BLOCK_TH 2
|
2019-03-02 10:19:20 -07:00
|
|
|
#define MT_EDCCA_LEARN_TH 50
|
|
|
|
#define MT_EDCCA_LEARN_CCA 180
|
|
|
|
#define MT_EDCCA_LEARN_TIMEOUT (20 * HZ)
|
|
|
|
|
2018-12-12 14:51:55 -07:00
|
|
|
static void mt76x02_edcca_check(struct mt76x02_dev *dev)
|
|
|
|
{
|
2019-02-03 06:41:22 -07:00
|
|
|
ktime_t cur_time;
|
|
|
|
u32 active, val, busy;
|
2018-12-12 14:51:55 -07:00
|
|
|
|
2019-02-03 06:41:22 -07:00
|
|
|
cur_time = ktime_get_boottime();
|
2018-12-12 14:51:55 -07:00
|
|
|
val = mt76_rr(dev, MT_ED_CCA_TIMER);
|
2019-02-03 06:41:22 -07:00
|
|
|
|
|
|
|
active = ktime_to_us(ktime_sub(cur_time, dev->ed_time));
|
|
|
|
dev->ed_time = cur_time;
|
|
|
|
|
|
|
|
busy = (val * 100) / active;
|
2018-12-12 14:51:55 -07:00
|
|
|
busy = min_t(u32, busy, 100);
|
|
|
|
|
|
|
|
if (busy > MT_EDCCA_TH) {
|
|
|
|
dev->ed_trigger++;
|
|
|
|
dev->ed_silent = 0;
|
|
|
|
} else {
|
|
|
|
dev->ed_silent++;
|
|
|
|
dev->ed_trigger = 0;
|
|
|
|
}
|
|
|
|
|
2019-03-02 10:19:20 -07:00
|
|
|
if (dev->cal.agc_lowest_gain &&
|
|
|
|
dev->cal.false_cca > MT_EDCCA_LEARN_CCA &&
|
|
|
|
dev->ed_trigger > MT_EDCCA_LEARN_TH) {
|
|
|
|
dev->ed_monitor_learning = false;
|
|
|
|
dev->ed_trigger_timeout = jiffies + 20 * HZ;
|
|
|
|
} else if (!dev->ed_monitor_learning &&
|
|
|
|
time_is_after_jiffies(dev->ed_trigger_timeout)) {
|
|
|
|
dev->ed_monitor_learning = true;
|
|
|
|
mt76x02_edcca_tx_enable(dev, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->ed_monitor_learning)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (dev->ed_trigger > MT_EDCCA_BLOCK_TH && !dev->ed_tx_blocked)
|
2018-12-12 14:51:55 -07:00
|
|
|
mt76x02_edcca_tx_enable(dev, false);
|
2019-03-02 10:19:20 -07:00
|
|
|
else if (dev->ed_silent > MT_EDCCA_BLOCK_TH && dev->ed_tx_blocked)
|
2018-12-12 14:51:55 -07:00
|
|
|
mt76x02_edcca_tx_enable(dev, true);
|
|
|
|
}
|
|
|
|
|
2018-10-15 02:33:12 -07:00
|
|
|
void mt76x02_mac_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
|
2021-01-04 11:00:05 -07:00
|
|
|
mphy.mac_work.work);
|
2018-10-15 02:33:12 -07:00
|
|
|
int i, idx;
|
|
|
|
|
2018-12-06 09:07:39 -07:00
|
|
|
mutex_lock(&dev->mt76.mutex);
|
|
|
|
|
2021-06-10 11:43:45 -07:00
|
|
|
mt76_update_survey(&dev->mphy);
|
2018-10-15 02:33:12 -07:00
|
|
|
for (i = 0, idx = 0; i < 16; i++) {
|
|
|
|
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
|
|
|
|
|
2022-11-02 15:29:15 -07:00
|
|
|
dev->mphy.aggr_stats[idx++] += val & 0xffff;
|
|
|
|
dev->mphy.aggr_stats[idx++] += val >> 16;
|
2018-10-15 02:33:12 -07:00
|
|
|
}
|
|
|
|
|
2022-01-31 03:35:34 -07:00
|
|
|
mt76x02_check_mac_err(dev);
|
2018-10-15 02:33:15 -07:00
|
|
|
|
2018-12-12 14:51:55 -07:00
|
|
|
if (dev->ed_monitor)
|
|
|
|
mt76x02_edcca_check(dev);
|
|
|
|
|
2018-12-06 09:07:39 -07:00
|
|
|
mutex_unlock(&dev->mt76.mutex);
|
|
|
|
|
2021-09-13 02:25:03 -07:00
|
|
|
mt76_tx_status_check(&dev->mt76, false);
|
2018-10-25 07:11:34 -07:00
|
|
|
|
2021-01-04 11:00:05 -07:00
|
|
|
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
|
2019-02-03 06:13:06 -07:00
|
|
|
MT_MAC_WORK_INTERVAL);
|
2018-10-15 02:33:12 -07:00
|
|
|
}
|
2018-10-20 03:13:25 -07:00
|
|
|
|
2019-09-05 09:29:13 -07:00
|
|
|
void mt76x02_mac_cc_reset(struct mt76x02_dev *dev)
|
|
|
|
{
|
2019-10-12 10:46:40 -07:00
|
|
|
dev->mphy.survey_time = ktime_get_boottime();
|
2019-09-05 09:29:13 -07:00
|
|
|
|
2019-09-05 10:30:21 -07:00
|
|
|
mt76_wr(dev, MT_CH_TIME_CFG,
|
|
|
|
MT_CH_TIME_CFG_TIMER_EN |
|
|
|
|
MT_CH_TIME_CFG_TX_AS_BUSY |
|
|
|
|
MT_CH_TIME_CFG_RX_AS_BUSY |
|
|
|
|
MT_CH_TIME_CFG_NAV_AS_BUSY |
|
|
|
|
MT_CH_TIME_CFG_EIFS_AS_BUSY |
|
|
|
|
MT_CH_CCA_RC_EN |
|
|
|
|
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
|
|
|
|
|
2019-09-05 09:29:13 -07:00
|
|
|
/* channel cycle counters read-and-clear */
|
|
|
|
mt76_rr(dev, MT_CH_BUSY);
|
|
|
|
mt76_rr(dev, MT_CH_IDLE);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_cc_reset);
|
|
|
|
|
2018-10-20 03:13:25 -07:00
|
|
|
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
|
|
|
|
{
|
|
|
|
idx &= 7;
|
|
|
|
mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr));
|
|
|
|
mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR,
|
|
|
|
get_unaligned_le16(addr + 4));
|
|
|
|
}
|