2021-01-28 03:33:38 +08:00
|
|
|
// SPDX-License-Identifier: ISC
|
|
|
|
/* Copyright (C) 2020 MediaTek Inc. */
|
|
|
|
|
2021-01-28 03:33:56 +08:00
|
|
|
#include <linux/devcoredump.h>
|
2021-01-28 03:33:38 +08:00
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/timekeeping.h>
|
|
|
|
#include "mt7921.h"
|
|
|
|
#include "../dma.h"
|
|
|
|
#include "mac.h"
|
2021-01-28 03:33:56 +08:00
|
|
|
#include "mcu.h"
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev,
|
|
|
|
u16 idx, bool unicast)
|
|
|
|
{
|
|
|
|
struct mt7921_sta *sta;
|
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
|
|
|
|
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
|
|
|
if (unicast || !wcid)
|
|
|
|
return wcid;
|
|
|
|
|
|
|
|
if (!wcid->sta)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sta = container_of(wcid, struct mt7921_sta, wcid);
|
|
|
|
if (!sta->vif)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return &sta->vif->sta.wcid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
|
|
|
|
{
|
|
|
|
}
|
2021-10-19 07:11:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mt7921_sta_ps);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
|
|
|
|
{
|
|
|
|
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
|
|
|
|
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
|
|
|
|
|
|
|
|
return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
|
|
|
|
0, 5000);
|
|
|
|
}
|
|
|
|
|
2021-10-19 07:11:31 +08:00
|
|
|
void mt7921_mac_sta_poll(struct mt7921_dev *dev)
|
2021-01-28 03:33:38 +08:00
|
|
|
{
|
|
|
|
static const u8 ac_to_tid[] = {
|
|
|
|
[IEEE80211_AC_BE] = 0,
|
|
|
|
[IEEE80211_AC_BK] = 1,
|
|
|
|
[IEEE80211_AC_VI] = 4,
|
|
|
|
[IEEE80211_AC_VO] = 6
|
|
|
|
};
|
|
|
|
struct ieee80211_sta *sta;
|
|
|
|
struct mt7921_sta *msta;
|
|
|
|
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
|
|
|
|
LIST_HEAD(sta_poll_list);
|
2021-09-04 18:16:45 +08:00
|
|
|
struct rate_info *rate;
|
2021-01-28 03:33:38 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
list_splice_init(&dev->sta_poll_list, &sta_poll_list);
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
bool clear = false;
|
2021-09-04 18:16:45 +08:00
|
|
|
u32 addr, val;
|
2021-01-28 03:33:38 +08:00
|
|
|
u16 idx;
|
2021-09-04 18:16:45 +08:00
|
|
|
u8 bw;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
if (list_empty(&sta_poll_list)) {
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
msta = list_first_entry(&sta_poll_list,
|
|
|
|
struct mt7921_sta, poll_list);
|
|
|
|
list_del_init(&msta->poll_list);
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
|
|
|
idx = msta->wcid.idx;
|
2021-09-04 18:16:45 +08:00
|
|
|
addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
|
|
|
u32 tx_last = msta->airtime_ac[i];
|
|
|
|
u32 rx_last = msta->airtime_ac[i + 4];
|
|
|
|
|
|
|
|
msta->airtime_ac[i] = mt76_rr(dev, addr);
|
|
|
|
msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
|
|
|
|
|
|
|
|
tx_time[i] = msta->airtime_ac[i] - tx_last;
|
|
|
|
rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
|
|
|
|
|
|
|
|
if ((tx_last | rx_last) & BIT(30))
|
|
|
|
clear = true;
|
|
|
|
|
|
|
|
addr += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clear) {
|
|
|
|
mt7921_mac_wtbl_update(dev, idx,
|
|
|
|
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
|
|
|
memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!msta->wcid.sta)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
sta = container_of((void *)msta, struct ieee80211_sta,
|
|
|
|
drv_priv);
|
|
|
|
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
2022-01-16 20:43:14 +08:00
|
|
|
u8 q = mt76_connac_lmac_mapping(i);
|
2021-01-28 03:33:38 +08:00
|
|
|
u32 tx_cur = tx_time[q];
|
|
|
|
u32 rx_cur = rx_time[q];
|
|
|
|
u8 tid = ac_to_tid[i];
|
|
|
|
|
|
|
|
if (!tx_cur && !rx_cur)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ieee80211_sta_register_airtime(sta, tid, tx_cur,
|
|
|
|
rx_cur);
|
|
|
|
}
|
2021-09-04 18:16:45 +08:00
|
|
|
|
|
|
|
/* We don't support reading GI info from txs packets.
|
|
|
|
* For accurate tx status reporting and AQL improvement,
|
|
|
|
* we need to make sure that flags match so polling GI
|
|
|
|
* from per-sta counters directly.
|
|
|
|
*/
|
|
|
|
rate = &msta->wcid.rate;
|
|
|
|
addr = mt7921_mac_wtbl_lmac_addr(idx,
|
|
|
|
MT_WTBL_TXRX_CAP_RATE_OFFSET);
|
|
|
|
val = mt76_rr(dev, addr);
|
|
|
|
|
|
|
|
switch (rate->bw) {
|
|
|
|
case RATE_INFO_BW_160:
|
|
|
|
bw = IEEE80211_STA_RX_BW_160;
|
|
|
|
break;
|
|
|
|
case RATE_INFO_BW_80:
|
|
|
|
bw = IEEE80211_STA_RX_BW_80;
|
|
|
|
break;
|
|
|
|
case RATE_INFO_BW_40:
|
|
|
|
bw = IEEE80211_STA_RX_BW_40;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bw = IEEE80211_STA_RX_BW_20;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
|
|
|
|
u8 offs = MT_WTBL_TXRX_RATE_G2_HE + 2 * bw;
|
|
|
|
|
|
|
|
rate->he_gi = (val & (0x3 << offs)) >> offs;
|
|
|
|
} else if (rate->flags &
|
|
|
|
(RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
|
|
|
|
if (val & BIT(MT_WTBL_TXRX_RATE_G2 + bw))
|
|
|
|
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
|
|
|
else
|
|
|
|
rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
|
|
|
|
}
|
2021-01-28 03:33:38 +08:00
|
|
|
}
|
|
|
|
}
|
2021-10-19 07:11:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy,
|
|
|
|
struct mt76_rx_status *status, u8 chfreq)
|
|
|
|
{
|
|
|
|
if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
|
|
|
|
!test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) &&
|
|
|
|
!test_bit(MT76_STATE_ROC, &mphy->state)) {
|
|
|
|
status->freq = mphy->chandef.chan->center_freq;
|
|
|
|
status->band = mphy->chandef.chan->band;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-08-24 18:22:27 +08:00
|
|
|
if (chfreq > 180) {
|
|
|
|
status->band = NL80211_BAND_6GHZ;
|
|
|
|
chfreq = (chfreq - 181) * 4 + 1;
|
|
|
|
} else if (chfreq > 14) {
|
|
|
|
status->band = NL80211_BAND_5GHZ;
|
|
|
|
} else {
|
|
|
|
status->band = NL80211_BAND_2GHZ;
|
|
|
|
}
|
2021-01-28 03:33:38 +08:00
|
|
|
status->freq = ieee80211_channel_to_frequency(chfreq, status->band);
|
|
|
|
}
|
|
|
|
|
2021-03-24 16:37:37 +08:00
|
|
|
static void
|
|
|
|
mt7921_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb = priv;
|
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
|
|
|
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
|
|
|
|
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
|
|
|
|
|
|
|
|
if (status->signal > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!ether_addr_equal(vif->addr, hdr->addr1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
ewma_rssi_add(&mvif->rssi, -status->signal);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
|
|
|
|
|
|
|
|
if (!ieee80211_is_assoc_resp(hdr->frame_control) &&
|
|
|
|
!ieee80211_is_auth(hdr->frame_control))
|
|
|
|
return;
|
|
|
|
|
|
|
|
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
|
|
|
|
IEEE80211_IFACE_ITER_RESUME_ALL,
|
|
|
|
mt7921_mac_rssi_iter, skb);
|
|
|
|
}
|
|
|
|
|
2021-08-16 21:11:24 +08:00
|
|
|
static int
|
|
|
|
mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
|
2021-01-28 03:33:38 +08:00
|
|
|
{
|
2021-05-07 02:13:35 +08:00
|
|
|
u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
|
2021-01-28 03:33:38 +08:00
|
|
|
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
2021-05-07 02:13:34 +08:00
|
|
|
bool hdr_trans, unicast, insert_ccmp_hdr = false;
|
|
|
|
u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info;
|
2021-11-10 12:19:31 +08:00
|
|
|
u16 hdr_gap;
|
2021-05-07 02:13:35 +08:00
|
|
|
__le32 *rxv = NULL, *rxd = (__le32 *)skb->data;
|
2021-01-28 03:33:38 +08:00
|
|
|
struct mt76_phy *mphy = &dev->mt76.phy;
|
|
|
|
struct mt7921_phy *phy = &dev->phy;
|
|
|
|
struct ieee80211_supported_band *sband;
|
2021-05-07 02:13:35 +08:00
|
|
|
u32 rxd0 = le32_to_cpu(rxd[0]);
|
2021-01-28 03:33:38 +08:00
|
|
|
u32 rxd1 = le32_to_cpu(rxd[1]);
|
|
|
|
u32 rxd2 = le32_to_cpu(rxd[2]);
|
|
|
|
u32 rxd3 = le32_to_cpu(rxd[3]);
|
2021-05-07 02:13:32 +08:00
|
|
|
u32 rxd4 = le32_to_cpu(rxd[4]);
|
2022-06-09 01:30:30 +08:00
|
|
|
struct mt7921_sta *msta;
|
2021-05-07 02:13:34 +08:00
|
|
|
u16 seq_ctrl = 0;
|
|
|
|
__le16 fc = 0;
|
2022-06-09 01:30:31 +08:00
|
|
|
u8 mode = 0;
|
2021-01-28 03:33:38 +08:00
|
|
|
int i, idx;
|
|
|
|
|
|
|
|
memset(status, 0, sizeof(*status));
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_BAND_IDX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-05-07 02:13:32 +08:00
|
|
|
if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-11-19 14:37:06 +08:00
|
|
|
hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
|
|
|
|
if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* ICV error or CCMP/BIP/WPI MIC error */
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
|
|
|
|
status->flag |= RX_FLAG_ONLY_MONITOR;
|
|
|
|
|
2021-01-28 03:33:38 +08:00
|
|
|
chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
|
|
|
|
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
|
|
|
|
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
|
|
|
|
status->wcid = mt7921_rx_get_wcid(dev, idx, unicast);
|
|
|
|
|
|
|
|
if (status->wcid) {
|
|
|
|
msta = container_of(status->wcid, struct mt7921_sta, wcid);
|
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
if (list_empty(&msta->poll_list))
|
|
|
|
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
mt7921_get_status_freq_info(dev, mphy, status, chfreq);
|
|
|
|
|
2021-08-24 18:22:27 +08:00
|
|
|
switch (status->band) {
|
|
|
|
case NL80211_BAND_5GHZ:
|
2021-01-28 03:33:38 +08:00
|
|
|
sband = &mphy->sband_5g.sband;
|
2021-08-24 18:22:27 +08:00
|
|
|
break;
|
|
|
|
case NL80211_BAND_6GHZ:
|
|
|
|
sband = &mphy->sband_6g.sband;
|
|
|
|
break;
|
|
|
|
default:
|
2021-01-28 03:33:38 +08:00
|
|
|
sband = &mphy->sband_2g.sband;
|
2021-08-24 18:22:27 +08:00
|
|
|
break;
|
|
|
|
}
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
if (!sband->channels)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-05-07 02:13:35 +08:00
|
|
|
if ((rxd0 & csum_mask) == csum_mask)
|
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
|
2021-01-28 03:33:38 +08:00
|
|
|
if (rxd1 & MT_RXD1_NORMAL_FCS_ERR)
|
|
|
|
status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
|
|
|
|
status->flag |= RX_FLAG_MMIC_ERROR;
|
|
|
|
|
|
|
|
if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 &&
|
|
|
|
!(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
|
|
|
|
status->flag |= RX_FLAG_DECRYPTED;
|
|
|
|
status->flag |= RX_FLAG_IV_STRIPPED;
|
|
|
|
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
|
|
|
|
|
|
|
|
if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rxd += 6;
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
|
2021-05-07 02:13:34 +08:00
|
|
|
u32 v0 = le32_to_cpu(rxd[0]);
|
|
|
|
u32 v2 = le32_to_cpu(rxd[2]);
|
|
|
|
|
|
|
|
fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0));
|
|
|
|
seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2);
|
|
|
|
qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2);
|
|
|
|
|
2021-01-28 03:33:38 +08:00
|
|
|
rxd += 4;
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
|
|
|
|
u8 *data = (u8 *)rxd;
|
|
|
|
|
|
|
|
if (status->flag & RX_FLAG_DECRYPTED) {
|
2021-06-17 15:17:49 +08:00
|
|
|
switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) {
|
|
|
|
case MT_CIPHER_AES_CCMP:
|
|
|
|
case MT_CIPHER_CCMP_CCX:
|
|
|
|
case MT_CIPHER_CCMP_256:
|
|
|
|
insert_ccmp_hdr =
|
|
|
|
FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
|
|
|
|
fallthrough;
|
|
|
|
case MT_CIPHER_TKIP:
|
|
|
|
case MT_CIPHER_TKIP_NO_MIC:
|
|
|
|
case MT_CIPHER_GCMP:
|
|
|
|
case MT_CIPHER_GCMP_256:
|
|
|
|
status->iv[0] = data[5];
|
|
|
|
status->iv[1] = data[4];
|
|
|
|
status->iv[2] = data[3];
|
|
|
|
status->iv[3] = data[2];
|
|
|
|
status->iv[4] = data[1];
|
|
|
|
status->iv[5] = data[0];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-01-28 03:33:38 +08:00
|
|
|
}
|
|
|
|
rxd += 4;
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
|
2021-03-30 01:25:00 +08:00
|
|
|
status->timestamp = le32_to_cpu(rxd[0]);
|
|
|
|
status->flag |= RX_FLAG_MACTIME_START;
|
|
|
|
|
|
|
|
if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
|
|
|
|
status->flag |= RX_FLAG_AMPDU_DETAILS;
|
|
|
|
|
|
|
|
/* all subframes of an A-MPDU have the same timestamp */
|
|
|
|
if (phy->rx_ampdu_ts != status->timestamp) {
|
|
|
|
if (!++phy->ampdu_ref)
|
|
|
|
phy->ampdu_ref++;
|
|
|
|
}
|
|
|
|
phy->rx_ampdu_ts = status->timestamp;
|
|
|
|
|
|
|
|
status->ampdu_ref = phy->ampdu_ref;
|
|
|
|
}
|
|
|
|
|
2021-01-28 03:33:38 +08:00
|
|
|
rxd += 2;
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RXD Group 3 - P-RXV */
|
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
|
2021-02-20 01:28:48 +08:00
|
|
|
u32 v0, v1;
|
2022-06-09 01:30:31 +08:00
|
|
|
int ret;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
rxv = rxd;
|
|
|
|
rxd += 2;
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
v0 = le32_to_cpu(rxv[0]);
|
|
|
|
v1 = le32_to_cpu(rxv[1]);
|
|
|
|
|
|
|
|
if (v0 & MT_PRXV_HT_AD_CODE)
|
|
|
|
status->enc_flags |= RX_ENC_FLAG_LDPC;
|
|
|
|
|
|
|
|
status->chains = mphy->antenna_mask;
|
|
|
|
status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1);
|
|
|
|
status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1);
|
|
|
|
status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1);
|
|
|
|
status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1);
|
2021-05-10 23:14:55 +08:00
|
|
|
status->signal = -128;
|
|
|
|
for (i = 0; i < hweight8(mphy->antenna_mask); i++) {
|
|
|
|
if (!(status->chains & BIT(i)) ||
|
|
|
|
status->chain_signal[i] >= 0)
|
2021-01-28 03:33:38 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
status->signal = max(status->signal,
|
|
|
|
status->chain_signal[i]);
|
|
|
|
}
|
|
|
|
|
2022-06-09 01:30:31 +08:00
|
|
|
ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status, sband,
|
|
|
|
rxv, &mode);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-02-20 01:28:48 +08:00
|
|
|
if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
|
|
|
|
rxd += 18;
|
|
|
|
if ((u8 *)rxd - skb->data >= skb->len)
|
|
|
|
return -EINVAL;
|
2021-01-28 03:33:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-07 02:13:32 +08:00
|
|
|
amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
|
|
|
|
status->amsdu = !!amsdu_info;
|
|
|
|
if (status->amsdu) {
|
|
|
|
status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
|
|
|
|
status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
|
2021-11-10 12:19:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
|
|
|
|
if (hdr_trans && ieee80211_has_morefrags(fc)) {
|
2022-06-09 01:30:30 +08:00
|
|
|
struct ieee80211_vif *vif;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!msta || !msta->vif)
|
2021-11-10 12:19:31 +08:00
|
|
|
return -EINVAL;
|
2022-06-09 01:30:30 +08:00
|
|
|
|
|
|
|
vif = container_of((void *)msta->vif, struct ieee80211_vif,
|
|
|
|
drv_priv);
|
|
|
|
err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2021-11-10 12:19:31 +08:00
|
|
|
hdr_trans = false;
|
|
|
|
} else {
|
|
|
|
skb_pull(skb, hdr_gap);
|
|
|
|
if (!hdr_trans && status->amsdu) {
|
2021-05-07 02:13:34 +08:00
|
|
|
memmove(skb->data + 2, skb->data,
|
|
|
|
ieee80211_get_hdrlen_from_skb(skb));
|
|
|
|
skb_pull(skb, 2);
|
|
|
|
}
|
2021-05-07 02:13:32 +08:00
|
|
|
}
|
|
|
|
|
2021-05-07 02:13:34 +08:00
|
|
|
if (!hdr_trans) {
|
2021-12-03 14:04:54 +08:00
|
|
|
struct ieee80211_hdr *hdr;
|
2021-11-15 01:58:58 +08:00
|
|
|
|
2021-05-07 02:13:34 +08:00
|
|
|
if (insert_ccmp_hdr) {
|
|
|
|
u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-05-07 02:13:34 +08:00
|
|
|
mt76_insert_ccmp_hdr(skb, key_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr = mt76_skb_get_hdr(skb);
|
|
|
|
fc = hdr->frame_control;
|
|
|
|
if (ieee80211_is_data_qos(fc)) {
|
|
|
|
seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
|
|
|
|
qos_ctl = *ieee80211_get_qos_ctl(hdr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status->flag |= RX_FLAG_8023;
|
2021-01-28 03:33:38 +08:00
|
|
|
}
|
|
|
|
|
2021-03-24 16:37:37 +08:00
|
|
|
mt7921_mac_assoc_rssi(dev, skb);
|
|
|
|
|
2021-11-15 01:58:58 +08:00
|
|
|
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
|
2022-06-09 01:30:29 +08:00
|
|
|
mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
|
2021-08-13 06:48:24 +08:00
|
|
|
|
2021-05-07 02:13:34 +08:00
|
|
|
if (!status->wcid || !ieee80211_is_data_qos(fc))
|
2021-01-28 03:33:38 +08:00
|
|
|
return 0;
|
|
|
|
|
2021-05-07 02:13:34 +08:00
|
|
|
status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);
|
|
|
|
status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
|
|
|
|
status->qos_ctl = qos_ctl;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-10-19 07:11:31 +08:00
|
|
|
void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
|
2021-01-28 03:33:38 +08:00
|
|
|
{
|
|
|
|
struct mt7921_sta *msta;
|
|
|
|
u16 fc, tid;
|
|
|
|
u32 val;
|
|
|
|
|
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 23:41:23 +08:00
|
|
|
if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
|
2021-01-28 03:33:38 +08:00
|
|
|
return;
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
tid = le32_get_bits(txwi[1], MT_TXD1_TID);
|
2021-01-28 03:33:38 +08:00
|
|
|
if (tid >= 6) /* skip VO queue */
|
|
|
|
return;
|
|
|
|
|
|
|
|
val = le32_to_cpu(txwi[2]);
|
|
|
|
fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
|
|
|
|
FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
|
|
|
|
if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
msta = (struct mt7921_sta *)sta->drv_priv;
|
|
|
|
if (!test_and_set_bit(tid, &msta->ampdu_state))
|
|
|
|
ieee80211_start_tx_ba_session(sta, tid, 0);
|
|
|
|
}
|
2021-10-19 07:11:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mt7921_tx_check_aggr);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-12-08 22:59:55 +08:00
|
|
|
void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
|
2021-09-04 18:16:44 +08:00
|
|
|
{
|
|
|
|
struct mt7921_sta *msta = NULL;
|
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
__le32 *txs_data = data;
|
|
|
|
u16 wcidx;
|
|
|
|
u8 pid;
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
|
2021-09-04 18:16:44 +08:00
|
|
|
return;
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
|
|
|
|
pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
|
2021-09-04 18:16:44 +08:00
|
|
|
|
|
|
|
if (pid < MT_PACKET_ID_FIRST)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (wcidx >= MT7921_WTBL_SIZE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
|
|
|
if (!wcid)
|
|
|
|
goto out;
|
|
|
|
|
2022-06-07 17:28:41 +08:00
|
|
|
msta = container_of(wcid, struct mt7921_sta, wcid);
|
2021-09-04 18:16:44 +08:00
|
|
|
|
2022-06-07 17:28:41 +08:00
|
|
|
mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data,
|
|
|
|
&msta->stats);
|
2021-09-04 18:16:44 +08:00
|
|
|
if (!wcid->sta)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
spin_lock_bh(&dev->sta_poll_lock);
|
|
|
|
if (list_empty(&msta->poll_list))
|
|
|
|
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
|
|
|
spin_unlock_bh(&dev->sta_poll_lock);
|
|
|
|
|
|
|
|
out:
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
2021-12-28 20:01:19 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mt7921_mac_add_txs);
|
2021-09-04 18:16:44 +08:00
|
|
|
|
2021-08-16 21:11:24 +08:00
|
|
|
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
|
|
|
|
__le32 *rxd = (__le32 *)skb->data;
|
2021-09-04 18:16:44 +08:00
|
|
|
__le32 *end = (__le32 *)&skb->data[skb->len];
|
2021-08-16 21:11:24 +08:00
|
|
|
enum rx_pkt_type type;
|
|
|
|
u16 flag;
|
|
|
|
|
2022-03-09 14:29:24 +08:00
|
|
|
type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
|
|
|
|
flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG);
|
2021-08-16 21:11:24 +08:00
|
|
|
|
|
|
|
if (type == PKT_TYPE_RX_EVENT && flag == 0x1)
|
|
|
|
type = PKT_TYPE_NORMAL_MCU;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case PKT_TYPE_RX_EVENT:
|
|
|
|
mt7921_mcu_rx_event(dev, skb);
|
|
|
|
break;
|
2021-09-04 18:16:44 +08:00
|
|
|
case PKT_TYPE_TXS:
|
|
|
|
for (rxd += 2; rxd + 8 <= end; rxd += 8)
|
|
|
|
mt7921_mac_add_txs(dev, rxd);
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
break;
|
2021-08-16 21:11:24 +08:00
|
|
|
case PKT_TYPE_NORMAL_MCU:
|
|
|
|
case PKT_TYPE_NORMAL:
|
|
|
|
if (!mt7921_mac_fill_rx(dev, skb)) {
|
|
|
|
mt76_rx(&dev->mt76, q, skb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fallthrough;
|
|
|
|
default:
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-10-19 07:11:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mt7921_queue_rx_skb);
|
2021-08-16 21:11:24 +08:00
|
|
|
|
2021-01-28 03:33:38 +08:00
|
|
|
void mt7921_mac_reset_counters(struct mt7921_phy *phy)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = phy->dev;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
mt76_rr(dev, MT_TX_AGG_CNT(0, i));
|
|
|
|
mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->mt76.phy.survey_time = ktime_get_boottime();
|
|
|
|
memset(&dev->mt76.aggr_stats[0], 0, sizeof(dev->mt76.aggr_stats) / 2);
|
|
|
|
|
|
|
|
/* reset airtime counters */
|
|
|
|
mt76_rr(dev, MT_MIB_SDR9(0));
|
|
|
|
mt76_rr(dev, MT_MIB_SDR36(0));
|
|
|
|
mt76_rr(dev, MT_MIB_SDR37(0));
|
|
|
|
|
|
|
|
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
|
|
|
|
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mt7921_mac_set_timing(struct mt7921_phy *phy)
|
|
|
|
{
|
|
|
|
s16 coverage_class = phy->coverage_class;
|
|
|
|
struct mt7921_dev *dev = phy->dev;
|
|
|
|
u32 val, reg_offset;
|
|
|
|
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
|
|
|
|
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
|
|
|
|
u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
|
|
|
|
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
|
2021-08-24 18:22:27 +08:00
|
|
|
bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
|
|
|
|
int sifs = is_2ghz ? 10 : 16, offset;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
|
|
|
|
return;
|
|
|
|
|
|
|
|
mt76_set(dev, MT_ARB_SCR(0),
|
|
|
|
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
|
|
|
|
udelay(1);
|
|
|
|
|
|
|
|
offset = 3 * coverage_class;
|
|
|
|
reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
|
|
|
|
FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
|
|
|
|
|
|
|
|
mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset);
|
|
|
|
mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset);
|
|
|
|
mt76_wr(dev, MT_TMAC_ICR0(0),
|
|
|
|
FIELD_PREP(MT_IFS_EIFS, 360) |
|
|
|
|
FIELD_PREP(MT_IFS_RIFS, 2) |
|
|
|
|
FIELD_PREP(MT_IFS_SIFS, sifs) |
|
|
|
|
FIELD_PREP(MT_IFS_SLOT, phy->slottime));
|
|
|
|
|
2021-08-24 18:22:27 +08:00
|
|
|
if (phy->slottime < 20 || !is_2ghz)
|
2021-01-28 03:33:38 +08:00
|
|
|
val = MT7921_CFEND_RATE_DEFAULT;
|
|
|
|
else
|
|
|
|
val = MT7921_CFEND_RATE_11B;
|
|
|
|
|
|
|
|
mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val);
|
|
|
|
mt76_clear(dev, MT_ARB_SCR(0),
|
|
|
|
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u8
|
|
|
|
mt7921_phy_get_nf(struct mt7921_phy *phy, int idx)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mt7921_phy_update_channel(struct mt76_phy *mphy, int idx)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76);
|
|
|
|
struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv;
|
|
|
|
struct mt76_channel_state *state;
|
|
|
|
u64 busy_time, tx_time, rx_time, obss_time;
|
|
|
|
int nf;
|
|
|
|
|
|
|
|
busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
|
|
|
|
MT_MIB_SDR9_BUSY_MASK);
|
|
|
|
tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
|
|
|
|
MT_MIB_SDR36_TXTIME_MASK);
|
|
|
|
rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
|
|
|
|
MT_MIB_SDR37_RXTIME_MASK);
|
|
|
|
obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
|
|
|
|
MT_MIB_OBSSTIME_MASK);
|
|
|
|
|
|
|
|
nf = mt7921_phy_get_nf(phy, idx);
|
|
|
|
if (!phy->noise)
|
|
|
|
phy->noise = nf << 4;
|
|
|
|
else if (nf)
|
|
|
|
phy->noise += nf - (phy->noise >> 4);
|
|
|
|
|
|
|
|
state = mphy->chan_state;
|
|
|
|
state->cc_busy += busy_time;
|
|
|
|
state->cc_tx += tx_time;
|
|
|
|
state->cc_rx += rx_time + obss_time;
|
|
|
|
state->cc_bss_rx += rx_time;
|
|
|
|
state->noise = -(phy->noise >> 4);
|
|
|
|
}
|
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
void mt7921_update_channel(struct mt76_phy *mphy)
|
2021-01-28 03:33:38 +08:00
|
|
|
{
|
2021-06-11 02:43:45 +08:00
|
|
|
struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
if (mt76_connac_pm_wake(mphy, &dev->pm))
|
2021-01-28 03:33:53 +08:00
|
|
|
return;
|
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
mt7921_phy_update_channel(mphy, 0);
|
2021-01-28 03:33:38 +08:00
|
|
|
/* reset obss airtime */
|
|
|
|
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
|
2021-01-28 03:33:53 +08:00
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
mt76_connac_power_save_sched(mphy, &dev->pm);
|
2021-01-28 03:33:38 +08:00
|
|
|
}
|
2021-10-19 07:11:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mt7921_update_channel);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-03-08 02:20:51 +08:00
|
|
|
static void
|
|
|
|
mt7921_vif_connect_iter(void *priv, u8 *mac,
|
|
|
|
struct ieee80211_vif *vif)
|
2021-01-28 03:33:38 +08:00
|
|
|
{
|
2021-03-08 02:20:51 +08:00
|
|
|
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
|
|
|
|
struct mt7921_dev *dev = mvif->phy->dev;
|
2022-04-07 02:29:14 +08:00
|
|
|
struct ieee80211_hw *hw = mt76_hw(dev);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-06-16 05:31:10 +08:00
|
|
|
if (vif->type == NL80211_IFTYPE_STATION)
|
|
|
|
ieee80211_disconnect(vif, true);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-03-08 02:20:51 +08:00
|
|
|
mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true);
|
|
|
|
mt7921_mcu_set_tx(dev, vif);
|
2022-04-07 02:29:14 +08:00
|
|
|
|
|
|
|
if (vif->type == NL80211_IFTYPE_AP) {
|
|
|
|
mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.wcid,
|
|
|
|
true);
|
|
|
|
mt7921_mcu_sta_update(dev, NULL, vif, true,
|
|
|
|
MT76_STA_INFO_STATE_NONE);
|
|
|
|
mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, true);
|
|
|
|
}
|
2021-03-08 02:20:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* system error recovery */
|
|
|
|
void mt7921_mac_reset_work(struct work_struct *work)
|
|
|
|
{
|
2021-05-20 11:46:37 +08:00
|
|
|
struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
|
|
|
|
reset_work);
|
|
|
|
struct ieee80211_hw *hw = mt76_hw(dev);
|
|
|
|
struct mt76_connac_pm *pm = &dev->pm;
|
2021-03-08 02:20:51 +08:00
|
|
|
int i;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2022-06-27 07:27:05 +08:00
|
|
|
dev_dbg(dev->mt76.dev, "chip reset\n");
|
2021-05-20 11:46:38 +08:00
|
|
|
dev->hw_full_reset = true;
|
2021-03-08 02:20:51 +08:00
|
|
|
ieee80211_stop_queues(hw);
|
|
|
|
|
|
|
|
cancel_delayed_work_sync(&dev->mphy.mac_work);
|
2021-05-20 11:46:37 +08:00
|
|
|
cancel_delayed_work_sync(&pm->ps_work);
|
|
|
|
cancel_work_sync(&pm->wake_work);
|
2021-03-08 02:20:51 +08:00
|
|
|
|
|
|
|
mutex_lock(&dev->mt76.mutex);
|
2021-10-19 07:11:33 +08:00
|
|
|
for (i = 0; i < 10; i++)
|
2021-10-19 07:11:31 +08:00
|
|
|
if (!mt7921_dev_reset(dev))
|
2021-03-08 02:20:51 +08:00
|
|
|
break;
|
|
|
|
mutex_unlock(&dev->mt76.mutex);
|
|
|
|
|
|
|
|
if (i == 10)
|
|
|
|
dev_err(dev->mt76.dev, "chip reset failed\n");
|
|
|
|
|
2021-04-16 23:30:36 +08:00
|
|
|
if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state)) {
|
|
|
|
struct cfg80211_scan_info info = {
|
|
|
|
.aborted = true,
|
|
|
|
};
|
|
|
|
|
|
|
|
ieee80211_scan_completed(dev->mphy.hw, &info);
|
|
|
|
}
|
|
|
|
|
2021-05-20 11:46:38 +08:00
|
|
|
dev->hw_full_reset = false;
|
2021-12-16 05:25:34 +08:00
|
|
|
pm->suspended = false;
|
2021-03-08 02:20:51 +08:00
|
|
|
ieee80211_wake_queues(hw);
|
|
|
|
ieee80211_iterate_active_interfaces(hw,
|
|
|
|
IEEE80211_IFACE_ITER_RESUME_ALL,
|
2021-04-17 18:27:06 +08:00
|
|
|
mt7921_vif_connect_iter, NULL);
|
2021-05-20 11:46:37 +08:00
|
|
|
mt76_connac_power_save_sched(&dev->mt76.phy, pm);
|
2021-03-08 02:20:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void mt7921_reset(struct mt76_dev *mdev)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
|
|
|
|
|
2021-06-18 18:30:47 +08:00
|
|
|
if (!dev->hw_init_done)
|
mt76: mt7921: do not schedule hw reset if the device is not running
Do not schedule hw full reset if the device is not fully initialized
(e.g if the channel has not been configured yet). This patch fixes
the kernel crash reported below
[ 44.440266] mt7921e 0000:01:00.0: chip reset failed
[ 44.527575] Unable to handle kernel paging request at virtual address ffffffc02f3e0000
[ 44.535771] Mem abort info:
[ 44.538646] ESR = 0x96000006
[ 44.541792] EC = 0x25: DABT (current EL), IL = 32 bits
[ 44.547268] SET = 0, FnV = 0
[ 44.550413] EA = 0, S1PTW = 0
[ 44.553648] Data abort info:
[ 44.556613] ISV = 0, ISS = 0x00000006
[ 44.560563] CM = 0, WnR = 0
[ 44.563619] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000000955000
[ 44.570530] [ffffffc02f3e0000] pgd=100000003ffff003, p4d=100000003ffff003, pud=100000003ffff003, pmd=0000000000000000
[ 44.581489] Internal error: Oops: 96000006 [#1] SMP
[ 44.606406] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 5.13.0-rc1-espressobin-12875-g6dc7f82ebc26 #33
[ 44.617264] Hardware name: Globalscale Marvell ESPRESSOBin Board (DT)
[ 44.623905] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO BTYPE=--)
[ 44.630100] pc : __queue_work+0x1f0/0x500
[ 44.634249] lr : __queue_work+0x1e8/0x500
[ 44.638384] sp : ffffffc010003d70
[ 44.641798] x29: ffffffc010003d70 x28: 0000000000000000 x27: ffffff8003989200
[ 44.649166] x26: ffffffc010c08510 x25: 0000000000000002 x24: ffffffc010ad90b0
[ 44.656533] x23: ffffffc010c08508 x22: 0000000000000012 x21: 0000000000000000
[ 44.663899] x20: ffffff8006385238 x19: ffffffc02f3e0000 x18: 00000000000003c9
[ 44.671266] x17: 0000000000000000 x16: 0000000000000000 x15: 000009b1a8a3bf90
[ 44.678632] x14: 0098968000000000 x13: 0000000000000000 x12: 0000000000000325
[ 44.685998] x11: ffffff803fda1928 x10: 0000000000000001 x9 : ffffffc010003e98
[ 44.693365] x8 : 0000000000000032 x7 : fff8000000000000 x6 : 0000000000000035
[ 44.700732] x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffffffc010adf700
[ 44.708098] x2 : ffffff8006385238 x1 : 000000007fffffff x0 : 0000000000000000
[ 44.715465] Call trace:
[ 44.717982] __queue_work+0x1f0/0x500
[ 44.721760] delayed_work_timer_fn+0x18/0x20
[ 44.726167] call_timer_fn+0x2c/0x178
[ 44.729947] run_timer_softirq+0x488/0x5c8
[ 44.734172] _stext+0x11c/0x378
[ 44.737411] irq_exit+0x100/0x108
[ 44.740830] __handle_domain_irq+0x60/0xb0
[ 44.745059] gic_handle_irq+0x70/0x2b4
[ 44.748929] el1_irq+0xb8/0x13c
[ 44.752167] arch_cpu_idle+0x14/0x30
[ 44.755858] default_idle_call+0x38/0x168
[ 44.759994] do_idle+0x1fc/0x210
[ 44.763325] cpu_startup_entry+0x20/0x58
[ 44.767372] rest_init+0xb8/0xc8
[ 44.770703] arch_call_rest_init+0xc/0x14
[ 44.774841] start_kernel+0x408/0x424
[ 44.778623] Code: aa1403e0 97fff54f aa0003f5 b5fff500 (f9400275)
[ 44.784907] ---[ end trace be73c3142d8c36a9 ]---
[ 44.789668] Kernel panic - not syncing: Oops: Fatal exception in interrupt
Fixes: 0c1ce9884607 ("mt76: mt7921: add wifi reset support")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2021-05-24 05:08:05 +08:00
|
|
|
return;
|
|
|
|
|
2021-06-18 18:30:47 +08:00
|
|
|
if (dev->hw_full_reset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
queue_work(dev->mt76.wq, &dev->reset_work);
|
2021-01-28 03:33:38 +08:00
|
|
|
}
|
|
|
|
|
2021-08-18 16:23:14 +08:00
|
|
|
void mt7921_mac_update_mib_stats(struct mt7921_phy *phy)
|
2021-01-28 03:33:38 +08:00
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = phy->dev;
|
|
|
|
struct mib_stats *mib = &phy->mib;
|
|
|
|
int i, aggr0 = 0, aggr1;
|
2021-10-19 18:12:28 +08:00
|
|
|
u32 val;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-02-23 02:17:49 +08:00
|
|
|
mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0),
|
|
|
|
MT_MIB_SDR3_FCS_ERR_MASK);
|
|
|
|
mib->ack_fail_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR3(0),
|
|
|
|
MT_MIB_ACK_FAIL_COUNT_MASK);
|
|
|
|
mib->ba_miss_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR2(0),
|
|
|
|
MT_MIB_BA_FAIL_COUNT_MASK);
|
|
|
|
mib->rts_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR0(0),
|
|
|
|
MT_MIB_RTS_COUNT_MASK);
|
|
|
|
mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0),
|
|
|
|
MT_MIB_RTS_FAIL_COUNT_MASK);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-10-19 18:12:28 +08:00
|
|
|
mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0));
|
|
|
|
mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0));
|
|
|
|
mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0));
|
|
|
|
|
|
|
|
val = mt76_rr(dev, MT_MIB_SDR32(0));
|
|
|
|
mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val);
|
|
|
|
mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val);
|
|
|
|
|
|
|
|
val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0));
|
|
|
|
mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val);
|
|
|
|
mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val);
|
|
|
|
|
|
|
|
val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0));
|
|
|
|
mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val);
|
|
|
|
mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val);
|
|
|
|
mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val);
|
|
|
|
mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val);
|
|
|
|
|
|
|
|
mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0));
|
|
|
|
mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0));
|
|
|
|
mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0));
|
|
|
|
mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0));
|
|
|
|
|
2021-10-19 18:12:31 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
|
|
|
|
val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
|
|
|
|
mib->tx_amsdu[i] += val;
|
|
|
|
mib->tx_amsdu_cnt += val;
|
|
|
|
}
|
|
|
|
|
2021-01-28 03:33:38 +08:00
|
|
|
for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) {
|
2021-10-19 18:12:28 +08:00
|
|
|
u32 val2;
|
2021-01-28 03:33:38 +08:00
|
|
|
|
|
|
|
val = mt76_rr(dev, MT_TX_AGG_CNT(0, i));
|
|
|
|
val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
|
|
|
|
|
|
|
|
dev->mt76.aggr_stats[aggr0++] += val & 0xffff;
|
|
|
|
dev->mt76.aggr_stats[aggr0++] += val >> 16;
|
|
|
|
dev->mt76.aggr_stats[aggr1++] += val2 & 0xffff;
|
|
|
|
dev->mt76.aggr_stats[aggr1++] += val2 >> 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mt7921_mac_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mt7921_phy *phy;
|
|
|
|
struct mt76_phy *mphy;
|
|
|
|
|
|
|
|
mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
|
|
|
|
mac_work.work);
|
|
|
|
phy = mphy->priv;
|
|
|
|
|
2021-01-28 03:33:53 +08:00
|
|
|
mt7921_mutex_acquire(phy->dev);
|
2021-01-28 03:33:38 +08:00
|
|
|
|
2021-06-11 02:43:45 +08:00
|
|
|
mt76_update_survey(mphy);
|
2021-04-21 18:43:48 +08:00
|
|
|
if (++mphy->mac_work_count == 2) {
|
2021-01-28 03:33:38 +08:00
|
|
|
mphy->mac_work_count = 0;
|
|
|
|
|
|
|
|
mt7921_mac_update_mib_stats(phy);
|
|
|
|
}
|
|
|
|
|
2021-01-28 03:33:53 +08:00
|
|
|
mt7921_mutex_release(phy->dev);
|
2021-09-04 18:16:44 +08:00
|
|
|
|
2021-09-13 17:25:03 +08:00
|
|
|
mt76_tx_status_check(mphy->dev, false);
|
2021-01-28 03:33:53 +08:00
|
|
|
ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
|
2021-01-28 03:33:38 +08:00
|
|
|
MT7921_WATCHDOG_TIME);
|
|
|
|
}
|
2021-01-28 03:33:53 +08:00
|
|
|
|
|
|
|
void mt7921_pm_wake_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev;
|
|
|
|
struct mt76_phy *mphy;
|
|
|
|
|
|
|
|
dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
|
|
|
|
pm.wake_work);
|
|
|
|
mphy = dev->phy.mt76;
|
|
|
|
|
2021-04-19 00:45:33 +08:00
|
|
|
if (!mt7921_mcu_drv_pmctrl(dev)) {
|
2021-10-19 07:11:46 +08:00
|
|
|
struct mt76_dev *mdev = &dev->mt76;
|
2021-04-19 00:45:33 +08:00
|
|
|
int i;
|
|
|
|
|
2021-10-19 07:11:46 +08:00
|
|
|
if (mt76_is_sdio(mdev)) {
|
|
|
|
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
|
|
|
|
mt76_worker_schedule(&mdev->sdio.txrx_worker);
|
|
|
|
} else {
|
2022-06-03 15:35:00 +08:00
|
|
|
local_bh_disable();
|
2021-10-19 07:11:46 +08:00
|
|
|
mt76_for_each_q_rx(mdev, i)
|
|
|
|
napi_schedule(&mdev->napi[i]);
|
2022-06-03 15:35:00 +08:00
|
|
|
local_bh_enable();
|
2021-10-19 07:11:46 +08:00
|
|
|
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
|
2022-06-24 18:08:29 +08:00
|
|
|
mt76_connac_tx_cleanup(mdev);
|
2021-10-19 07:11:46 +08:00
|
|
|
}
|
2021-04-23 22:27:11 +08:00
|
|
|
if (test_bit(MT76_STATE_RUNNING, &mphy->state))
|
|
|
|
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
|
|
|
|
MT7921_WATCHDOG_TIME);
|
2021-04-19 00:45:33 +08:00
|
|
|
}
|
2021-01-28 03:33:53 +08:00
|
|
|
|
|
|
|
ieee80211_wake_queues(mphy->hw);
|
2021-04-19 00:45:42 +08:00
|
|
|
wake_up(&dev->pm.wait);
|
2021-01-28 03:33:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void mt7921_pm_power_save_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev;
|
|
|
|
unsigned long delta;
|
2021-05-28 01:05:33 +08:00
|
|
|
struct mt76_phy *mphy;
|
2021-01-28 03:33:53 +08:00
|
|
|
|
|
|
|
dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
|
|
|
|
pm.ps_work.work);
|
2021-05-28 01:05:33 +08:00
|
|
|
mphy = dev->phy.mt76;
|
2021-01-28 03:33:53 +08:00
|
|
|
|
|
|
|
delta = dev->pm.idle_timeout;
|
2021-05-28 01:05:33 +08:00
|
|
|
if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
|
2021-12-24 16:32:49 +08:00
|
|
|
test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) ||
|
|
|
|
dev->fw_assert)
|
2021-04-19 00:45:39 +08:00
|
|
|
goto out;
|
|
|
|
|
2021-12-31 04:47:05 +08:00
|
|
|
if (mutex_is_locked(&dev->mt76.mutex))
|
|
|
|
/* if mt76 mutex is held we should not put the device
|
|
|
|
* to sleep since we are currently accessing device
|
|
|
|
* register map. We need to wait for the next power_save
|
|
|
|
* trigger.
|
|
|
|
*/
|
|
|
|
goto out;
|
|
|
|
|
2021-01-28 03:33:53 +08:00
|
|
|
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
|
|
|
|
delta = dev->pm.last_activity + delta - jiffies;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2021-05-28 01:05:33 +08:00
|
|
|
if (!mt7921_mcu_fw_pmctrl(dev)) {
|
|
|
|
cancel_delayed_work_sync(&mphy->mac_work);
|
2021-01-28 03:33:53 +08:00
|
|
|
return;
|
2021-05-28 01:05:33 +08:00
|
|
|
}
|
2021-01-28 03:33:53 +08:00
|
|
|
out:
|
|
|
|
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
|
|
|
|
}
|
|
|
|
|
2021-01-28 03:33:56 +08:00
|
|
|
void mt7921_coredump_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev;
|
|
|
|
char *dump, *data;
|
|
|
|
|
|
|
|
dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
|
|
|
|
coredump.work.work);
|
|
|
|
|
|
|
|
if (time_is_after_jiffies(dev->coredump.last_activity +
|
|
|
|
4 * MT76_CONNAC_COREDUMP_TIMEOUT)) {
|
|
|
|
queue_delayed_work(dev->mt76.wq, &dev->coredump.work,
|
|
|
|
MT76_CONNAC_COREDUMP_TIMEOUT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dump = vzalloc(MT76_CONNAC_COREDUMP_SZ);
|
|
|
|
data = dump;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
spin_lock_bh(&dev->mt76.lock);
|
|
|
|
skb = __skb_dequeue(&dev->coredump.msg_list);
|
|
|
|
spin_unlock_bh(&dev->mt76.lock);
|
|
|
|
|
|
|
|
if (!skb)
|
|
|
|
break;
|
|
|
|
|
2022-06-20 20:59:17 +08:00
|
|
|
skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
|
2021-06-17 09:39:19 +08:00
|
|
|
if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {
|
2021-02-20 01:28:45 +08:00
|
|
|
dev_kfree_skb(skb);
|
|
|
|
continue;
|
|
|
|
}
|
2021-01-28 03:33:56 +08:00
|
|
|
|
|
|
|
memcpy(data, skb->data, skb->len);
|
|
|
|
data += skb->len;
|
|
|
|
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
}
|
2021-06-17 09:39:19 +08:00
|
|
|
|
|
|
|
if (dump)
|
|
|
|
dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
2021-03-08 02:20:51 +08:00
|
|
|
mt7921_reset(&dev->mt76);
|
2021-01-28 03:33:56 +08:00
|
|
|
}
|
2022-03-14 23:10:28 +08:00
|
|
|
|
|
|
|
/* usb_sdio */
|
|
|
|
static void
|
|
|
|
mt7921_usb_sdio_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid,
|
|
|
|
enum mt76_txq_id qid, struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *key, int pid,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
__le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE);
|
|
|
|
|
|
|
|
memset(txwi, 0, MT_SDIO_TXD_SIZE);
|
2022-07-02 21:56:23 +08:00
|
|
|
mt76_connac2_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, qid, 0);
|
2022-03-14 23:10:28 +08:00
|
|
|
skb_push(skb, MT_SDIO_TXD_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|
|
|
enum mt76_txq_id qid, struct mt76_wcid *wcid,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct mt76_tx_info *tx_info)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
|
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
|
|
|
|
struct ieee80211_key_conf *key = info->control.hw_key;
|
|
|
|
struct sk_buff *skb = tx_info->skb;
|
|
|
|
int err, pad, pktid, type;
|
|
|
|
|
|
|
|
if (unlikely(tx_info->skb->len <= ETH_HLEN))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!wcid)
|
|
|
|
wcid = &dev->mt76.global_wcid;
|
|
|
|
|
|
|
|
if (sta) {
|
|
|
|
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
|
|
|
|
|
|
|
|
if (time_after(jiffies, msta->last_txs + HZ / 4)) {
|
|
|
|
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
|
|
|
msta->last_txs = jiffies;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb);
|
|
|
|
mt7921_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb);
|
|
|
|
|
|
|
|
type = mt76_is_sdio(mdev) ? MT7921_SDIO_DATA : 0;
|
|
|
|
mt7921_skb_add_usb_sdio_hdr(dev, skb, type);
|
|
|
|
pad = round_up(skb->len, 4) - skb->len;
|
|
|
|
if (mt76_is_usb(mdev))
|
|
|
|
pad += 4;
|
|
|
|
|
|
|
|
err = mt76_skb_adjust_pad(skb, pad);
|
|
|
|
if (err)
|
|
|
|
/* Release pktid in case of error. */
|
|
|
|
idr_remove(&wcid->pktid, pktid);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_prepare_skb);
|
2022-03-14 23:10:29 +08:00
|
|
|
|
|
|
|
void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
|
|
|
struct mt76_queue_entry *e)
|
|
|
|
{
|
|
|
|
__le32 *txwi = (__le32 *)(e->skb->data + MT_SDIO_HDR_SIZE);
|
|
|
|
unsigned int headroom = MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;
|
|
|
|
struct ieee80211_sta *sta;
|
|
|
|
struct mt76_wcid *wcid;
|
|
|
|
u16 idx;
|
|
|
|
|
|
|
|
idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
|
|
|
|
wcid = rcu_dereference(mdev->wcid[idx]);
|
|
|
|
sta = wcid_to_sta(wcid);
|
|
|
|
|
|
|
|
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
|
|
|
mt7921_tx_check_aggr(sta, txwi);
|
|
|
|
|
|
|
|
skb_pull(e->skb, headroom);
|
|
|
|
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_complete_skb);
|
2022-03-14 23:10:30 +08:00
|
|
|
|
|
|
|
bool mt7921_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
|
|
|
|
|
|
|
|
mt7921_mutex_acquire(dev);
|
|
|
|
mt7921_mac_sta_poll(dev);
|
|
|
|
mt7921_mutex_release(dev);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_status_data);
|
2022-05-12 07:06:36 +08:00
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
|
void mt7921_set_ipv6_ns_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
|
|
|
|
ipv6_ns_work);
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
skb = skb_dequeue(&dev->ipv6_ns_list);
|
|
|
|
|
|
|
|
if (!skb)
|
|
|
|
break;
|
|
|
|
|
|
|
|
mt7921_mutex_acquire(dev);
|
|
|
|
ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
|
|
|
|
MCU_UNI_CMD(OFFLOAD), true);
|
|
|
|
mt7921_mutex_release(dev);
|
|
|
|
|
|
|
|
} while (!ret);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
skb_queue_purge(&dev->ipv6_ns_list);
|
|
|
|
}
|
|
|
|
#endif
|