2019-07-24 16:58:20 +08:00
|
|
|
// SPDX-License-Identifier: ISC
|
2018-08-29 13:16:36 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
|
|
|
|
|
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
|
|
|
|
|
*/
|
|
|
|
|
|
2018-10-05 10:00:33 +02:00
|
|
|
#include "mt76x02.h"
|
2018-10-05 10:28:34 +02:00
|
|
|
#include "mt76x02_trace.h"
|
2018-08-29 13:16:36 +02:00
|
|
|
|
2019-09-12 11:06:35 +02: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);
|
|
|
|
|
|
2019-09-13 09:05:52 +02:00
|
|
|
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
|
2019-09-12 11:06:35 +02:00
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters);
|
|
|
|
|
|
2018-10-17 13:10:16 +02:00
|
|
|
static enum mt76x02_cipher_type
|
2018-08-29 13:16:36 +02:00
|
|
|
mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
|
|
|
|
|
{
|
|
|
|
|
memset(key_data, 0, 32);
|
|
|
|
|
if (!key)
|
|
|
|
|
return MT_CIPHER_NONE;
|
|
|
|
|
|
|
|
|
|
if (key->keylen > 32)
|
|
|
|
|
return MT_CIPHER_NONE;
|
|
|
|
|
|
|
|
|
|
memcpy(key_data, key->key, key->keylen);
|
|
|
|
|
|
|
|
|
|
switch (key->cipher) {
|
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
|
|
|
return MT_CIPHER_WEP40;
|
|
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
|
|
|
return MT_CIPHER_WEP104;
|
|
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
|
|
|
return MT_CIPHER_TKIP;
|
|
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
|
|
|
return MT_CIPHER_AES_CCMP;
|
|
|
|
|
default:
|
|
|
|
|
return MT_CIPHER_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-29 13:16:38 +02:00
|
|
|
|
2018-10-07 11:45:22 +02: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 13:16:38 +02:00
|
|
|
{
|
|
|
|
|
enum mt76x02_cipher_type cipher;
|
|
|
|
|
u8 key_data[32];
|
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
|
|
cipher = mt76x02_mac_get_key_info(key, key_data);
|
|
|
|
|
if (cipher == MT_CIPHER_NONE && key)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
|
2018-08-29 13:16:38 +02: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 11:45:22 +02:00
|
|
|
mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
|
2018-08-29 13:16:38 +02:00
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data,
|
|
|
|
|
sizeof(key_data));
|
2018-08-29 13:16:38 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup);
|
2018-08-29 13:16:39 +02:00
|
|
|
|
2019-02-27 19:42:39 +01: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;
|
|
|
|
|
if (cipher == MT_CIPHER_TKIP) {
|
|
|
|
|
pn |= (iv >> 16) & 0xff;
|
|
|
|
|
pn |= (iv & 0xff) << 8;
|
|
|
|
|
} else if (cipher >= MT_CIPHER_AES_CCMP) {
|
|
|
|
|
pn |= iv & 0xffff;
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
atomic64_set(&key->tx_pn, pn);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
|
|
|
|
|
struct ieee80211_key_conf *key)
|
2018-08-29 13:16:39 +02:00
|
|
|
{
|
|
|
|
|
enum mt76x02_cipher_type cipher;
|
|
|
|
|
u8 key_data[32];
|
|
|
|
|
u8 iv_data[8];
|
2019-02-27 19:40:27 +01:00
|
|
|
u64 pn;
|
2018-08-29 13:16:39 +02:00
|
|
|
|
|
|
|
|
cipher = mt76x02_mac_get_key_info(key, key_data);
|
|
|
|
|
if (cipher == MT_CIPHER_NONE && key)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
2018-10-07 11:45:22 +02: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 13:16:39 +02:00
|
|
|
|
|
|
|
|
memset(iv_data, 0, sizeof(iv_data));
|
|
|
|
|
if (key) {
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE,
|
|
|
|
|
!!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
|
2019-02-27 19:40:27 +01:00
|
|
|
|
|
|
|
|
pn = atomic64_read(&key->tx_pn);
|
|
|
|
|
|
2018-08-29 13:16:39 +02:00
|
|
|
iv_data[3] = key->keyidx << 6;
|
2019-02-27 19:40:27 +01:00
|
|
|
if (cipher >= MT_CIPHER_TKIP) {
|
2018-08-29 13:16:39 +02:00
|
|
|
iv_data[3] |= 0x20;
|
2019-02-27 19:40:27 +01:00
|
|
|
put_unaligned_le32(pn >> 16, &iv_data[4]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cipher == MT_CIPHER_TKIP) {
|
|
|
|
|
iv_data[0] = (pn >> 8) & 0xff;
|
|
|
|
|
iv_data[1] = (iv_data[0] | 0x20) & 0x7f;
|
|
|
|
|
iv_data[2] = pn & 0xff;
|
|
|
|
|
} else if (cipher >= MT_CIPHER_AES_CCMP) {
|
|
|
|
|
put_unaligned_le16((pn & 0xffff), &iv_data[0]);
|
|
|
|
|
}
|
2018-08-29 13:16:39 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
|
2018-08-29 13:16:39 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2018-08-29 13:16:40 +02:00
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx,
|
|
|
|
|
u8 vif_idx, u8 *mac)
|
2018-08-29 13:16:40 +02: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 11:45:22 +02:00
|
|
|
mt76_wr(dev, MT_WCID_ATTR(idx), attr);
|
2018-08-29 13:16:40 +02:00
|
|
|
|
|
|
|
|
if (idx >= 128)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (mac)
|
|
|
|
|
memcpy(addr.macaddr, mac, ETH_ALEN);
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr));
|
2018-08-29 13:16:40 +02:00
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup);
|
2018-08-29 13:16:41 +02:00
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)
|
2018-08-29 13:16:41 +02:00
|
|
|
{
|
2018-10-07 11:45:22 +02:00
|
|
|
u32 val = mt76_rr(dev, MT_WCID_DROP(idx));
|
2018-08-29 13:16:41 +02:00
|
|
|
u32 bit = MT_WCID_DROP_MASK(idx);
|
|
|
|
|
|
|
|
|
|
/* prevent unnecessary writes */
|
|
|
|
|
if ((val & bit) != (bit * drop))
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
|
2018-08-29 13:16:41 +02:00
|
|
|
}
|
2018-08-29 13:16:44 +02:00
|
|
|
|
2018-10-01 18:58:20 +02:00
|
|
|
static __le16
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
|
|
|
|
|
const struct ieee80211_tx_rate *rate, u8 *nss_val)
|
2018-09-04 16:41:07 +02:00
|
|
|
{
|
2018-12-28 11:00:47 +01:00
|
|
|
u8 phy, rate_idx, nss, bw = 0;
|
2018-09-04 16:41:07 +02: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;
|
2018-10-07 11:45:22 +02:00
|
|
|
int band = dev->mt76.chandef.chan->band;
|
2018-09-04 16:41:07 +02:00
|
|
|
u16 val;
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx];
|
2018-09-04 16:41:07 +02: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 11:00:47 +01:00
|
|
|
nss = 1;
|
2018-09-04 16:41:07 +02: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;
|
|
|
|
|
return cpu_to_le16(rateval);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
|
|
|
|
|
const struct ieee80211_tx_rate *rate)
|
2018-09-04 16:41:07 +02:00
|
|
|
{
|
2019-03-13 14:20:06 +01:00
|
|
|
s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
|
|
|
|
|
__le16 rateval;
|
|
|
|
|
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 16:41:07 +02:00
|
|
|
}
|
2018-09-04 16:41:09 +02:00
|
|
|
|
2018-10-19 14:56:24 +02: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 11:45:22 +02:00
|
|
|
bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev,
|
|
|
|
|
struct mt76x02_tx_status *stat)
|
2018-09-04 16:41:09 +02:00
|
|
|
{
|
|
|
|
|
u32 stat1, stat2;
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
|
|
|
|
|
stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
|
2018-09-04 16:41:09 +02: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-18 00:35:32 +02:00
|
|
|
trace_mac_txstat_fetch(dev, stat);
|
|
|
|
|
|
2018-09-04 16:41:09 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-04 16:41:10 +02:00
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
|
2019-07-24 16:58:18 +08:00
|
|
|
enum nl80211_band band)
|
2018-09-04 16:41:10 +02: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;
|
|
|
|
|
/* fall through */
|
|
|
|
|
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 11:45:22 +02:00
|
|
|
void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
|
2018-10-01 18:58:19 +02:00
|
|
|
struct sk_buff *skb, struct mt76_wcid *wcid,
|
|
|
|
|
struct ieee80211_sta *sta, int len)
|
|
|
|
|
{
|
2018-10-07 11:57:21 +02:00
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
2018-10-01 18:58:19 +02: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 14:20:06 +01:00
|
|
|
u32 wcid_tx_info;
|
2018-10-01 18:58:19 +02:00
|
|
|
u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
|
2018-10-07 11:57:21 +02:00
|
|
|
u16 txwi_flags = 0;
|
2018-10-01 18:58:19 +02:00
|
|
|
u8 nss;
|
|
|
|
|
s8 txpwr_adj, max_txpwr_adj;
|
2018-10-07 11:45:22 +02:00
|
|
|
u8 ccmp_pn[8], nstreams = dev->mt76.chainmask & 0xf;
|
2018-10-01 18:58:19 +02:00
|
|
|
|
|
|
|
|
memset(txwi, 0, sizeof(*txwi));
|
|
|
|
|
|
2019-01-31 21:01:24 +01: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 16:58:18 +08:00
|
|
|
info->control.rates, 1);
|
2019-01-31 21:01:24 +01:00
|
|
|
}
|
|
|
|
|
|
2018-10-01 18:58:19 +02: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 16:58:18 +08:00
|
|
|
|
2018-10-01 18:58:19 +02: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 17:59:06 +01:00
|
|
|
txwi->eiv = *((__le32 *)&ccmp_pn[4]);
|
2018-10-01 18:58:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wcid && (rate->idx < 0 || !rate->count)) {
|
2019-03-13 14:20:06 +01:00
|
|
|
wcid_tx_info = wcid->tx_info;
|
|
|
|
|
txwi->rate = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
|
|
|
|
|
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 18:58:19 +02:00
|
|
|
} else {
|
|
|
|
|
txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss);
|
2018-10-07 11:45:23 +02:00
|
|
|
max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
|
2018-10-01 18:58:19 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-07 11:45:23 +02:00
|
|
|
txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf,
|
2018-10-05 10:28:31 +02:00
|
|
|
max_txpwr_adj);
|
|
|
|
|
txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj);
|
2018-10-01 18:58:19 +02:00
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4)
|
2018-10-01 18:58:19 +02:00
|
|
|
txwi->txstream = 0x13;
|
2018-10-07 11:45:22 +02:00
|
|
|
else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 &&
|
2018-10-01 18:58:19 +02:00
|
|
|
!(txwi->rate & cpu_to_le16(rate_ht_mask)))
|
|
|
|
|
txwi->txstream = 0x93;
|
|
|
|
|
|
2018-10-07 11:57:21 +02: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);
|
|
|
|
|
if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
ba_size <<= sta->ht_cap.ampdu_factor;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
txwi_flags |= MT_TXWI_FLAGS_AMPDU |
|
|
|
|
|
FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY,
|
|
|
|
|
sta->ht_cap.ampdu_density);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 18:58:19 +02:00
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
|
|
|
|
|
|
2018-09-04 16:41:10 +02: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 20:50:52 +02: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 16:58:18 +08: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 20:50:52 +02:00
|
|
|
}
|
|
|
|
|
/* fall through */
|
|
|
|
|
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 11:45:22 +02:00
|
|
|
struct ieee80211_tx_info *info,
|
|
|
|
|
struct mt76x02_tx_status *st, int n_frames)
|
2018-09-04 16:41:10 +02: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 20:50:52 +02:00
|
|
|
struct ieee80211_tx_rate last_rate;
|
|
|
|
|
u16 first_rate;
|
|
|
|
|
int retry = st->retry;
|
|
|
|
|
int phy;
|
2018-09-04 16:41:10 +02: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 20:50:52 +02:00
|
|
|
phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
|
|
|
|
|
|
|
|
|
|
if (st->pktid & MT_PACKET_ID_HAS_RATE) {
|
|
|
|
|
first_rate = st->rate & ~MT_RXWI_RATE_INDEX;
|
|
|
|
|
first_rate |= st->pktid & MT_RXWI_RATE_INDEX;
|
|
|
|
|
|
|
|
|
|
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
|
|
|
|
|
dev->mt76.chandef.chan->band);
|
|
|
|
|
} else if (rate[0].idx < 0) {
|
|
|
|
|
if (!msta)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
|
|
|
|
|
dev->mt76.chandef.chan->band);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mt76x02_mac_process_tx_rate(&last_rate, st->rate,
|
2018-10-07 11:45:22 +02:00
|
|
|
dev->mt76.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 20:50:52 +02: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 16:41:10 +02: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 11:45:22 +02:00
|
|
|
void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|
|
|
|
struct mt76x02_tx_status *stat, u8 *update)
|
2018-09-04 16:41:10 +02:00
|
|
|
{
|
|
|
|
|
struct ieee80211_tx_info info = {};
|
2018-10-25 16:11:34 +02:00
|
|
|
struct ieee80211_tx_status status = {
|
|
|
|
|
.info = &info
|
|
|
|
|
};
|
2018-09-04 16:41:10 +02:00
|
|
|
struct mt76_wcid *wcid = NULL;
|
|
|
|
|
struct mt76x02_sta *msta = NULL;
|
2018-10-25 16:11:34 +02:00
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
2018-11-05 21:11:39 +01:00
|
|
|
struct sk_buff_head list;
|
2018-10-25 16:11:34 +02:00
|
|
|
|
|
|
|
|
if (stat->pktid == MT_PACKET_ID_NO_ACK)
|
|
|
|
|
return;
|
2018-09-04 16:41:10 +02:00
|
|
|
|
|
|
|
|
rcu_read_lock();
|
2018-10-25 16:11:34 +02:00
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid))
|
|
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]);
|
2018-09-04 16:41:10 +02:00
|
|
|
|
2018-10-25 14:23:13 +02:00
|
|
|
if (wcid && wcid->sta) {
|
2018-09-04 16:41:10 +02:00
|
|
|
void *priv;
|
|
|
|
|
|
|
|
|
|
priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
|
2018-10-25 16:11:34 +02:00
|
|
|
status.sta = container_of(priv, struct ieee80211_sta,
|
|
|
|
|
drv_priv);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-05 13:42:56 +02:00
|
|
|
mt76_tx_status_lock(mdev, &list);
|
|
|
|
|
|
2018-10-25 16:11:34 +02: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 20:50:52 +02:00
|
|
|
if (mt76_is_skb_pktid(stat->pktid))
|
2018-10-25 16:11:34 +02:00
|
|
|
status.skb = mt76_tx_status_skb_get(mdev, wcid,
|
2018-11-05 21:11:39 +01:00
|
|
|
stat->pktid, &list);
|
2018-10-25 16:11:34 +02:00
|
|
|
if (status.skb)
|
|
|
|
|
status.info = IEEE80211_SKB_CB(status.skb);
|
2018-09-04 16:41:10 +02: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 20:50:52 +02:00
|
|
|
if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
|
|
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 16:11:34 +02:00
|
|
|
if (msta && stat->aggr && !status.skb) {
|
2018-09-04 16:41:10 +02:00
|
|
|
u32 stat_val, stat_cache;
|
|
|
|
|
|
|
|
|
|
stat_val = stat->rate;
|
2019-07-24 16:58:18 +08:00
|
|
|
stat_val |= ((u32)stat->retry) << 16;
|
2018-09-04 16:41:10 +02:00
|
|
|
stat_cache = msta->status.rate;
|
2019-07-24 16:58:18 +08:00
|
|
|
stat_cache |= ((u32)msta->status.retry) << 16;
|
2018-09-04 16:41:10 +02:00
|
|
|
|
|
|
|
|
if (*update == 0 && stat_val == stat_cache &&
|
|
|
|
|
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
|
|
|
|
|
msta->n_frames++;
|
2019-04-05 13:42:56 +02:00
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
return;
|
2018-09-04 16:41:10 +02: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 20:50:52 +02:00
|
|
|
mt76x02_mac_fill_tx_status(dev, msta, status.info,
|
|
|
|
|
&msta->status, msta->n_frames);
|
2018-09-04 16:41:10 +02:00
|
|
|
|
|
|
|
|
msta->status = *stat;
|
|
|
|
|
msta->n_frames = 1;
|
|
|
|
|
*update = 0;
|
|
|
|
|
} else {
|
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 20:50:52 +02:00
|
|
|
mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
|
2018-09-04 16:41:10 +02:00
|
|
|
*update = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 16:11:34 +02:00
|
|
|
if (status.skb)
|
2018-11-05 21:11:39 +01:00
|
|
|
mt76_tx_status_skb_done(mdev, status.skb, &list);
|
|
|
|
|
mt76_tx_status_unlock(mdev, &list);
|
2019-04-05 13:42:56 +02:00
|
|
|
|
|
|
|
|
if (!status.skb)
|
|
|
|
|
ieee80211_tx_status_ext(mt76_hw(dev), &status);
|
2018-09-04 16:41:10 +02:00
|
|
|
rcu_read_unlock();
|
|
|
|
|
}
|
2018-09-04 16:41:12 +02:00
|
|
|
|
2018-10-24 17:57:10 +02:00
|
|
|
static int
|
2019-01-19 16:00:26 +01:00
|
|
|
mt76x02_mac_process_rate(struct mt76x02_dev *dev,
|
|
|
|
|
struct mt76_rx_status *status,
|
|
|
|
|
u16 rate)
|
2018-09-04 16:41:12 +02: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;
|
|
|
|
|
/* fall through */
|
|
|
|
|
case MT_PHY_TYPE_HT:
|
|
|
|
|
status->encoding = RX_ENC_HT;
|
|
|
|
|
status->rate_idx = idx;
|
|
|
|
|
break;
|
2019-01-19 16:00:26 +01:00
|
|
|
case MT_PHY_TYPE_VHT: {
|
|
|
|
|
u8 n_rxstream = dev->mt76.chainmask & 0xf;
|
|
|
|
|
|
2018-09-04 16:41:12 +02:00
|
|
|
status->encoding = RX_ENC_VHT;
|
|
|
|
|
status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
|
2019-01-19 16:00:26 +01:00
|
|
|
status->nss = min_t(u8, n_rxstream,
|
|
|
|
|
FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1);
|
2018-09-04 16:41:12 +02:00
|
|
|
break;
|
2019-01-19 16:00:26 +01:00
|
|
|
}
|
2018-09-04 16:41:12 +02: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 11:11:53 +02:00
|
|
|
|
2019-01-30 17:02:15 +01:00
|
|
|
void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)
|
2018-09-20 11:11:53 +02:00
|
|
|
{
|
2019-01-30 17:02:15 +01:00
|
|
|
static const u8 null_addr[ETH_ALEN] = {};
|
|
|
|
|
int i;
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
ether_addr_copy(dev->mt76.macaddr, addr);
|
2018-09-20 11:11:53 +02:00
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
if (!is_valid_ether_addr(dev->mt76.macaddr)) {
|
|
|
|
|
eth_random_addr(dev->mt76.macaddr);
|
|
|
|
|
dev_info(dev->mt76.dev,
|
2018-09-20 11:11:53 +02:00
|
|
|
"Invalid MAC address, using random address %pM\n",
|
2018-10-07 11:45:22 +02:00
|
|
|
dev->mt76.macaddr);
|
2018-09-20 11:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
|
|
|
|
|
mt76_wr(dev, MT_MAC_ADDR_DW1,
|
|
|
|
|
get_unaligned_le16(dev->mt76.macaddr + 4) |
|
|
|
|
|
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
|
2019-01-30 17:02:15 +01:00
|
|
|
|
|
|
|
|
mt76_wr(dev, MT_MAC_BSSID_DW0,
|
|
|
|
|
get_unaligned_le32(dev->mt76.macaddr));
|
|
|
|
|
mt76_wr(dev, MT_MAC_BSSID_DW1,
|
|
|
|
|
get_unaligned_le16(dev->mt76.macaddr + 4) |
|
|
|
|
|
FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */
|
|
|
|
|
MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
|
mt76x02_mac_set_bssid(dev, i, null_addr);
|
2018-09-20 11:11:53 +02:00
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr);
|
2018-10-04 23:53:10 +02: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 16:58:18 +08:00
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
2018-10-04 23:53:10 +02: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);
|
2019-02-18 20:29:11 +01:00
|
|
|
int pad_len = 0, nstreams = dev->mt76.chainmask & 0xf;
|
2018-10-04 23:53:10 +02:00
|
|
|
s8 signal;
|
|
|
|
|
u8 pn_len;
|
|
|
|
|
u8 wcid;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (WARN_ON_ONCE(len > skb->len))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
pskb_trim(skb, len);
|
|
|
|
|
|
|
|
|
|
status->chains = BIT(0);
|
|
|
|
|
signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0);
|
2019-02-18 20:29:11 +01: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);
|
|
|
|
|
signal = max_t(s8, signal, status->chain_signal[1]);
|
2018-10-04 23:53:10 +02:00
|
|
|
}
|
|
|
|
|
status->signal = signal;
|
|
|
|
|
status->freq = dev->mt76.chandef.chan->center_freq;
|
|
|
|
|
status->band = dev->mt76.chandef.chan->band;
|
|
|
|
|
|
|
|
|
|
status->tid = FIELD_GET(MT_RXWI_TID, tid_sn);
|
|
|
|
|
status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn);
|
|
|
|
|
|
2019-01-19 16:00:26 +01:00
|
|
|
return mt76x02_mac_process_rate(dev, status, rate);
|
2018-10-04 23:53:10 +02:00
|
|
|
}
|
2018-10-05 10:28:34 +02:00
|
|
|
|
|
|
|
|
void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq)
|
|
|
|
|
{
|
|
|
|
|
struct mt76x02_tx_status stat = {};
|
|
|
|
|
u8 update = 1;
|
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
trace_mac_txstat_poll(dev);
|
|
|
|
|
|
|
|
|
|
while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
|
2019-01-31 22:38:28 +01:00
|
|
|
if (!spin_trylock(&dev->txstatus_fifo_lock))
|
|
|
|
|
break;
|
|
|
|
|
|
2018-10-07 11:45:22 +02:00
|
|
|
ret = mt76x02_mac_load_tx_status(dev, &stat);
|
2019-01-31 22:38:28 +01:00
|
|
|
spin_unlock(&dev->txstatus_fifo_lock);
|
2018-10-05 10:28:34 +02:00
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!irq) {
|
2018-10-07 11:45:22 +02:00
|
|
|
mt76x02_send_tx_status(dev, &stat, &update);
|
2018-10-05 10:28:34 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kfifo_put(&dev->txstatus_fifo, stat);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-05 10:28:35 +02:00
|
|
|
|
2019-03-02 14:47:40 +01:00
|
|
|
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
|
|
|
|
struct mt76_queue_entry *e)
|
2018-10-05 10:28:35 +02:00
|
|
|
{
|
|
|
|
|
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
|
2018-10-25 16:11:34 +02:00
|
|
|
struct mt76x02_txwi *txwi;
|
2019-04-02 11:47:56 +02:00
|
|
|
u8 *txwi_ptr;
|
2018-10-05 10:28:35 +02:00
|
|
|
|
2018-10-25 16:11:34 +02:00
|
|
|
if (!e->txwi) {
|
2018-10-05 10:28:35 +02:00
|
|
|
dev_kfree_skb_any(e->skb);
|
2018-10-25 16:11:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mt76x02_mac_poll_tx_status(dev, false);
|
|
|
|
|
|
2019-04-02 11:47:56 +02:00
|
|
|
txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi);
|
|
|
|
|
txwi = (struct mt76x02_txwi *)txwi_ptr;
|
2018-10-25 16:11:34 +02:00
|
|
|
trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid);
|
|
|
|
|
|
|
|
|
|
mt76_tx_complete_skb(mdev, e->skb);
|
2018-10-05 10:28:35 +02:00
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
|
2018-10-15 11:33:11 +02:00
|
|
|
|
2018-12-10 11:53:55 +01:00
|
|
|
void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val)
|
2018-10-20 12:40:54 +02: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 11:53:57 +01: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]);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 11:33:11 +02:00
|
|
|
void mt76x02_update_channel(struct mt76_dev *mdev)
|
|
|
|
|
{
|
|
|
|
|
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
|
|
|
|
|
struct mt76_channel_state *state;
|
|
|
|
|
u32 active, busy;
|
|
|
|
|
|
|
|
|
|
state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan);
|
|
|
|
|
|
|
|
|
|
busy = mt76_rr(dev, MT_CH_BUSY);
|
|
|
|
|
active = busy + mt76_rr(dev, MT_CH_IDLE);
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&dev->mt76.cc_lock);
|
|
|
|
|
state->cc_busy += busy;
|
|
|
|
|
state->cc_active += active;
|
|
|
|
|
spin_unlock_bh(&dev->mt76.cc_lock);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_update_channel);
|
2018-10-15 11:33:12 +02:00
|
|
|
|
2018-10-15 11:33:15 +02:00
|
|
|
static void mt76x02_check_mac_err(struct mt76x02_dev *dev)
|
|
|
|
|
{
|
|
|
|
|
u32 val = mt76_rr(dev, 0x10f4);
|
|
|
|
|
|
|
|
|
|
if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
dev_err(dev->mt76.dev, "mac specific condition occurred\n");
|
|
|
|
|
|
|
|
|
|
mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
|
|
|
|
|
udelay(10);
|
2018-12-06 12:40:23 +01:00
|
|
|
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
|
|
|
|
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
|
2018-10-15 11:33:15 +02:00
|
|
|
}
|
|
|
|
|
|
2018-12-12 22:51:55 +01: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 12:17:51 +02:00
|
|
|
void mt76x02_edcca_init(struct mt76x02_dev *dev)
|
2018-12-12 22:51:55 +01:00
|
|
|
{
|
|
|
|
|
dev->ed_trigger = 0;
|
|
|
|
|
dev->ed_silent = 0;
|
|
|
|
|
|
2019-05-11 12:17:51 +02:00
|
|
|
if (dev->ed_monitor) {
|
2018-12-12 22:51:55 +01:00
|
|
|
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
|
|
|
|
|
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 18:37:42 +01:00
|
|
|
mt76_set(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN);
|
2018-12-12 22:51:55 +01: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 18:37:42 +01:00
|
|
|
mt76_set(dev, MT_TXOP_HLDR_ET,
|
|
|
|
|
MT_TXOP_HLDR_TX40M_BLK_EN);
|
2018-12-12 22:51:55 +01: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 18:19:20 +01:00
|
|
|
dev->ed_monitor_learning = true;
|
2019-02-03 14:15:58 +01:00
|
|
|
|
|
|
|
|
/* clear previous CCA timer value */
|
|
|
|
|
mt76_rr(dev, MT_ED_CCA_TIMER);
|
2019-02-03 14:41:22 +01:00
|
|
|
dev->ed_time = ktime_get_boottime();
|
2018-12-12 22:51:55 +01:00
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(mt76x02_edcca_init);
|
|
|
|
|
|
2019-02-03 20:35:31 +01:00
|
|
|
#define MT_EDCCA_TH 92
|
2018-12-12 22:51:55 +01:00
|
|
|
#define MT_EDCCA_BLOCK_TH 2
|
2019-03-02 18:19:20 +01:00
|
|
|
#define MT_EDCCA_LEARN_TH 50
|
|
|
|
|
#define MT_EDCCA_LEARN_CCA 180
|
|
|
|
|
#define MT_EDCCA_LEARN_TIMEOUT (20 * HZ)
|
|
|
|
|
|
2018-12-12 22:51:55 +01:00
|
|
|
static void mt76x02_edcca_check(struct mt76x02_dev *dev)
|
|
|
|
|
{
|
2019-02-03 14:41:22 +01:00
|
|
|
ktime_t cur_time;
|
|
|
|
|
u32 active, val, busy;
|
2018-12-12 22:51:55 +01:00
|
|
|
|
2019-02-03 14:41:22 +01:00
|
|
|
cur_time = ktime_get_boottime();
|
2018-12-12 22:51:55 +01:00
|
|
|
val = mt76_rr(dev, MT_ED_CCA_TIMER);
|
2019-02-03 14:41:22 +01:00
|
|
|
|
|
|
|
|
active = ktime_to_us(ktime_sub(cur_time, dev->ed_time));
|
|
|
|
|
dev->ed_time = cur_time;
|
|
|
|
|
|
|
|
|
|
busy = (val * 100) / active;
|
2018-12-12 22:51:55 +01: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 18:19:20 +01: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 22:51:55 +01:00
|
|
|
mt76x02_edcca_tx_enable(dev, false);
|
2019-03-02 18:19:20 +01:00
|
|
|
else if (dev->ed_silent > MT_EDCCA_BLOCK_TH && dev->ed_tx_blocked)
|
2018-12-12 22:51:55 +01:00
|
|
|
mt76x02_edcca_tx_enable(dev, true);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 11:33:12 +02:00
|
|
|
void mt76x02_mac_work(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
|
2019-03-18 11:21:44 +01:00
|
|
|
mt76.mac_work.work);
|
2018-10-15 11:33:12 +02:00
|
|
|
int i, idx;
|
|
|
|
|
|
2018-12-06 17:07:39 +01:00
|
|
|
mutex_lock(&dev->mt76.mutex);
|
|
|
|
|
|
2018-10-15 11:33:12 +02:00
|
|
|
mt76x02_update_channel(&dev->mt76);
|
|
|
|
|
for (i = 0, idx = 0; i < 16; i++) {
|
|
|
|
|
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
|
|
|
|
|
|
2019-09-13 09:05:52 +02:00
|
|
|
dev->mt76.aggr_stats[idx++] += val & 0xffff;
|
|
|
|
|
dev->mt76.aggr_stats[idx++] += val >> 16;
|
2018-10-15 11:33:12 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-29 10:13:00 +02:00
|
|
|
if (!dev->mt76.beacon_mask)
|
2018-10-15 11:33:15 +02:00
|
|
|
mt76x02_check_mac_err(dev);
|
|
|
|
|
|
2018-12-12 22:51:55 +01:00
|
|
|
if (dev->ed_monitor)
|
|
|
|
|
mt76x02_edcca_check(dev);
|
|
|
|
|
|
2018-12-06 17:07:39 +01:00
|
|
|
mutex_unlock(&dev->mt76.mutex);
|
|
|
|
|
|
2018-11-05 21:11:39 +01:00
|
|
|
mt76_tx_status_check(&dev->mt76, NULL, false);
|
2018-10-25 16:11:34 +02:00
|
|
|
|
2019-03-18 11:21:44 +01:00
|
|
|
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
|
2019-02-03 14:13:06 +01:00
|
|
|
MT_MAC_WORK_INTERVAL);
|
2018-10-15 11:33:12 +02:00
|
|
|
}
|
2018-10-20 12:13:25 +02: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));
|
|
|
|
|
}
|