Merge tag 'mt76-next-2026-03-23' of https://github.com/nbd168/wireless

Felix Fietkau says:
===================
mt76 patches for 7.1

- fixes
- mt7996/mt7925 MLO fixes/improvements
- mt7996 NPU support
- mt7996 external EEPROM support
===================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg
2026-03-24 17:12:38 +01:00
60 changed files with 3347 additions and 969 deletions

View File

@@ -88,6 +88,9 @@ void mt76_change_chanctx(struct ieee80211_hw *hw,
IEEE80211_CHANCTX_CHANGE_RADAR)))
return;
if (phy->roc_vif)
mt76_abort_roc(phy);
cancel_delayed_work_sync(&phy->mac_work);
mutex_lock(&dev->mutex);
@@ -155,8 +158,6 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
{
struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
struct mt76_vif_data *mvif = mlink->mvif;
int link_id = link_conf->link_id;
struct mt76_phy *phy = ctx->phy;
struct mt76_dev *dev = phy->dev;
@@ -173,15 +174,8 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
if (!mlink)
goto out;
if (mlink != (struct mt76_vif_link *)vif->drv_priv)
rcu_assign_pointer(mvif->link[link_id], NULL);
dev->drv->vif_link_remove(phy, vif, link_conf, mlink);
mlink->ctx = NULL;
if (mlink != (struct mt76_vif_link *)vif->drv_priv)
kfree_rcu(mlink, rcu_head);
out:
mutex_unlock(&dev->mutex);
}
@@ -254,6 +248,8 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
continue;
mlink->ctx = vifs->new_ctx;
if (mlink->beacon_mon_interval)
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
}
out:
@@ -324,9 +320,11 @@ void mt76_roc_complete(struct mt76_phy *phy)
if (mlink)
mlink->mvif->roc_phy = NULL;
if (phy->main_chandef.chan &&
!test_bit(MT76_MCU_RESET, &dev->phy.state))
mt76_set_channel(phy, &phy->main_chandef, false);
if (phy->chanctx && phy->main_chandef.chan && phy->offchannel &&
!test_bit(MT76_MCU_RESET, &dev->phy.state)) {
__mt76_set_channel(phy, &phy->main_chandef, false);
mt76_offchannel_notify(phy, false);
}
mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
phy->roc_vif = NULL;
phy->roc_link = NULL;
@@ -364,12 +362,15 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct mt76_phy *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
struct mt76_vif_link *mlink;
bool offchannel;
int ret = 0;
phy = dev->band_phys[chan->band];
if (!phy)
return -EINVAL;
cancel_delayed_work_sync(&phy->mac_work);
mutex_lock(&dev->mutex);
if (phy->roc_vif || dev->scan.phy == phy ||
@@ -387,8 +388,18 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mlink->mvif->roc_phy = phy;
phy->roc_vif = vif;
phy->roc_link = mlink;
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
mt76_set_channel(phy, &chandef, true);
offchannel = mt76_offchannel_chandef(phy, chan, &chandef);
if (offchannel)
mt76_offchannel_notify(phy, true);
ret = __mt76_set_channel(phy, &chandef, offchannel);
if (ret) {
mlink->mvif->roc_phy = NULL;
phy->roc_vif = NULL;
phy->roc_link = NULL;
mt76_put_vif_phy_link(phy, vif, mlink);
goto out;
}
ieee80211_ready_on_channel(hw);
ieee80211_queue_delayed_work(phy->hw, &phy->roc_work,
msecs_to_jiffies(duration));

View File

@@ -6,6 +6,7 @@
#include <linux/dma-mapping.h>
#include "mt76.h"
#include "dma.h"
#include "mt76_connac.h"
static struct mt76_txwi_cache *
mt76_alloc_txwi(struct mt76_dev *dev)
@@ -188,16 +189,18 @@ mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q)
static void
mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
{
Q_WRITE(q, desc_base, q->desc_dma);
if ((q->flags & MT_QFLAG_WED_RRO_EN) && !mt76_npu_device_active(dev))
if ((q->flags & MT_QFLAG_WED_RRO_EN) &&
(!is_mt7992(dev) || !mt76_npu_device_active(dev)))
Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc);
else
Q_WRITE(q, ring_size, q->ndesc);
if (mt76_queue_is_npu_tx(q)) {
writel(q->desc_dma, &q->regs->desc_base);
writel(q->ndesc, &q->regs->ring_size);
writel(q->desc_dma, &q->regs->desc_base);
}
Q_WRITE(q, desc_base, q->desc_dma);
q->head = Q_READ(q, dma_idx);
q->tail = q->head;
}
@@ -663,6 +666,8 @@ mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
if (!t)
goto free_skb;
t->phy_idx = phy->band_idx;
t->qid = qid;
txwi = mt76_get_txwi_ptr(dev, t);
skb->prev = skb->next = NULL;
@@ -874,7 +879,16 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
if (!mt76_queue_is_wed_rro(q))
if (mtk_wed_device_active(&dev->mmio.wed) &&
mt76_queue_is_wed_rro(q))
continue;
if (mt76_npu_device_active(dev) &&
mt76_queue_is_wed_rro(q))
continue;
if (!mt76_queue_is_wed_rro_rxdmad_c(q) &&
!mt76_queue_is_wed_rro_ind(q))
mt76_put_page_pool_buf(buf, false);
} while (1);
@@ -915,6 +929,13 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
mt76_queue_is_wed_rro(q))
return;
if (mt76_npu_device_active(dev) &&
mt76_queue_is_wed_rro(q))
return;
if (mt76_queue_is_npu_txfree(q))
return;
mt76_dma_sync_idx(dev, q);
if (mt76_queue_is_npu(q))
mt76_npu_fill_rx_queue(dev, q);
@@ -1168,10 +1189,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
if (mtk_wed_device_active(&dev->mmio.wed) &&
mt76_queue_is_wed_rro(q))
continue;
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);

View File

@@ -174,7 +174,9 @@ void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
static inline void
mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
dev->queue_ops->reset_q(dev, q, true);
bool reset_idx = q && !mt76_queue_is_npu_tx(q);
dev->queue_ops->reset_q(dev, q, reset_idx);
if (mtk_wed_device_active(&dev->mmio.wed))
mt76_wed_dma_setup(dev, q, true);
}

View File

@@ -9,6 +9,13 @@
#include <linux/nvmem-consumer.h>
#include <linux/etherdevice.h>
#include "mt76.h"
#include "mt76_connac.h"
enum mt76_sku_type {
MT76_SKU_RATE,
MT76_SKU_BACKOFF,
MT76_SKU_BACKOFF_BF_OFFSET,
};
static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
{
@@ -292,7 +299,6 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan)
}
EXPORT_SYMBOL_GPL(mt76_find_channel_node);
static s8
mt76_get_txs_delta(struct device_node *np, u8 nss)
{
@@ -306,9 +312,24 @@ mt76_get_txs_delta(struct device_node *np, u8 nss)
return be32_to_cpu(val[nss - 1]);
}
static inline u8 mt76_backoff_n_chains(struct mt76_dev *dev, u8 idx)
{
/* 0:1T1ss, 1:2T1ss, ..., 14:5T5ss */
static const u8 connac3_table[] = {
1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
static const u8 connac2_table[] = {
1, 2, 3, 4, 2, 3, 4, 3, 4, 4, 0, 0, 0, 0, 0};
if (idx >= ARRAY_SIZE(connac3_table))
return 0;
return is_mt799x(dev) ? connac3_table[idx] : connac2_table[idx];
}
static void
mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data,
s8 target_power, s8 nss_delta, s8 *max_power)
mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len,
const s8 *data, s8 target_power, s8 nss_delta,
s8 *max_power, int n_chains, enum mt76_sku_type type)
{
int i;
@@ -316,18 +337,51 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data,
return;
for (i = 0; i < pwr_len; i++) {
pwr[i] = min_t(s8, target_power, data[i] + nss_delta);
u8 backoff_chain_idx = i;
int backoff_n_chains;
s8 backoff_delta;
s8 delta;
switch (type) {
case MT76_SKU_RATE:
delta = 0;
backoff_delta = 0;
backoff_n_chains = 0;
break;
case MT76_SKU_BACKOFF_BF_OFFSET:
backoff_chain_idx += 1;
fallthrough;
case MT76_SKU_BACKOFF:
delta = mt76_tx_power_path_delta(n_chains);
backoff_n_chains = mt76_backoff_n_chains(dev, backoff_chain_idx);
backoff_delta = mt76_tx_power_path_delta(backoff_n_chains);
break;
default:
return;
}
pwr[i] = min_t(s8, target_power + delta - backoff_delta, data[i] + nss_delta);
/* used for padding, doesn't need to be considered */
if (data[i] >= S8_MAX - 1)
continue;
/* only consider backoff value for the configured chain number */
if (type != MT76_SKU_RATE && n_chains != backoff_n_chains)
continue;
*max_power = max(*max_power, pwr[i]);
}
}
static void
mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
const s8 *data, size_t len, s8 target_power,
s8 nss_delta)
mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len,
s8 pwr_num, const s8 *data, size_t len,
s8 target_power, s8 nss_delta, s8 *max_power,
int n_chains, enum mt76_sku_type type)
{
static const int connac2_backoff_ru_idx = 2;
int i, cur;
s8 max_power = -128;
if (!data)
return;
@@ -337,8 +391,26 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
if (len < pwr_len + 1)
break;
mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
target_power, nss_delta, &max_power);
/* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS
* corresponds to 10 stream combinations (1T1ss, 2T1ss, 3T1ss,
* 4T1ss, 2T2ss, 3T2ss, 4T2ss, 3T3ss, 4T3ss, 4T4ss).
*
* For beamforming tables:
* - In connac2, beamforming entries for BW20~BW160 and OFDM
* do not include 1T1ss.
* - In connac3, beamforming entries for BW20~BW160 and RU
* include 1T1ss, but OFDM beamforming does not include 1T1ss.
*
* Non-beamforming and RU entries for both connac2 and connac3
* include 1T1ss.
*/
if (!is_mt799x(dev) && type == MT76_SKU_BACKOFF &&
i > connac2_backoff_ru_idx)
type = MT76_SKU_BACKOFF_BF_OFFSET;
mt76_apply_array_limit(dev, pwr + pwr_len * i, pwr_len, data + 1,
target_power, nss_delta, max_power,
n_chains, type);
if (--cur > 0)
continue;
@@ -360,18 +432,11 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
struct device_node *np;
const s8 *val;
char name[16];
u32 mcs_rates = dev->drv->mcs_rates;
u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
char band;
size_t len;
s8 max_power = 0;
s8 max_power_backoff = -127;
s8 max_power = -127;
s8 txs_delta;
int n_chains = hweight16(phy->chainmask);
s8 target_power_combine = target_power + mt76_tx_power_path_delta(n_chains);
if (!mcs_rates)
mcs_rates = 10;
memset(dest, target_power, sizeof(*dest) - sizeof(dest->path));
memset(&dest->path, 0, sizeof(dest->path));
@@ -409,46 +474,45 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask));
val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
target_power, txs_delta, &max_power);
mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val,
target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE);
val = mt76_get_of_array_s8(np, "rates-ofdm",
&len, ARRAY_SIZE(dest->ofdm));
mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
target_power, txs_delta, &max_power);
val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm));
mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE);
val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1);
mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
ARRAY_SIZE(dest->mcs), val, len,
target_power, txs_delta);
val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1);
mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
ARRAY_SIZE(dest->mcs), val, len, target_power,
txs_delta, &max_power, n_chains, MT76_SKU_RATE);
val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1);
mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
ARRAY_SIZE(dest->ru), val, len,
target_power, txs_delta);
val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1);
mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]),
ARRAY_SIZE(dest->ru), val, len, target_power,
txs_delta, &max_power, n_chains, MT76_SKU_RATE);
max_power_backoff = max_power;
val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck));
mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
target_power_combine, txs_delta, &max_power_backoff);
mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm));
mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
target_power_combine, txs_delta, &max_power_backoff);
mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf));
mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
target_power_combine, txs_delta, &max_power_backoff);
mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
target_power, txs_delta, &max_power, n_chains,
MT76_SKU_BACKOFF_BF_OFFSET);
val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1);
mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
ARRAY_SIZE(dest->path.ru), val, len,
target_power_combine, txs_delta);
mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
ARRAY_SIZE(dest->path.ru), val, len, target_power,
txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1);
mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
ARRAY_SIZE(dest->path.ru_bf), val, len,
target_power_combine, txs_delta);
mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
ARRAY_SIZE(dest->path.ru_bf), val, len, target_power,
txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
return max_power;
}

View File

@@ -726,6 +726,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
INIT_LIST_HEAD(&dev->rxwi_cache);
dev->token_size = dev->drv->token_size;
INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work);
spin_lock_init(&dev->scan_lock);
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
skb_queue_head_init(&dev->rx_skb[i]);
@@ -970,6 +971,9 @@ bool mt76_has_tx_pending(struct mt76_phy *phy)
return true;
}
if (atomic_read(&phy->mgmt_tx_pending))
return true;
return false;
}
EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
@@ -1030,9 +1034,10 @@ int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
int timeout = HZ / 5;
int ret;
set_bit(MT76_RESET, &phy->state);
mt76_worker_disable(&dev->tx_worker);
mt76_txq_schedule_pending(phy);
set_bit(MT76_RESET, &phy->state);
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
mt76_update_survey(phy);
@@ -1716,6 +1721,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
idr_destroy(&wcid->pktid);
/* Remove from sta_poll_list to prevent list corruption after reset.
* Without this, mt76_reset_device() reinitializes sta_poll_list but
* leaves wcid->poll_list with stale pointers, causing list corruption
* when mt76_wcid_add_poll() checks list_empty().
*/
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&wcid->poll_list))
list_del_init(&wcid->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
spin_lock_bh(&phy->tx_lock);
if (!list_empty(&wcid->tx_list))
@@ -2121,3 +2136,214 @@ u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links)
return sel_links;
}
EXPORT_SYMBOL_GPL(mt76_select_links);
struct mt76_offchannel_cb_data {
struct mt76_phy *phy;
bool offchannel;
};
static void
mt76_offchannel_send_nullfunc(struct mt76_offchannel_cb_data *data,
struct ieee80211_vif *vif, int link_id)
{
struct mt76_phy *phy = data->phy;
struct ieee80211_tx_info *info;
struct ieee80211_sta *sta = NULL;
struct ieee80211_hdr *hdr;
struct mt76_wcid *wcid;
struct sk_buff *skb;
skb = ieee80211_nullfunc_get(phy->hw, vif, link_id, true);
if (!skb)
return;
hdr = (struct ieee80211_hdr *)skb->data;
if (data->offchannel)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb,
phy->main_chandef.chan->band,
&sta))
return;
if (sta)
wcid = (struct mt76_wcid *)sta->drv_priv;
else
wcid = ((struct mt76_vif_link *)vif->drv_priv)->wcid;
if (link_id >= 0) {
info = IEEE80211_SKB_CB(skb);
info->control.flags &= ~IEEE80211_TX_CTRL_MLO_LINK;
info->control.flags |=
u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK);
}
mt76_tx(phy, sta, wcid, skb);
}
static void
mt76_offchannel_notify_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)
{
struct mt76_offchannel_cb_data *data = _data;
struct mt76_vif_link *mlink;
struct mt76_vif_data *mvif;
int link_id;
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
return;
mlink = (struct mt76_vif_link *)vif->drv_priv;
mvif = mlink->mvif;
if (!ieee80211_vif_is_mld(vif)) {
if (mt76_vif_link_phy(mlink) == data->phy) {
if (!data->offchannel && mlink->beacon_mon_interval)
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
mt76_offchannel_send_nullfunc(data, vif, -1);
}
return;
}
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
if (link_id == mvif->deflink_id)
mlink = (struct mt76_vif_link *)vif->drv_priv;
else
mlink = rcu_dereference(mvif->link[link_id]);
if (!mlink)
continue;
if (mt76_vif_link_phy(mlink) != data->phy)
continue;
if (!data->offchannel && mlink->beacon_mon_interval)
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
mt76_offchannel_send_nullfunc(data, vif, link_id);
}
}
void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel)
{
struct mt76_offchannel_cb_data data = {
.phy = phy,
.offchannel = offchannel,
};
if (!phy->num_sta)
return;
local_bh_disable();
ieee80211_iterate_active_interfaces_atomic(phy->hw,
IEEE80211_IFACE_ITER_NORMAL,
mt76_offchannel_notify_iter, &data);
local_bh_enable();
}
EXPORT_SYMBOL_GPL(mt76_offchannel_notify);
struct mt76_rx_beacon_data {
struct mt76_phy *phy;
const u8 *bssid;
};
static void mt76_rx_beacon_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct mt76_rx_beacon_data *data = _data;
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
struct mt76_vif_data *mvif = mlink->mvif;
int link_id;
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
return;
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
struct ieee80211_bss_conf *link_conf;
if (link_id == mvif->deflink_id)
mlink = (struct mt76_vif_link *)vif->drv_priv;
else
mlink = rcu_dereference(mvif->link[link_id]);
if (!mlink || !mlink->beacon_mon_interval)
continue;
if (mt76_vif_link_phy(mlink) != data->phy)
continue;
link_conf = rcu_dereference(vif->link_conf[link_id]);
if (!link_conf)
continue;
if (!ether_addr_equal(link_conf->bssid, data->bssid) &&
(!link_conf->nontransmitted ||
!ether_addr_equal(link_conf->transmitter_bssid,
data->bssid)))
continue;
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
}
}
void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
struct mt76_rx_beacon_data data = {
.phy = phy,
.bssid = hdr->addr3,
};
mt76_scan_rx_beacon(phy->dev, phy->chandef.chan);
if (!phy->num_sta)
return;
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_ONLY_MONITOR))
return;
ieee80211_iterate_active_interfaces_atomic(phy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt76_rx_beacon_iter, &data);
}
EXPORT_SYMBOL_GPL(mt76_rx_beacon);
static void mt76_beacon_mon_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct mt76_phy *phy = data;
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
struct mt76_vif_data *mvif = mlink->mvif;
int link_id;
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
return;
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
if (link_id == mvif->deflink_id)
mlink = (struct mt76_vif_link *)vif->drv_priv;
else
mlink = rcu_dereference(mvif->link[link_id]);
if (!mlink || !mlink->beacon_mon_interval)
continue;
if (mt76_vif_link_phy(mlink) != phy)
continue;
if (time_after(jiffies,
READ_ONCE(mlink->beacon_mon_last) +
MT76_BEACON_MON_MAX_MISS * mlink->beacon_mon_interval))
ieee80211_beacon_loss(vif);
}
}
void mt76_beacon_mon_check(struct mt76_phy *phy)
{
if (phy->offchannel)
return;
ieee80211_iterate_active_interfaces_atomic(phy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt76_beacon_mon_iter, phy);
}
EXPORT_SYMBOL_GPL(mt76_beacon_mon_check);

View File

@@ -98,7 +98,7 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
/* orig skb might be needed for retry, mcu_skb_send_msg consumes it */
if (orig_skb)
skb_get(orig_skb);
ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, wait_resp ? &seq : NULL);
if (ret < 0)
goto out;

View File

@@ -55,6 +55,8 @@
FIELD_PREP(MT_QFLAG_WED_RING, _n))
#define MT_NPU_Q_TX(_n) __MT_NPU_Q(MT76_WED_Q_TX, _n)
#define MT_NPU_Q_RX(_n) __MT_NPU_Q(MT76_WED_Q_RX, _n)
#define MT_NPU_Q_TXFREE(_n) (FIELD_PREP(MT_QFLAG_WED_TYPE, MT76_WED_Q_TXFREE) | \
FIELD_PREP(MT_QFLAG_WED_RING, _n))
struct mt76_dev;
struct mt76_phy;
@@ -362,6 +364,7 @@ enum mt76_wcid_flags {
};
#define MT76_N_WCIDS 1088
#define MT76_BEACON_MON_MAX_MISS 7
/* stored in ieee80211_tx_info::hw_queue */
#define MT_TX_HW_QUEUE_PHY GENMASK(3, 2)
@@ -448,6 +451,7 @@ struct mt76_txwi_cache {
};
u8 qid;
u8 phy_idx;
};
struct mt76_rx_tid {
@@ -540,7 +544,6 @@ struct mt76_driver_ops {
u32 survey_flags;
u16 txwi_size;
u16 token_size;
u8 mcs_rates;
unsigned int link_data_size;
@@ -831,6 +834,8 @@ struct mt76_vif_link {
u8 mcast_rates_idx;
u8 beacon_rates_idx;
bool offchannel;
unsigned long beacon_mon_last;
u16 beacon_mon_interval;
struct ieee80211_chanctx_conf *ctx;
struct mt76_wcid *wcid;
struct mt76_vif_data *mvif;
@@ -859,6 +864,8 @@ struct mt76_phy {
struct list_head tx_list;
struct mt76_queue *q_tx[__MT_TXQ_MAX];
atomic_t mgmt_tx_pending;
struct cfg80211_chan_def chandef;
struct cfg80211_chan_def main_chandef;
bool offchannel;
@@ -1002,6 +1009,7 @@ struct mt76_dev {
u32 rxfilter;
struct delayed_work scan_work;
spinlock_t scan_lock;
struct {
struct cfg80211_scan_request *req;
struct ieee80211_channel *chan;
@@ -1009,6 +1017,8 @@ struct mt76_dev {
struct mt76_vif_link *mlink;
struct mt76_phy *phy;
int chan_idx;
bool beacon_wait;
bool beacon_received;
} scan;
#ifdef CONFIG_NL80211_TESTMODE
@@ -1518,6 +1528,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
void mt76_txq_schedule_all(struct mt76_phy *phy);
void mt76_txq_schedule_pending(struct mt76_phy *phy);
void mt76_tx_worker_run(struct mt76_dev *dev);
void mt76_tx_worker(struct mt76_worker *w);
void mt76_release_buffered_frames(struct ieee80211_hw *hw,
@@ -1596,6 +1607,9 @@ int mt76_get_rate(struct mt76_dev *dev,
int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req);
void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan);
void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb);
void mt76_beacon_mon_check(struct mt76_phy *phy);
void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac);
void mt76_sw_scan_complete(struct ieee80211_hw *hw,
@@ -1649,6 +1663,9 @@ void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index);
int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct net_device *dev, enum tc_setup_type type,
void *type_data);
int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
u32 direction, u32 i_count_addr,
u32 o_status_addr, u32 o_count_addr);
#else
static inline void mt76_npu_check_ppe(struct mt76_dev *dev,
struct sk_buff *skb, u32 info)
@@ -1707,6 +1724,13 @@ static inline int mt76_npu_net_setup_tc(struct ieee80211_hw *hw,
{
return -EOPNOTSUPP;
}
static inline int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
u32 direction, u32 i_count_addr,
u32 o_status_addr, u32 o_count_addr)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_MT76_NPU */
static inline bool mt76_npu_device_active(struct mt76_dev *dev)
@@ -1775,6 +1799,18 @@ void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_entry *e);
int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
bool offchannel);
static inline bool
mt76_offchannel_chandef(struct mt76_phy *phy, struct ieee80211_channel *chan,
struct cfg80211_chan_def *chandef)
{
cfg80211_chandef_create(chandef, chan, NL80211_CHAN_HT20);
if (phy->main_chandef.chan != chan)
return true;
*chandef = phy->main_chandef;
return false;
}
int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
bool offchannel);
void mt76_scan_work(struct work_struct *work);
@@ -1786,6 +1822,7 @@ struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
struct ieee80211_vif *vif);
void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
struct mt76_vif_link *mlink);
void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel);
/* usb */
static inline bool mt76u_urb_error(struct urb *urb)
@@ -1993,6 +2030,14 @@ static inline bool mt76_queue_is_npu_rx(struct mt76_queue *q)
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX;
}
static inline bool mt76_queue_is_npu_txfree(struct mt76_queue *q)
{
if (q->flags & MT_QFLAG_WED)
return false;
return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE;
}
struct mt76_txwi_cache *
mt76_token_release(struct mt76_dev *dev, int token, bool *wake);
int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi);

View File

@@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
}
EXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
void mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
struct ieee80211_vif *vif, bool enable)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
u32 addr;
addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4;
if (enable)
mt76_set(dev, addr, MT_WTBL_W3_RTS);
else
mt76_clear(dev, addr, MT_WTBL_W3_RTS);
}
EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts);
static int
mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,

View File

@@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
}
}
if (changed & BSS_CHANGED_ERP_CTS_PROT)
mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot);
if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
mt7615_mcu_add_bss_info(phy, vif, NULL, true);
mt7615_mcu_sta_add(phy, vif, NULL, true);
@@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
BSS_CHANGED_BEACON_ENABLED))
mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon);
if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode,
info->use_cts_prot);
if (changed & BSS_CHANGED_PS)
mt76_connac_mcu_set_vif_ps(&dev->mt76, vif);

View File

@@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
&req, sizeof(req), false);
}
int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif,
u8 ht_mode, bool use_cts_prot)
{
struct mt7615_dev *dev = phy->dev;
struct {
u8 prot_idx;
u8 band;
u8 rsv[2];
bool long_nav;
bool prot_mm;
bool prot_gf;
bool prot_bw40;
bool prot_rifs;
bool prot_bw80;
bool prot_bw160;
u8 prot_erp_mask;
} __packed req = {
.prot_idx = 0x2,
.band = phy != &dev->phy,
};
switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
req.prot_mm = true;
req.prot_gf = true;
fallthrough;
case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
req.prot_bw40 = true;
break;
}
if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
req.prot_gf = true;
if (use_cts_prot) {
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx;
req.prot_erp_mask = BIT(i);
}
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req,
sizeof(req), true);
}

View File

@@ -467,8 +467,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy);
void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy);
void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable);
void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy);
void mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
struct ieee80211_vif *vif, bool enable);
void mt7615_mac_sta_poll(struct mt7615_dev *dev);
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
@@ -523,7 +521,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable);
int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy);
int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy);
int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy);
int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif,
u8 ht_mode, bool use_cts_prot);
int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, int duration);

View File

@@ -455,8 +455,6 @@ enum mt7615_reg_base {
#define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8)
#define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20)
#define MT_WTBL_W3_RTS BIT(22)
#define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5)
#define MT_WTBL_W5_SHORT_GI_20 BIT(8)
#define MT_WTBL_W5_SHORT_GI_40 BIT(9)

View File

@@ -182,14 +182,20 @@ static inline bool is_mt7920(struct mt76_dev *dev)
return mt76_chip(dev) == 0x7920;
}
static inline bool is_mt7902(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7902;
}
static inline bool is_mt7922(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7922;
}
static inline bool is_mt7921(struct mt76_dev *dev)
static inline bool is_connac2(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev);
return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev) ||
is_mt7902(dev);
}
static inline bool is_mt7663(struct mt76_dev *dev)
@@ -271,6 +277,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
case 0x7961:
case 0x7920:
case 0x7922:
case 0x7902:
case 0x7925:
case 0x7663:
case 0x7622:

View File

@@ -173,7 +173,7 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev,
txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev))
if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev))
last_mask = MT_TXD_LEN_LAST;
else
last_mask = MT_TXD_LEN_AMSDU_LAST |
@@ -217,7 +217,7 @@ mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev,
u32 last_mask;
int i;
if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev))
if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev))
last_mask = MT_TXD_LEN_LAST;
else
last_mask = MT_TXD_LEN_MSDU_LAST;
@@ -309,7 +309,7 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef;
band = chandef->chan->band;
if (is_mt7921(mphy->dev)) {
if (is_connac2(mphy->dev)) {
rateidx = ffs(conf->basic_rates) - 1;
goto legacy;
}
@@ -548,7 +548,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
val = MT_TXD1_LONG_FORMAT |
FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
if (!is_mt7921(dev))
if (!is_connac2(dev))
val |= MT_TXD1_VTA;
if (phy_idx || band_idx)
val |= MT_TXD1_TGID;
@@ -557,7 +557,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
txwi[2] = 0;
val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15);
if (!is_mt7921(dev))
if (!is_connac2(dev))
val |= MT_TXD3_SW_POWER_MGMT;
if (key)
val |= MT_TXD3_PROTECT_FRAME;
@@ -599,7 +599,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
if (!is_mt7921(dev)) {
if (!is_connac2(dev)) {
u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
if (!spe_idx)
@@ -831,7 +831,7 @@ mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb
};
struct ieee80211_radiotap_he_mu *he_mu;
if (is_mt7921(dev)) {
if (is_connac2(dev)) {
mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN);
mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN);
}
@@ -1047,7 +1047,7 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
stbc = FIELD_GET(MT_PRXV_HT_STBC, v0);
gi = FIELD_GET(MT_PRXV_HT_SGI, v0);
*mode = FIELD_GET(MT_PRXV_TX_MODE, v0);
if (is_mt7921(dev))
if (is_connac2(dev))
dcm = !!(idx & MT_PRXV_TX_DCM);
else
dcm = FIELD_GET(MT_PRXV_DCM, v0);
@@ -1153,8 +1153,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
return;
wcid = (struct mt76_wcid *)sta->drv_priv;
if (!test_and_set_bit(tid, &wcid->ampdu_state))
ieee80211_start_tx_ba_session(sta, tid, 0);
if (!test_and_set_bit(tid, &wcid->ampdu_state)) {
if (ieee80211_start_tx_ba_session(sta, tid, 0))
clear_bit(tid, &wcid->ampdu_state);
}
}
EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);
@@ -1207,5 +1209,11 @@ void mt76_connac2_tx_token_put(struct mt76_dev *dev)
}
spin_unlock_bh(&dev->token_lock);
idr_destroy(&dev->token);
for (id = 0; id < __MT_MAX_BAND; id++) {
struct mt76_phy *phy = dev->phys[id];
if (phy)
atomic_set(&phy->mgmt_tx_pending, 0);
}
}
EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put);

View File

@@ -4,6 +4,7 @@
#include <linux/firmware.h>
#include "mt76_connac2_mac.h"
#include "mt76_connac_mcu.h"
#include "mt792x_regs.h"
int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option)
{
@@ -65,7 +66,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len,
int cmd;
if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) ||
(is_mt7921(dev) && addr == 0x900000) ||
(is_connac2(dev) && addr == 0x900000) ||
(is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) ||
(is_mt799x(dev) && addr == 0x900000))
cmd = MCU_CMD(PATCH_START_REQ);
@@ -402,7 +403,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
if (vif->p2p && !is_mt7921(dev))
if (vif->p2p && !is_connac2(dev))
conn_type = CONNECTION_P2P_GC;
else
conn_type = CONNECTION_INFRA_STA;
@@ -410,7 +411,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
basic->aid = cpu_to_le16(link_sta->sta->aid);
break;
case NL80211_IFTYPE_STATION:
if (vif->p2p && !is_mt7921(dev))
if (vif->p2p && !is_connac2(dev))
conn_type = CONNECTION_P2P_GO;
else
conn_type = CONNECTION_INFRA_AP;
@@ -874,7 +875,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
struct sta_rec_vht *vht;
int len;
len = is_mt7921(dev) ? sizeof(*vht) : sizeof(*vht) - 4;
len = is_connac2(dev) ? sizeof(*vht) : sizeof(*vht) - 4;
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len);
vht = (struct sta_rec_vht *)tlv;
vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
@@ -885,7 +886,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
/* starec uapsd */
mt76_connac_mcu_sta_uapsd(skb, vif, sta);
if (!is_mt7921(dev))
if (!is_connac2(dev))
return;
if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)
@@ -1295,8 +1296,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,
wtbl_hdr);
ret = mt76_connac_mcu_sta_wed_update(dev, skb);
if (ret)
if (ret) {
dev_kfree_skb(skb);
return ret;
}
ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true);
if (ret)
@@ -1309,8 +1312,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,
mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);
ret = mt76_connac_mcu_sta_wed_update(dev, skb);
if (ret)
if (ret) {
dev_kfree_skb(skb);
return ret;
}
return mt76_mcu_skb_send_msg(dev, skb, cmd, true);
}
@@ -1774,7 +1779,7 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
req->ssid_type_ext = n_ssids ? BIT(0) : 0;
req->ssids_num = n_ssids;
duration = is_mt7921(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME;
duration = is_connac2(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME;
/* increase channel time for passive scan */
if (!sreq->n_ssids)
duration *= 2;
@@ -1817,7 +1822,7 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
req->ies_len = cpu_to_le16(sreq->ie_len);
}
if (is_mt7921(phy->dev))
if (is_connac2(phy->dev))
req->scan_func |= SCAN_FUNC_SPLIT_SCAN;
memcpy(req->bssid, sreq->bssid, ETH_ALEN);
@@ -1893,7 +1898,7 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,
get_random_mask_addr(addr, sreq->mac_addr,
sreq->mac_addr_mask);
}
if (is_mt7921(phy->dev)) {
if (is_connac2(phy->dev)) {
req->mt7921.bss_idx = mvif->idx;
req->mt7921.delay = cpu_to_le32(sreq->delay);
}
@@ -2033,7 +2038,7 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
struct mt76_power_limits *limits,
enum nl80211_band band)
{
int max_power = is_mt7921(dev) ? 127 : 63;
int max_power = is_connac2(dev) ? 127 : 63;
int i, offset = sizeof(limits->cck);
memset(sku, max_power, MT_SKU_POWER_LIMIT);
@@ -2061,7 +2066,7 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
offset += 12;
}
if (!is_mt7921(dev))
if (!is_connac2(dev))
return;
/* he */
@@ -2117,7 +2122,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
enum nl80211_band band)
{
struct mt76_dev *dev = phy->dev;
int sku_len, batch_len = is_mt7921(dev) ? 8 : 16;
int sku_len, batch_len = is_connac2(dev) ? 8 : 16;
static const u8 chan_list_2ghz[] = {
1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14
@@ -2158,7 +2163,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
if (!limits)
return -ENOMEM;
sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;
sku_len = is_connac2(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;
tx_power = 2 * phy->hw->conf.power_level;
if (!tx_power)
tx_power = 127;
@@ -2242,6 +2247,9 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
false);
if (err < 0)
goto out;
/* read a CR to avoid PSE buffer underflow */
mt76_connac_mcu_reg_rr(dev, MT_PSE_BASE);
}
out:
@@ -2764,12 +2772,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd);
if (ret)
if (ret) {
dev_kfree_skb(skb);
return ret;
}
ret = mt76_connac_mcu_sta_wed_update(dev, skb);
if (ret)
if (ret) {
dev_kfree_skb(skb);
return ret;
}
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
}
@@ -3072,7 +3084,7 @@ static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info)
{
u32 mode = DL_MODE_NEED_RSP;
if ((!is_mt7921(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT)
if ((!is_connac2(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT)
return mode;
switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) {

View File

@@ -628,6 +628,13 @@ struct sta_rec_tx_proc {
__le32 flag;
} __packed;
struct sta_rec_eml_op {
__le16 tag;
__le16 len;
u8 link_bitmap;
u8 link_ant_num[3];
} __packed;
/* wtbl_rec */
struct wtbl_req_hdr {
@@ -796,6 +803,7 @@ struct wtbl_raw {
sizeof(struct sta_rec_he_6g_capa) + \
sizeof(struct sta_rec_pn_info) + \
sizeof(struct sta_rec_tx_proc) + \
sizeof(struct sta_rec_eml_op) + \
sizeof(struct tlv) + \
MT76_CONNAC_WTBL_UPDATE_MAX_SIZE)
@@ -832,6 +840,7 @@ enum {
STA_REC_PN_INFO = 0x26,
STA_REC_KEY_V3 = 0x27,
STA_REC_HDRT = 0x28,
STA_REC_EML_OP = 0x29,
STA_REC_HDR_TRANS = 0x2B,
STA_REC_MAX_NUM
};
@@ -1308,7 +1317,9 @@ enum {
MCU_UNI_CMD_PER_STA_INFO = 0x6d,
MCU_UNI_CMD_ALL_STA_INFO = 0x6e,
MCU_UNI_CMD_ASSERT_DUMP = 0x6f,
MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74,
MCU_UNI_CMD_RADIO_STATUS = 0x80,
MCU_UNI_CMD_MLD = 0x82,
MCU_UNI_CMD_SDO = 0x88,
};
@@ -1363,6 +1374,7 @@ enum {
UNI_BSS_INFO_BASIC = 0,
UNI_BSS_INFO_RA = 1,
UNI_BSS_INFO_RLM = 2,
UNI_BSS_INFO_PROTECT_INFO = 3,
UNI_BSS_INFO_BSS_COLOR = 4,
UNI_BSS_INFO_HE_BASIC = 5,
UNI_BSS_INFO_11V_MBSSID = 6,
@@ -1383,6 +1395,7 @@ enum {
UNI_BSS_INFO_MLD = 26,
UNI_BSS_INFO_PM_DISABLE = 27,
UNI_BSS_INFO_EHT = 30,
UNI_BSS_INFO_MLD_LINK_OP = 36,
};
enum {
@@ -1865,7 +1878,7 @@ mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa)
ret |= feature_set & FW_FEATURE_SET_ENCRYPT ?
DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0;
if (is_mt7921(dev) || is_mt7925(dev))
if (is_connac2(dev) || is_mt7925(dev))
ret |= feature_set & FW_FEATURE_ENCRY_MODE ?
DL_CONFIG_ENCRY_MODE_SEL : 0;
ret |= FIELD_PREP(DL_MODE_KEY_IDX,

View File

@@ -534,6 +534,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw,
return;
clear_bit(MT76_RESTART, &dev->mphy.state);
ieee80211_wake_queues(hw);
}
EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete);

View File

@@ -1294,6 +1294,7 @@ int mt7915_register_device(struct mt7915_dev *dev)
void mt7915_unregister_device(struct mt7915_dev *dev)
{
cancel_work_sync(&dev->dump_work);
mt7915_unregister_ext_phy(dev);
mt7915_coredump_unregister(dev);
mt7915_unregister_thermal(&dev->phy);

View File

@@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
rcu_read_unlock();
}
void mt7915_mac_enable_rtscts(struct mt7915_dev *dev,
struct ieee80211_vif *vif, bool enable)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
u32 addr;
addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
if (enable)
mt76_set(dev, addr, BIT(5));
else
mt76_clear(dev, addr, BIT(5));
}
static void
mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q,
struct mt7915_sta *msta, struct sk_buff *skb,

View File

@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw)
if (ret)
goto out;
ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b,
ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES,
phy->mt76->band_idx);
if (ret)
goto out;
@@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
if (set_sta == 1)
mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false);
if (changed & BSS_CHANGED_ERP_CTS_PROT)
mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot);
if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode,
info->use_cts_prot);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = 9;
@@ -851,8 +852,10 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false);
case MT76_STA_EVENT_DISASSOC:
mutex_lock(&dev->mt76.mutex);
for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
mt7915_mac_twt_teardown_flow(dev, msta, i);
mutex_unlock(&dev->mt76.mutex);
mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false);
msta->wcid.sta_disabled = 1;

View File

@@ -1765,8 +1765,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
}
out:
ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
if (ret)
if (ret) {
dev_kfree_skb(skb);
return ret;
}
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD(STA_REC_UPDATE), true);
@@ -3954,6 +3956,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
return ret;
}
int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,
u8 ht_mode, bool use_cts_prot)
{
struct mt7915_dev *dev = phy->dev;
int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot);
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct bss_info_prot *prot;
struct sk_buff *skb;
struct tlv *tlv;
enum {
PROT_NONMEMBER = BIT(1),
PROT_20MHZ = BIT(2),
PROT_NONHT_MIXED = BIT(3),
PROT_LEGACY_ERP = BIT(5),
PROT_NONGF_STA = BIT(7),
};
u32 rts_threshold;
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
NULL, len);
if (IS_ERR(skb))
return PTR_ERR(skb);
tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO,
sizeof(*prot));
prot = (struct bss_info_prot *)tlv;
switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
prot->prot_mode = cpu_to_le32(PROT_NONMEMBER);
break;
case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
prot->prot_mode = cpu_to_le32(PROT_20MHZ);
break;
case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED);
break;
}
if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA);
if (use_cts_prot)
prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP);
/* reuse current RTS setting */
rts_threshold = phy->mt76->hw->wiphy->rts_threshold;
if (rts_threshold == (u32)-1)
prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES);
else
prot->rts_len_thres = cpu_to_le32(rts_threshold);
prot->rts_pkt_thres = 0x2;
prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
if (!prot->he_rts_thres)
prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD(BSS_INFO_UPDATE), true);
}
int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct cfg80211_he_bss_color *he_bss_color)
{

View File

@@ -399,6 +399,17 @@ struct bss_info_inband_discovery {
__le16 prob_rsp_len;
} __packed __aligned(4);
struct bss_info_prot {
__le16 tag;
__le16 len;
__le32 prot_type;
__le32 prot_mode;
__le32 rts_len_thres;
__le16 he_rts_thres;
u8 rts_pkt_thres;
u8 rsv[5];
} __packed;
enum {
BSS_INFO_BCN_CSA,
BSS_INFO_BCN_BCC,

View File

@@ -84,6 +84,8 @@
#define MT7915_CRIT_TEMP 110
#define MT7915_MAX_TEMP 120
#define MT7915_RTS_LEN_THRES 0x92b
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -473,6 +475,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v
u32 changed);
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int enable, u32 changed);
int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,
u8 ht_mode, bool use_cts_prot);
int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_he_obss_pd *he_obss_pd);
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,

View File

@@ -302,7 +302,9 @@ int mt7921_register_device(struct mt792x_dev *dev)
dev->pm.idle_timeout = MT792x_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
if (!mt76_is_usb(&dev->mt76)) {
if (!mt76_is_usb(&dev->mt76) &&
!is_mt7902(&dev->mt76)) {
dev->pm.enable_user = true;
dev->pm.enable = true;
dev->pm.ds_enable_user = true;

View File

@@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev)
{
struct mt792x_phy *phy = &dev->phy;
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
return;
timer_delete_sync(&phy->roc_timer);
cancel_work_sync(&phy->roc_work);
if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
ieee80211_iterate_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_roc_iter, (void *)phy);
cancel_work(&phy->roc_work);
ieee80211_iterate_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_roc_iter, (void *)phy);
}
EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync);
@@ -387,10 +390,11 @@ void mt7921_roc_work(struct work_struct *work)
phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
roc_work);
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
return;
mt792x_mutex_acquire(phy->dev);
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) {
mt792x_mutex_release(phy->dev);
return;
}
ieee80211_iterate_active_interfaces(phy->mt76->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_roc_iter, phy);
@@ -796,7 +800,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add)
}
out:
mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env);
if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ)
mt7921_regd_update(dev);
}
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -807,6 +812,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
int ret, idx;
if (sta->aid > MT7921_MAX_AID)
return -ENOENT;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
return -ENOSPC;
@@ -850,6 +858,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
if (sta->aid > MT7921_MAX_AID)
return -ENOENT;
if (ev != MT76_STA_EVENT_ASSOC)
return 0;

View File

@@ -1353,6 +1353,9 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
u16 len = le16_to_cpu(rule->len);
u16 offset = len + sizeof(*rule);
if (buf_len < offset)
break;
pos += offset;
buf_len -= offset;
if (rule->alpha2[0] != alpha2[0] ||

View File

@@ -7,6 +7,8 @@
#include "../mt792x.h"
#include "regs.h"
#define MT7921_MAX_AID 20
#define MT7921_TX_RING_SIZE 2048
#define MT7921_TX_MCU_RING_SIZE 256
#define MT7921_TX_FWDL_RING_SIZE 128
@@ -15,6 +17,9 @@
#define MT7921_RX_MCU_RING_SIZE 8
#define MT7921_RX_MCU_WA_RING_SIZE 512
/* MT7902 Rx Ring0 is for both Rx Event and Tx Done Event */
#define MT7902_RX_MCU_RING_SIZE 512
#define MT7921_EEPROM_SIZE 3584
#define MT7921_TOKEN_SIZE 8192
@@ -117,6 +122,17 @@ enum mt7921_rxq_id {
MT7921_RXQ_MCU_WM = 0,
};
/* MT7902 assigns its MCU-WM TXQ at index 15 */
enum mt7902_txq_id {
MT7902_TXQ_MCU_WM = 15,
};
struct mt7921_dma_layout {
u8 mcu_wm_txq;
u16 mcu_rxdone_ring_size;
bool has_mcu_wa;
};
enum {
MT7921_CLC_POWER,
MT7921_CLC_CHAN,

View File

@@ -26,6 +26,8 @@ static const struct pci_device_id mt7921_pci_device_table[] = {
.driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7920),
.driver_data = (kernel_ulong_t)MT7920_FIRMWARE_WM },
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7902),
.driver_data = (kernel_ulong_t)MT7902_FIRMWARE_WM },
{ },
};
@@ -167,8 +169,29 @@ static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
static int mt7921_dma_init(struct mt792x_dev *dev)
{
struct mt7921_dma_layout layout = {
/* General case: MT7921 / MT7922 /MT7920 */
.mcu_wm_txq = MT7921_TXQ_MCU_WM,
.mcu_rxdone_ring_size = MT7921_RX_MCU_RING_SIZE,
.has_mcu_wa = true,
};
bool is_mt7902;
int ret;
is_mt7902 = mt7921_l1_rr(dev, MT_HW_CHIPID) == 0x7902;
/*
* MT7902 special case:
* - MCU-WM TXQ uses index 15
* - RX Ring0 is larger and shared for event/TX-done
* - MT7902 does not use the MCU_WA ring
*/
if (is_mt7902) {
layout.mcu_wm_txq = MT7902_TXQ_MCU_WM;
layout.mcu_rxdone_ring_size = MT7902_RX_MCU_RING_SIZE;
layout.has_mcu_wa = false;
}
mt76_dma_attach(&dev->mt76);
ret = mt792x_dma_disable(dev, true);
@@ -185,7 +208,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev)
mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4);
/* command to WM */
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM,
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, layout.mcu_wm_txq,
MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
@@ -199,18 +222,20 @@ static int mt7921_dma_init(struct mt792x_dev *dev)
/* event from WM before firmware download */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
MT7921_RXQ_MCU_WM,
MT7921_RX_MCU_RING_SIZE,
layout.mcu_rxdone_ring_size,
MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
if (ret)
return ret;
/* Change mcu queue after firmware download */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT7921_RXQ_MCU_WM,
MT7921_RX_MCU_WA_RING_SIZE,
MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
if (ret)
return ret;
if (layout.has_mcu_wa) {
/* Change mcu queue after firmware download */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT7921_RXQ_MCU_WM,
MT7921_RX_MCU_WA_RING_SIZE,
MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
if (ret)
return ret;
}
/* rx data */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
@@ -276,6 +301,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
struct mt76_bus_ops *bus_ops;
struct mt792x_dev *dev;
struct mt76_dev *mdev;
void __iomem *regs;
u16 cmd, chipid;
u8 features;
int ret;
@@ -284,10 +310,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
if (ret)
return ret;
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_MEMORY)) {
cmd |= PCI_COMMAND_MEMORY;
@@ -321,11 +343,29 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mdev);
regs = pcim_iomap_region(pdev, 0, pci_name(pdev));
if (IS_ERR(regs))
return PTR_ERR(regs);
dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &mt7921_pcie_ops;
dev->irq_map = &irq_map;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
mt76_mmio_init(&dev->mt76, regs);
if (id->device == 0x7902) {
struct mt792x_irq_map *map;
/* MT7902 needs a mutable copy because wm2_complete_mask differs */
map = devm_kmemdup(&pdev->dev, &irq_map,
sizeof(irq_map), GFP_KERNEL);
if (!map)
return -ENOMEM;
map->rx.wm2_complete_mask = 0;
dev->irq_map = map;
}
tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
dev->phy.dev = dev;
@@ -579,6 +619,8 @@ MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
MODULE_FIRMWARE(MT7921_ROM_PATCH);
MODULE_FIRMWARE(MT7922_FIRMWARE_WM);
MODULE_FIRMWARE(MT7922_ROM_PATCH);
MODULE_FIRMWARE(MT7902_FIRMWARE_WM);
MODULE_FIRMWARE(MT7902_ROM_PATCH);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver");

View File

@@ -71,9 +71,9 @@ int mt7921e_mac_reset(struct mt792x_dev *dev)
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]);
napi_disable(&dev->mt76.napi[MT_RXQ_MCU]);
napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
mt76_for_each_q_rx(&dev->mt76, i) {
napi_disable(&dev->mt76.napi[i]);
}
napi_disable(&dev->mt76.tx_napi);
mt76_connac2_tx_token_put(&dev->mt76);

View File

@@ -19,6 +19,8 @@
static const struct sdio_device_id mt7921s_table[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901),
.driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7902),
.driver_data = (kernel_ulong_t)MT7902_FIRMWARE_WM },
{ } /* Terminating entry */
};
@@ -317,6 +319,8 @@ static int mt7921s_resume(struct device *__dev)
MODULE_DEVICE_TABLE(sdio, mt7921s_table);
MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
MODULE_FIRMWARE(MT7921_ROM_PATCH);
MODULE_FIRMWARE(MT7902_FIRMWARE_WM);
MODULE_FIRMWARE(MT7902_ROM_PATCH);
static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume);

View File

@@ -91,6 +91,8 @@ int mt7925_mac_init(struct mt792x_dev *dev)
mt7925_mac_init_basic_rates(dev);
memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2));
return 0;
}
EXPORT_SYMBOL_GPL(mt7925_mac_init);

View File

@@ -804,8 +804,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
txwi[5] = cpu_to_le32(val);
val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
if (!ieee80211_vif_is_mld(vif) ||
(q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))
if (vif && (!ieee80211_vif_is_mld(vif) ||
(q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)))
val |= MT_TXD6_DIS_MAT;
txwi[6] = cpu_to_le32(val);
txwi[7] = 0;
@@ -846,11 +846,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,
bool is_8023;
u16 fc, tid;
if (!sta)
return;
link_sta = rcu_dereference(sta->link[wcid->link_id]);
if (!link_sta)
return;
if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
return;
tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -882,8 +885,10 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,
else
mlink = &msta->deflink;
if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state))
ieee80211_start_tx_ba_session(sta, tid, 0);
if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) {
if (ieee80211_start_tx_ba_session(sta, tid, 0))
clear_bit(tid, &mlink->wcid.ampdu_state);
}
}
static bool
@@ -1280,7 +1285,8 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
if (vif->type == NL80211_IFTYPE_AP) {
mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid,
true, NULL);
mt7925_mcu_sta_update(dev, NULL, vif, true,
mt7925_mcu_sta_update(dev, NULL, vif,
&mvif->sta.deflink, true,
MT76_STA_INFO_STATE_NONE);
mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);
}

View File

@@ -245,6 +245,7 @@ int mt7925_init_mlo_caps(struct mt792x_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
static const u8 ext_capa_sta[] = {
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
};
@@ -438,6 +439,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN)
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI;
INIT_WORK(&mvif->csa_work, mt7925_csa_work);
timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0);
out:
mt792x_mutex_release(dev);
@@ -457,12 +461,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev)
{
struct mt792x_phy *phy = &dev->phy;
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
return;
timer_delete_sync(&phy->roc_timer);
cancel_work_sync(&phy->roc_work);
if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
ieee80211_iterate_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_roc_iter, (void *)phy);
cancel_work(&phy->roc_work);
ieee80211_iterate_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_roc_iter, (void *)phy);
}
EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync);
@@ -541,7 +549,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy,
phy->roc_grant = false;
err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id);
err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id);
if (err < 0) {
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
goto out;
@@ -586,7 +594,8 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw,
static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key, int link_id)
struct ieee80211_key_conf *key, int link_id,
struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
@@ -595,7 +604,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_bss_conf *link_conf;
struct ieee80211_link_sta *link_sta;
int idx = key->keyidx, err = 0;
struct mt792x_link_sta *mlink;
struct mt792x_bss_conf *mconf;
struct mt76_wcid *wcid;
u8 *wcid_keyidx;
@@ -603,7 +611,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL;
mconf = mt792x_vif_to_link(mvif, link_id);
mlink = mt792x_sta_to_link(msta, link_id);
wcid = &mlink->wcid;
wcid_keyidx = &wcid->hw_key_idx;
@@ -671,6 +678,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv :
&mvif->sta;
struct mt792x_link_sta *mlink;
int err;
/* The hardware does not support per-STA RX GTK, fallback
@@ -692,12 +700,16 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links;
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id);
mlink = mt792x_sta_to_link(msta, link_id);
err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id,
mlink);
if (err < 0)
break;
}
} else {
err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id);
mlink = mt792x_sta_to_link(msta, vif->bss_conf.link_id);
err = mt7925_set_link_key(hw, cmd, vif, sta, key,
vif->bss_conf.link_id, mlink);
}
mt792x_mutex_release(dev);
@@ -842,20 +854,24 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta)
struct ieee80211_link_sta *link_sta,
struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct ieee80211_bss_conf *link_conf;
struct mt792x_bss_conf *mconf;
u8 link_id = link_sta->link_id;
struct mt792x_link_sta *mlink;
bool wcid_published = false;
struct mt792x_sta *msta;
struct mt76_wcid *wcid;
bool pm_woken = false;
int ret, idx;
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_id);
if (WARN_ON_ONCE(!mlink))
return -EINVAL;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
@@ -874,14 +890,15 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
wcid = &mlink->wcid;
ewma_signal_init(&wcid->rssi);
rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid);
mt76_wcid_init(wcid, 0);
wcid_published = true;
ewma_avg_signal_init(&mlink->avg_ack_signal);
memset(mlink->airtime_ac, 0,
sizeof(msta->deflink.airtime_ac));
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
return ret;
goto out_wcid;
pm_woken = true;
mt7925_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -890,41 +907,125 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
if (ieee80211_vif_is_mld(vif))
mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
link_conf, link_sta, link_sta != mlink->pri_link);
else
mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
link_conf, link_sta, false);
struct mt792x_link_sta *mlink_bc;
mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
if (ieee80211_vif_is_mld(vif)) {
ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
link_conf, link_sta,
mlink_bc->wcid.idx, mlink->wcid.idx,
link_sta != mlink->pri_link);
if (ret)
goto out_pm;
} else {
ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx,
link_conf, link_sta,
mlink_bc->wcid.idx, mlink->wcid.idx,
false);
if (ret)
goto out_pm;
}
}
if (ieee80211_vif_is_mld(vif) &&
link_sta == mlink->pri_link) {
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
return ret;
goto out_pm;
} else if (ieee80211_vif_is_mld(vif) &&
link_sta != mlink->pri_link) {
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
true, MT76_STA_INFO_STATE_ASSOC);
if (ret)
return ret;
struct mt792x_link_sta *pri_mlink;
struct mt76_wcid *pri_wcid;
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
/* alternative lookup via def_wcid */
pri_wcid = mlink->wcid.def_wcid;
pri_mlink = pri_wcid ?
container_of(pri_wcid, struct mt792x_link_sta, wcid) :
NULL;
if (WARN_ON_ONCE(!pri_mlink)) {
ret = -EINVAL;
goto out_pm;
}
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
pri_mlink, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
return ret;
goto out_pm;
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
goto out_pm;
} else {
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
return ret;
goto out_pm;
}
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
return 0;
out_pm:
if (pm_woken)
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
out_wcid:
if (wcid_published) {
u16 idx = wcid->idx;
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mt76_wcid_cleanup(mdev, wcid);
mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx);
}
return ret;
}
/*
* Host-only unwind for sta_add_links() failures.
*
* If add_links fail due to MCU/firmware timeouts; calling the full remove
* path would send more firmware commands and may hang again. So only rollback
* host-published state here (msta->link/valid_links, dev->mt76.wcid[idx]) and
* free mlink objects (RCU-safe). Firmware state is left for reset/recovery.
*/
static void
mt7925_mac_sta_unwind_links_host(struct mt792x_dev *dev,
struct ieee80211_sta *sta,
unsigned long links)
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
unsigned int link_id;
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt792x_link_sta *mlink;
u16 idx;
mlink = rcu_replace_pointer(msta->link[link_id], NULL,
lockdep_is_held(&dev->mt76.mutex));
if (!mlink)
continue;
msta->valid_links &= ~BIT(link_id);
if (msta->deflink_id == link_id)
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
idx = mlink->wcid.idx;
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx);
if (mlink != &msta->deflink)
kfree_rcu(mlink, rcu_head);
}
}
static int
@@ -932,34 +1033,50 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long new_links)
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
unsigned long added_links = 0;
unsigned int link_id;
int err = 0;
for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_link_sta *link_sta;
struct mt792x_link_sta *mlink;
bool is_deflink = false;
if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) {
mlink = &msta->deflink;
msta->deflink_id = link_id;
is_deflink = true;
} else {
mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL);
mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
if (!mlink) {
err = -ENOMEM;
break;
}
}
msta->valid_links |= BIT(link_id);
rcu_assign_pointer(msta->link[link_id], mlink);
mlink->sta = msta;
mlink->pri_link = &sta->deflink;
mlink->wcid.def_wcid = &msta->deflink.wcid;
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta);
err = mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta, mlink);
if (err) {
if (!is_deflink)
kfree_rcu(mlink, rcu_head);
break;
}
if (is_deflink)
msta->deflink_id = link_id;
rcu_assign_pointer(msta->link[link_id], mlink);
msta->valid_links |= BIT(link_id);
added_links |= BIT(link_id);
}
if (err && added_links)
mt7925_mac_sta_unwind_links_host(dev, sta, added_links);
return err;
}
@@ -981,7 +1098,8 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links);
} else {
err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink);
err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink,
&msta->deflink);
}
return err;
@@ -1030,11 +1148,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
struct mt792x_link_sta *mlink;
struct mt792x_sta *msta;
mt792x_mutex_acquire(dev);
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
mt792x_mutex_acquire(dev);
if (ieee80211_vif_is_mld(vif)) {
link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id);
} else {
@@ -1055,7 +1173,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));
mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_ASSOC);
mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true,
MT76_STA_INFO_STATE_ASSOC);
mt792x_mutex_release(dev);
}
@@ -1083,23 +1202,21 @@ EXPORT_SYMBOL_GPL(mt7925_mac_sta_event);
static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta)
struct ieee80211_link_sta *link_sta,
struct mt792x_link_sta *mlink)
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt76_wcid *wcid = &mlink->wcid;
struct ieee80211_bss_conf *link_conf;
u8 link_id = link_sta->link_id;
struct mt792x_link_sta *mlink;
struct mt792x_sta *msta;
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_id);
u16 idx = wcid->idx;
mt7925_roc_abort_sync(dev);
mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid);
mt76_connac_free_pending_tx_skbs(&dev->pm, wcid);
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
mt7925_mcu_sta_update(dev, link_sta, vif, false,
mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false,
MT76_STA_INFO_STATE_NONE);
mt7925_mac_wtbl_update(dev, mlink->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -1123,6 +1240,10 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
list_del_init(&mlink->wcid.poll_list);
spin_unlock_bh(&mdev->sta_poll_lock);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mt76_wcid_cleanup(mdev, wcid);
mt76_wcid_mask_clear(mdev->wcid_mask, idx);
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
@@ -1132,7 +1253,6 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
struct mt76_dev *mdev = &dev->mt76;
struct mt76_wcid *wcid;
unsigned int link_id;
/* clean up bss before starec */
@@ -1171,22 +1291,19 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
if (!link_sta)
continue;
mlink = mt792x_sta_to_link(msta, link_id);
mlink = rcu_replace_pointer(msta->link[link_id], NULL,
lockdep_is_held(&mdev->mutex));
if (!mlink)
continue;
mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta);
wcid = &mlink->wcid;
rcu_assign_pointer(msta->link[link_id], NULL);
msta->valid_links &= ~BIT(link_id);
mlink->sta = NULL;
mlink->pri_link = NULL;
if (link_sta != mlink->pri_link) {
mt76_wcid_cleanup(mdev, wcid);
mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx);
}
mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink);
if (mlink != &msta->deflink)
kfree_rcu(mlink, rcu_head);
if (msta->deflink_id == link_id)
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
@@ -1323,10 +1440,18 @@ void mt7925_mlo_pm_work(struct work_struct *work)
void mt7925_scan_work(struct work_struct *work)
{
struct mt792x_phy *phy;
struct mt792x_dev *dev;
struct mt76_connac_pm *pm;
phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
scan_work.work);
dev = phy->dev;
pm = &dev->pm;
if (pm->suspended)
return;
while (true) {
struct sk_buff *skb;
struct tlv *tlv;
@@ -1544,8 +1669,10 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0);
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt792x_bss_conf *mconf;
struct mt792x_link_sta *mlink;
mconf = mt792x_vif_to_link(mvif, i);
mlink = mt792x_sta_to_link(msta, i);
if (enabled)
@@ -1556,7 +1683,7 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
if (!mlink->wcid.sta)
continue;
mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i);
mt7925_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
}
mt792x_mutex_release(dev);
@@ -1716,7 +1843,8 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (err)
goto out;
err = mt7925_mcu_sta_update(dev, NULL, vif, true,
err = mt7925_mcu_sta_update(dev, NULL, vif,
&mvif->sta.deflink, true,
MT76_STA_INFO_STATE_NONE);
out:
mt792x_mutex_release(dev);
@@ -1749,6 +1877,10 @@ static int
mt7925_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
dev->new_ctx = ctx;
return 0;
}
@@ -1756,6 +1888,11 @@ static void
mt7925_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
if (dev->new_ctx == ctx)
dev->new_ctx = NULL;
}
static void
@@ -1850,7 +1987,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
mt792x_mutex_acquire(dev);
if (changed & BSS_CHANGED_ASSOC) {
mt7925_mcu_sta_update(dev, NULL, vif, true,
mt7925_mcu_sta_update(dev, NULL, vif,
&mvif->sta.deflink, true,
MT76_STA_INFO_STATE_ASSOC);
mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc);
@@ -1894,10 +2032,8 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
struct mt792x_phy *phy = mt792x_hw_phy(hw);
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_bss_conf *mconf;
struct ieee80211_bss_conf *link_conf;
mconf = mt792x_vif_to_link(mvif, info->link_id);
link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id);
mt792x_mutex_acquire(dev);
@@ -1939,10 +2075,6 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS;
}
if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING)
mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76,
link_conf, NULL);
if (changed & BSS_CHANGED_CQM)
mt7925_mcu_set_rssimonitor(dev, vif);
@@ -2144,6 +2276,11 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw,
mctx->bss_conf = NULL;
mconf->mt76.ctx = NULL;
mutex_unlock(&dev->mt76.mutex);
if (link_conf->csa_active) {
timer_delete_sync(&mvif->csa_timer);
cancel_work_sync(&mvif->csa_work);
}
}
static void mt7925_rfkill_poll(struct ieee80211_hw *hw)
@@ -2158,6 +2295,121 @@ static void mt7925_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(hw->wiphy, ret == 0);
}
static int mt7925_switch_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
return mt7925_assign_vif_chanctx(hw, vifs->vif, vifs->link_conf,
vifs->new_ctx);
}
void mt7925_csa_work(struct work_struct *work)
{
struct mt792x_vif *mvif;
struct mt792x_dev *dev;
struct ieee80211_vif *vif;
struct ieee80211_bss_conf *link_conf;
struct mt792x_bss_conf *mconf;
u8 link_id, roc_rtype;
int ret = 0;
mvif = (struct mt792x_vif *)container_of(work, struct mt792x_vif,
csa_work);
dev = mvif->phy->dev;
vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
if (ieee80211_vif_is_mld(vif))
return;
if (!dev->new_ctx)
return;
link_id = 0;
mconf = &mvif->bss_conf;
link_conf = &vif->bss_conf;
roc_rtype = MT7925_ROC_REQ_JOIN;
mt792x_mutex_acquire(dev);
ret = mt7925_set_roc(mvif->phy, mconf, dev->new_ctx->def.chan,
4000, roc_rtype);
mt792x_mutex_release(dev);
if (!ret) {
mt792x_mutex_acquire(dev);
ret = mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, link_conf,
dev->new_ctx);
mt792x_mutex_release(dev);
mt7925_abort_roc(mvif->phy, mconf);
}
ieee80211_chswitch_done(vif, !ret, link_id);
}
static int mt7925_pre_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
if (ieee80211_vif_is_mld(vif))
return -EOPNOTSUPP;
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
return -EOPNOTSUPP;
if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef,
IEEE80211_CHAN_DISABLED))
return -EOPNOTSUPP;
return 0;
}
static void mt7925_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
u16 beacon_interval;
if (ieee80211_vif_is_mld(vif))
return;
beacon_interval = vif->bss_conf.beacon_int;
mvif->csa_timer.expires = TU_TO_EXP_TIME(beacon_interval * chsw->count);
add_timer(&mvif->csa_timer);
}
static void mt7925_abort_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
timer_delete_sync(&mvif->csa_timer);
cancel_work_sync(&mvif->csa_work);
}
static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
u16 beacon_interval;
if (ieee80211_vif_is_mld(vif))
return;
beacon_interval = vif->bss_conf.beacon_int;
if (cfg80211_chandef_identical(&chsw->chandef,
&dev->new_ctx->def) &&
chsw->count) {
mod_timer(&mvif->csa_timer,
TU_TO_EXP_TIME(beacon_interval * chsw->count));
}
}
const struct ieee80211_ops mt7925_ops = {
.tx = mt792x_tx,
.start = mt7925_start,
@@ -2221,6 +2473,12 @@ const struct ieee80211_ops mt7925_ops = {
.change_vif_links = mt7925_change_vif_links,
.change_sta_links = mt7925_change_sta_links,
.rfkill_poll = mt7925_rfkill_poll,
.switch_vif_chanctx = mt7925_switch_vif_chanctx,
.pre_channel_switch = mt7925_pre_channel_switch,
.channel_switch = mt7925_channel_switch,
.abort_channel_switch = mt7925_abort_channel_switch,
.channel_switch_rx_beacon = mt7925_channel_switch_rx_beacon,
};
EXPORT_SYMBOL_GPL(mt7925_ops);

View File

@@ -1066,9 +1066,8 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware);
static void
mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta)
struct mt792x_link_sta *mlink)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct sta_rec_hdr_trans *hdr_trans;
struct mt76_wcid *wcid;
struct tlv *tlv;
@@ -1082,19 +1081,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
else
hdr_trans->from_ds = true;
if (link_sta) {
struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
struct mt792x_link_sta *mlink;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
wcid = &mlink->wcid;
} else {
wcid = &mvif->sta.deflink.wcid;
}
if (!wcid)
if (WARN_ON_ONCE(!mlink))
return;
wcid = &mlink->wcid;
hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);
if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {
hdr_trans->to_ds = true;
@@ -1104,30 +1095,18 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
int link_id)
struct mt792x_bss_conf *mconf,
struct mt792x_link_sta *mlink)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL;
struct mt792x_link_sta *mlink;
struct mt792x_bss_conf *mconf;
struct mt792x_sta *msta;
struct sk_buff *skb;
msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta;
mlink = mt792x_sta_to_link(msta, link_id);
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
mconf = mt792x_vif_to_link(mvif, link_id);
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
&mlink->wcid,
MT7925_STA_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
return PTR_ERR(skb);
/* starec hdr trans */
mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta);
mt7925_mcu_sta_hdr_trans_tlv(skb, vif, mlink);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
@@ -1288,14 +1267,16 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta);
if (ret)
if (ret) {
dev_kfree_skb(skb);
return ret;
}
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
}
int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
int duration, u8 token_id)
int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
u16 sel_links, int duration, u8 token_id)
{
struct mt792x_vif *mvif = mconf->vif;
struct ieee80211_vif *vif = container_of((void *)mvif,
@@ -1330,6 +1311,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
.roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv))
};
struct wiphy *wiphy = phy->mt76->hw->wiphy;
if (!mconf || hweight16(vif->valid_links) < 2 ||
hweight16(sel_links) != 2)
return -EPERM;
@@ -1352,7 +1335,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ;
}
if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)
if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops &
IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS))
type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG :
MT7925_ROC_REQ_MLSR_AA;
else
@@ -1721,10 +1705,9 @@ mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)
static void
mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta)
struct ieee80211_link_sta *link_sta,
struct mt792x_link_sta *mlink)
{
struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
struct mt792x_link_sta *mlink;
struct sta_rec_amsdu *amsdu;
struct tlv *tlv;
@@ -1740,7 +1723,6 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,
amsdu->max_amsdu_num = 8;
amsdu->amsdu_en = true;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
mlink->wcid.amsdu = true;
switch (link_sta->agg.max_amsdu_len) {
@@ -1911,36 +1893,53 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,
static void
mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct mt792x_bss_conf *mconf,
struct mt792x_link_sta *mlink)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
unsigned long valid = mvif->valid_links;
struct mt792x_bss_conf *mconf;
struct mt792x_link_sta *mlink;
struct mt792x_dev *dev = mvif->phy->dev;
struct mt792x_bss_conf *mconf_pri;
struct sta_rec_mld *mld;
struct tlv *tlv;
int i, cnt = 0;
u8 cnt = 0;
/* Primary link always uses driver's deflink WCID. */
mconf_pri = (msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) ?
mt792x_vif_to_link(mvif, msta->deflink_id) : NULL;
/* If caller is operating on deflink, reuse its mconf as primary. */
if (!mconf_pri && mlink == &msta->deflink)
mconf_pri = mconf;
if (!mconf_pri) {
dev_warn_ratelimited(dev->mt76.dev,
"mt7925: MLD_TLV_LINK skip (no primary mconf) sta=%pM\n",
sta->addr);
return;
}
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld));
mld = (struct sta_rec_mld *)tlv;
memcpy(mld->mac_addr, sta->addr, ETH_ALEN);
mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx);
mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2);
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
if (cnt == mld->link_num)
break;
/* Always encode primary link first. */
mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
mld->link[cnt++].bss_idx = mconf_pri->mt76.idx;
mconf = mt792x_vif_to_link(mvif, i);
mlink = mt792x_sta_to_link(msta, i);
/* Optionally encode the currently-updated secondary link. */
if (mlink && mlink != &msta->deflink && mconf) {
mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt++].bss_idx = mconf->mt76.idx;
if (mlink != &msta->deflink)
mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
}
mld->link_num = cnt;
}
static void
@@ -1961,10 +1960,12 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv;
struct mt76_dev *dev = phy->dev;
struct mt792x_bss_conf *mconf;
struct mt792x_link_sta *mlink;
struct sk_buff *skb;
int conn_state;
mconf = mt792x_vif_to_link(mvif, info->wcid->link_id);
mlink = container_of(info->wcid, struct mt792x_link_sta, wcid);
skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid,
MT7925_STA_UPDATE_MAX_SIZE);
@@ -1982,7 +1983,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
mt7925_mcu_sta_ht_tlv(skb, info->link_sta);
mt7925_mcu_sta_vht_tlv(skb, info->link_sta);
mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta);
mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta);
mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta, mlink);
mt7925_mcu_sta_he_tlv(skb, info->link_sta);
mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta);
mt7925_mcu_sta_eht_tlv(skb, info->link_sta);
@@ -1993,7 +1994,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
info->state);
if (info->state != MT76_STA_INFO_STATE_NONE) {
mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta);
mt7925_mcu_sta_mld_tlv(skb, info->vif,
info->link_sta->sta,
mconf, mlink);
mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta);
}
}
@@ -2003,7 +2007,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF,
sizeof(struct tlv));
} else {
mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta);
if (!info->link_sta)
mlink = &mvif->sta.deflink;
mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, mlink);
}
return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);
@@ -2011,7 +2018,9 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct ieee80211_link_sta *link_sta,
struct ieee80211_vif *vif, bool enable,
struct ieee80211_vif *vif,
struct mt792x_link_sta *mlink,
bool enable,
enum mt76_sta_info_state state)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
@@ -2026,14 +2035,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
.offload_fw = true,
.rcpi = to_rcpi(rssi),
};
struct mt792x_sta *msta;
struct mt792x_link_sta *mlink;
if (link_sta) {
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
}
info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid;
info.wcid = &mlink->wcid;
info.newly = state != MT76_STA_INFO_STATE_ASSOC;
return mt7925_mcu_sta_cmd(&dev->mphy, &info);
@@ -2470,7 +2473,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
struct ieee80211_chanctx_conf *ctx,
struct mt76_phy *phy, u16 wlan_idx,
struct mt76_phy *phy,
u16 bmc_tx_wlan_idx,
u16 sta_wlan_idx,
bool enable)
{
struct ieee80211_vif *vif = link_conf->vif;
@@ -2479,7 +2484,6 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
&link_conf->chanreq.oper;
enum nl80211_band band = chandef->chan->band;
struct mt76_connac_bss_basic_tlv *basic_req;
struct mt792x_link_sta *mlink;
struct tlv *tlv;
int conn_type;
u8 idx;
@@ -2503,20 +2507,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta);
basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int);
basic_req->dtim_period = link_conf->dtim_period;
basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
basic_req->bmc_tx_wlan_idx = cpu_to_le16(bmc_tx_wlan_idx);
basic_req->link_idx = mconf->mt76.idx;
if (link_sta) {
struct mt792x_sta *msta;
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
} else {
mlink = &mconf->vif->sta.deflink;
}
basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx);
basic_req->sta_idx = cpu_to_le16(sta_wlan_idx);
basic_req->omac_idx = mconf->mt76.omac_idx;
basic_req->band_idx = mconf->mt76.band_idx;
basic_req->wmm_idx = mconf->mt76.wmm_idx;
@@ -2823,16 +2816,16 @@ void mt7925_mcu_del_dev(struct mt76_dev *mdev,
&dev_req, sizeof(dev_req), true);
}
int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
struct ieee80211_chanctx_conf *ctx,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
int enable)
int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,
struct ieee80211_chanctx_conf *ctx,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
u16 bmc_tx_wlan_idx,
u16 sta_wlan_idx,
int enable)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;
struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);
struct mt792x_dev *dev = phy->dev;
struct mt792x_link_sta *mlink_bc;
struct sk_buff *skb;
skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
@@ -2840,11 +2833,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
if (IS_ERR(skb))
return PTR_ERR(skb);
mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
/* bss_basic must be first */
mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76,
mlink_bc->wcid.idx, enable);
bmc_tx_wlan_idx, sta_wlan_idx, enable);
mt7925_mcu_bss_sec_tlv(skb, link_conf);
mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf);
mt7925_mcu_bss_qos_tlv(skb, link_conf);
@@ -2865,6 +2856,33 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
MCU_UNI_CMD(BSS_INFO_UPDATE), true);
}
int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
struct ieee80211_chanctx_conf *ctx,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
int enable)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;
struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);
struct mt792x_link_sta *mlink_bc;
struct mt792x_link_sta *mlink;
mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);
if (link_sta) {
struct mt792x_sta *msta = (void *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
if (WARN_ON(!mlink))
return -EINVAL;
} else {
mlink = &mconf->vif->sta.deflink;
}
return mt7925_mcu_add_bss_info_sta(phy, ctx, link_conf, link_sta,
mlink_bc->wcid.idx, mlink->wcid.idx, enable);
}
int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)
{
struct mt76_dev *mdev = phy->dev;
@@ -3375,7 +3393,6 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
u8 rsvd[64];
} __packed req = {
.tag = cpu_to_le16(0x3),
.len = cpu_to_le16(sizeof(req) - 4),
.idx = idx,
.env = env_cap,
@@ -3404,6 +3421,7 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
memcpy(req.type, rule->type, 2);
req.size = cpu_to_le16(seg->len);
req.len = cpu_to_le16(sizeof(req) + seg->len - 4);
dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag;
skb = __mt76_mcu_msg_alloc(&dev->mt76, &req,
le16_to_cpu(req.size) + sizeof(req),
@@ -3727,7 +3745,7 @@ mt7925_mcu_rate_txpower_band(struct mt76_phy *phy,
memcpy(tx_power_tlv->alpha2, dev->alpha2, sizeof(dev->alpha2));
tx_power_tlv->n_chan = num_ch;
tx_power_tlv->tag = cpu_to_le16(0x1);
tx_power_tlv->len = cpu_to_le16(sizeof(*tx_power_tlv));
tx_power_tlv->len = cpu_to_le16(msg_len);
switch (band) {
case NL80211_BAND_2GHZ:

View File

@@ -693,6 +693,13 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
int enable);
int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,
struct ieee80211_chanctx_conf *ctx,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
u16 bmc_tx_wlan_idx,
u16 sta_wlan_idx,
int enable);
int mt7925_mcu_set_timing(struct mt792x_phy *phy,
struct ieee80211_bss_conf *link_conf);
int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable);

View File

@@ -250,7 +250,9 @@ int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev,
bool enable);
int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct ieee80211_link_sta *link_sta,
struct ieee80211_vif *vif, bool enable,
struct ieee80211_vif *vif,
struct mt792x_link_sta *mlink,
bool enable,
enum mt76_sta_info_state state);
int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag);
int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf);
@@ -298,6 +300,7 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev,
void mt7925_mlo_pm_work(struct work_struct *work);
void mt7925_scan_work(struct work_struct *work);
void mt7925_roc_work(struct work_struct *work);
void mt7925_csa_work(struct work_struct *work);
int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev,
struct ieee80211_bss_conf *link_conf);
void mt7925_coredump_work(struct work_struct *work);
@@ -349,8 +352,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw,
int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set);
int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
enum environment_cap env_cap);
int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
int duration, u8 token_id);
int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
u16 sel_links, int duration, u8 token_id);
int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
struct ieee80211_channel *chan, int duration,
enum mt7925_roc_req type, u8 token_id);
@@ -367,8 +370,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val);
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
int link_id);
struct mt792x_bss_conf *mconf,
struct mt792x_link_sta *mlink);
int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy);
int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,

View File

@@ -232,7 +232,8 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2)
dev->regd_user)
return -EINVAL;
if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0')
if ((mdev->alpha2[0] && mdev->alpha2[0] != '0') &&
(mdev->alpha2[1] && mdev->alpha2[1] != '0'))
return 0;
/* do not need to update the same country twice */

View File

@@ -41,11 +41,13 @@
#define MT792x_MCU_INIT_RETRY_COUNT 10
#define MT792x_WFSYS_INIT_RETRY_COUNT 2
#define MT7902_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7902_1.bin"
#define MT7920_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1a.bin"
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin"
#define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin"
#define MT7902_ROM_PATCH "mediatek/WIFI_MT7902_patch_mcu_1_1_hdr.bin"
#define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin"
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin"
@@ -95,6 +97,7 @@ DECLARE_EWMA(avg_signal, 10, 8)
struct mt792x_link_sta {
struct mt76_wcid wcid; /* must be first */
struct rcu_head rcu_head;
u32 airtime_ac[8];
@@ -448,6 +451,8 @@ void mt792x_config_mac_addr_list(struct mt792x_dev *dev);
static inline char *mt792x_ram_name(struct mt792x_dev *dev)
{
switch (mt76_chip(&dev->mt76)) {
case 0x7902:
return MT7902_FIRMWARE_WM;
case 0x7920:
return MT7920_FIRMWARE_WM;
case 0x7922:
@@ -462,6 +467,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev)
static inline char *mt792x_patch_name(struct mt792x_dev *dev)
{
switch (mt76_chip(&dev->mt76)) {
case 0x7902:
return MT7902_ROM_PATCH;
case 0x7920:
return MT7920_ROM_PATCH;
case 0x7922:

View File

@@ -151,7 +151,7 @@ void mt792x_stop(struct ieee80211_hw *hw, bool suspend)
cancel_work_sync(&dev->reset_work);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
if (is_mt7921(&dev->mt76)) {
if (is_connac2(&dev->mt76)) {
mt792x_mutex_acquire(dev);
mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false);
mt792x_mutex_release(dev);
@@ -691,9 +691,8 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID);
if (is_mt7921(&dev->mt76)) {
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
}
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
if (dev->pm.enable)
ieee80211_hw_set(hw, CONNECTION_MONITOR);
@@ -927,6 +926,13 @@ int mt792x_load_firmware(struct mt792x_dev *dev)
{
int ret;
mt76_connac_mcu_restart(&dev->mt76);
if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC_FW_STATE,
MT_TOP_MISC2_FW_PWR_ON, 1000))
dev_warn(dev->mt76.dev,
"MCU is not ready for firmware download\n");
ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev));
if (ret)
return ret;

View File

@@ -103,6 +103,22 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev)
mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10));
mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4));
} else if (is_mt7902(&dev->mt76)) {
/* rx ring */
mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0040, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x0080, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x00c0, 0x4));
/* tx ring */
mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0100, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0140, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0180, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x01c0, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x0200, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x0240, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x0280, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x02c0, 0x4));
mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0300, 0x4));
} else {
/* rx ring */
mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4));
@@ -356,7 +372,7 @@ EXPORT_SYMBOL_GPL(mt792x_poll_rx);
int mt792x_wfsys_reset(struct mt792x_dev *dev)
{
u32 addr = is_mt7921(&dev->mt76) ? 0x18000140 : 0x7c000140;
u32 addr = is_connac2(&dev->mt76) ? 0x18000140 : 0x7c000140;
mt76_clear(dev, addr, WFSYS_SW_RST_B);
msleep(50);

View File

@@ -375,7 +375,7 @@ void mt792x_pm_power_save_work(struct work_struct *work)
}
if (!mt792x_mcu_fw_pmctrl(dev)) {
cancel_delayed_work_sync(&mphy->mac_work);
cancel_delayed_work(&mphy->mac_work);
return;
}
out:

View File

@@ -25,6 +25,8 @@
#define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n))
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
#define MT_PSE_BASE 0x820c8000
/* TMAC: band 0(0x21000), band 1(0xa1000) */
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000)
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
@@ -390,6 +392,10 @@
#define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600)
#define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0)
#define MT7925_CBTOP_RGU_WF_SUBSYS_RST 0x70028600
#define MT7925_WFSYS_INIT_DONE_ADDR 0x184c1604
#define MT7925_WFSYS_INIT_DONE 0x00001d1e
#define MT_HW_BOUND 0x70010020
#define MT_HW_CHIPID 0x70010200
#define MT_HW_REV 0x70010204

View File

@@ -206,6 +206,33 @@ static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset)
mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val);
}
struct mt792xu_wfsys_desc {
u32 rst_reg;
u32 done_reg;
u32 done_mask;
u32 done_val;
u32 delay_ms;
bool need_status_sel;
};
static const struct mt792xu_wfsys_desc mt7921_wfsys_desc = {
.rst_reg = MT_CBTOP_RGU_WF_SUBSYS_RST,
.done_reg = MT_UDMA_CONN_INFRA_STATUS,
.done_mask = MT_UDMA_CONN_WFSYS_INIT_DONE,
.done_val = MT_UDMA_CONN_WFSYS_INIT_DONE,
.delay_ms = 0,
.need_status_sel = true,
};
static const struct mt792xu_wfsys_desc mt7925_wfsys_desc = {
.rst_reg = MT7925_CBTOP_RGU_WF_SUBSYS_RST,
.done_reg = MT7925_WFSYS_INIT_DONE_ADDR,
.done_mask = U32_MAX,
.done_val = MT7925_WFSYS_INIT_DONE,
.delay_ms = 20,
.need_status_sel = false,
};
int mt792xu_dma_init(struct mt792x_dev *dev, bool resume)
{
int err;
@@ -236,25 +263,33 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init);
int mt792xu_wfsys_reset(struct mt792x_dev *dev)
{
const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ?
&mt7925_wfsys_desc :
&mt7921_wfsys_desc;
u32 val;
int i;
mt792xu_epctl_rst_opt(dev, false);
val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg);
val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val);
usleep_range(10, 20);
if (desc->delay_ms)
msleep(desc->delay_ms);
else
usleep_range(10, 20);
val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg);
val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val);
if (desc->need_status_sel)
mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0);
mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0);
for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) {
val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS);
if (val & MT_UDMA_CONN_WFSYS_INIT_DONE)
val = mt792xu_uhw_rr(&dev->mt76, desc->done_reg);
if ((val & desc->done_mask) == desc->done_val)
break;
msleep(100);

View File

@@ -226,14 +226,23 @@ mt7996_radar_trigger(void *data, u64 val)
#define RADAR_BACKGROUND 2
struct mt7996_dev *dev = data;
struct mt7996_phy *phy = mt7996_band_phy(dev, NL80211_BAND_5GHZ);
int rdd_idx;
struct cfg80211_chan_def *chandef;
int rdd_idx, ret;
if (!phy || !val || val > RADAR_BACKGROUND)
return -EINVAL;
if (val == RADAR_BACKGROUND && !dev->rdd2_phy) {
dev_err(dev->mt76.dev, "Background radar is not enabled\n");
return -EINVAL;
if (test_bit(MT76_SCANNING, &phy->mt76->state))
return -EBUSY;
if (val == RADAR_BACKGROUND) {
if (!dev->rdd2_phy || !cfg80211_chandef_valid(&dev->rdd2_chandef)) {
dev_err(dev->mt76.dev, "Background radar is not enabled\n");
return -EINVAL;
}
chandef = &dev->rdd2_chandef;
} else {
chandef = &phy->mt76->chandef;
}
rdd_idx = mt7996_get_rdd_idx(phy, val == RADAR_BACKGROUND);
@@ -242,6 +251,11 @@ mt7996_radar_trigger(void *data, u64 val)
return -EINVAL;
}
ret = cfg80211_chandef_dfs_required(dev->mt76.hw->wiphy, chandef,
NL80211_IFTYPE_AP);
if (ret <= 0)
return ret;
return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, rdd_idx, 0);
}
@@ -626,13 +640,18 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_vif *mvif = msta->vif;
struct mt7996_dev *dev = mvif->deflink.phy->dev;
struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink);
struct ieee80211_link_sta *link_sta;
struct seq_file *s = data;
struct ieee80211_vif *vif;
struct mt7996_dev *dev;
unsigned int link_id;
if (!phy)
return;
vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
dev = phy->dev;
rcu_read_lock();
@@ -979,13 +998,17 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file,
#define LONG_PREAMBLE 1
struct ieee80211_link_sta *link_sta = file->private_data;
struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv;
struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
struct mt7996_phy *link_phy = mt7996_vif_link_phy(&msta->vif->deflink);
struct mt7996_sta_link *msta_link;
struct ra_rate phy = {};
struct mt7996_dev *dev;
char buf[100];
int ret;
u16 gi, ltf;
if (!link_phy)
return -EINVAL;
if (count >= sizeof(buf))
return -EINVAL;
@@ -1008,6 +1031,7 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file,
* spe - off: 0, on: 1
* ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2
*/
dev = link_phy->dev;
if (sscanf(buf, "%hhu %hhu %hhu %hhu %hu %hhu %hhu %hhu %hhu %hu",
&phy.mode, &phy.bw, &phy.mcs, &phy.nss, &gi,
&phy.preamble, &phy.stbc, &phy.ldpc, &phy.spe, &ltf) != 10) {

View File

@@ -128,15 +128,27 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
/* data tx queue */
if (is_mt7996(&dev->mt76)) {
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
if (dev->hif2) {
/* default bn1:ring19 bn2:ring21 */
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1,
MT7996_TXQ_BAND1);
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2,
MT7996_TXQ_BAND2);
if (mt76_npu_device_active(&dev->mt76)) {
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND2,
MT7996_TXQ_BAND2);
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND0,
MT7996_TXQ_BAND0);
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1,
MT7996_TXQ_BAND1);
} else {
/* default bn1:ring19 bn2:ring21 */
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0,
MT7996_TXQ_BAND0);
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1,
MT7996_TXQ_BAND1);
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2,
MT7996_TXQ_BAND2);
}
} else {
/* single pcie bn0/1:ring18 bn2:ring19 */
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0,
MT7996_TXQ_BAND0);
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1,
MT7996_TXQ_BAND1);
}
@@ -350,6 +362,9 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset)
if (!mt7996_has_wa(dev) || mt76_npu_device_active(&dev->mt76))
irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) |
MT_INT_RX(MT_RXQ_BAND1_WA));
if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
irq_mask &= ~(MT_INT_RX(MT_RXQ_TXFREE_BAND0) |
MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2));
irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;
mt7996_irq_enable(dev, irq_mask);
@@ -430,39 +445,48 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 |
MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
if (is_mt7996(&dev->mt76))
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
else
if (is_mt7996(&dev->mt76)) {
if (mt76_npu_device_active(&dev->mt76))
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
MT_WFDMA_HOST_CONFIG_BAND0_PCIE1);
else
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
} else {
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
}
/* AXI read outstanding number */
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
(dev->hif2->speed == PCIE_SPEED_5_0GT &&
dev->hif2->width < PCIE_LNK_X2)) {
mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
0x1));
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
0x1));
} else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
(dev->hif2->speed == PCIE_SPEED_8_0GT &&
dev->hif2->width < PCIE_LNK_X2)) {
mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
0x2));
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
0x2));
if (!is_mt7996(&dev->mt76) ||
!mt76_npu_device_active(&dev->mt76)) {
if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
(dev->hif2->speed == PCIE_SPEED_5_0GT &&
dev->hif2->width < PCIE_LNK_X2)) {
mt76_rmw(dev,
WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
0x1));
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
0x1));
} else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
(dev->hif2->speed == PCIE_SPEED_8_0GT &&
dev->hif2->width < PCIE_LNK_X2)) {
mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
0x2));
mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
0x2));
}
}
/* WFDMA rx threshold */
@@ -497,7 +521,7 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
int mt7996_dma_rro_init(struct mt7996_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
u32 irq_mask;
u32 size;
int ret;
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
@@ -524,7 +548,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C],
true);
}
goto start_hw_rro;
return 0;
}
/* ind cmd */
@@ -545,10 +570,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
if (mtk_wed_device_active(&mdev->mmio.wed) &&
mtk_wed_get_rx_capa(&mdev->mmio.wed))
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed;
size = is_mt7996(mdev) && mt76_npu_device_active(mdev)
? MT7996_NPU_RX_RING_SIZE / 4 : MT7996_RX_RING_SIZE;
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0],
MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0),
MT7996_RX_RING_SIZE,
MT7996_RX_MSDU_PAGE_SIZE,
size, MT7996_RX_MSDU_PAGE_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0));
if (ret)
return ret;
@@ -560,10 +587,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
if (mtk_wed_device_active(&mdev->mmio.wed) &&
mtk_wed_get_rx_capa(&mdev->mmio.wed))
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed;
size = is_mt7996(mdev) && mt76_npu_device_active(mdev)
? MT7996_NPU_RX_RING_SIZE / 2 : MT7996_RX_RING_SIZE;
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1],
MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1),
MT7996_RX_RING_SIZE,
MT7996_RX_MSDU_PAGE_SIZE,
size, MT7996_RX_MSDU_PAGE_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1));
if (ret)
return ret;
@@ -576,52 +605,60 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
if (mtk_wed_device_active(&mdev->mmio.wed) &&
mtk_wed_get_rx_capa(&mdev->mmio.wed))
mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed;
size = is_mt7996(mdev) && mt76_npu_device_active(mdev)
? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE;
ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2],
MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2),
MT7996_RX_RING_SIZE,
MT7996_RX_MSDU_PAGE_SIZE,
size, MT7996_RX_MSDU_PAGE_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2));
if (ret)
return ret;
}
start_hw_rro:
if (mtk_wed_device_active(&mdev->mmio.wed)) {
irq_mask = mdev->mmio.irqmask |
return 0;
}
void mt7996_dma_rro_start(struct mt7996_dev *dev)
{
u32 irq_mask;
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
irq_mask = dev->mt76.mmio.irqmask |
MT_INT_TX_DONE_BAND2;
mt76_wr(dev, MT_INT_MASK_CSR, irq_mask);
mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false);
mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, irq_mask,
false);
mt7996_irq_enable(dev, irq_mask);
} else {
if (is_mt7996(&dev->mt76)) {
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1,
mt76_dma_rx_poll);
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2,
mt76_dma_rx_poll);
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2,
mt76_dma_rx_poll);
} else {
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1,
mt76_dma_rx_poll);
}
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll);
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C,
mt76_dma_rx_poll);
} else {
mt76_queue_rx_init(dev, MT_RXQ_RRO_IND,
mt76_dma_rx_poll);
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0,
mt76_dma_rx_poll);
}
if (!mt76_npu_device_active(&dev->mt76))
mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE);
return;
}
return 0;
if (is_mt7996(&dev->mt76)) {
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1,
mt76_dma_rx_poll);
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2,
mt76_dma_rx_poll);
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2,
mt76_dma_rx_poll);
} else {
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1,
mt76_dma_rx_poll);
}
mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll);
if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) {
mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C,
mt76_dma_rx_poll);
} else {
mt76_queue_rx_init(dev, MT_RXQ_RRO_IND,
mt76_dma_rx_poll);
mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0,
mt76_dma_rx_poll);
}
if (!mt76_npu_device_active(&dev->mt76))
mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE);
}
int mt7996_dma_init(struct mt7996_dev *dev)
@@ -642,11 +679,16 @@ int mt7996_dma_init(struct mt7996_dev *dev)
mt7996_dma_disable(dev, true);
/* init tx queue */
ret = mt7996_init_tx_queues(&dev->phy,
MT_TXQ_ID(dev->mphy.band_idx),
MT7996_TX_RING_SIZE,
MT_TXQ_RING_BASE(0),
wed);
if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0),
MT7996_NPU_TX_RING_SIZE,
MT_TXQ_RING_BASE(0) + hif1_ofs,
NULL);
else
ret = mt7996_init_tx_queues(&dev->phy,
MT_TXQ_ID(dev->mphy.band_idx),
MT7996_TX_RING_SIZE,
MT_TXQ_RING_BASE(0), wed);
if (ret)
return ret;
@@ -714,6 +756,9 @@ int mt7996_dma_init(struct mt7996_dev *dev)
(is_mt7992(&dev->mt76)))) {
dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE;
dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed;
} else if (is_mt7992(&dev->mt76) &&
mt76_npu_device_active(&dev->mt76)) {
dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_NPU_Q_TXFREE(0);
}
if (mt7996_has_wa(dev)) {
@@ -846,6 +891,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
/* tx free notify event from WA for band0 */
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE;
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed;
} else if (mt76_npu_device_active(&dev->mt76)) {
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_NPU_Q_TXFREE(0);
}
ret = mt76_queue_alloc(dev,
@@ -859,16 +906,21 @@ int mt7996_dma_init(struct mt7996_dev *dev)
}
if (mt7996_band_valid(dev, MT_BAND2)) {
u32 size;
/* rx rro data queue for band2 */
dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags =
MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN;
if (mtk_wed_device_active(wed) &&
mtk_wed_get_rx_capa(wed))
dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed;
size = is_mt7996(&dev->mt76) &&
mt76_npu_device_active(&dev->mt76)
? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE;
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2],
MT_RXQ_ID(MT_RXQ_RRO_BAND2),
MT7996_RX_RING_SIZE,
MT7996_RX_BUF_SIZE,
size, MT7996_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs);
if (ret)
return ret;

View File

@@ -33,6 +33,8 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev)
if (dev->var.fem == MT7996_FEM_INT)
return MT7992_EEPROM_DEFAULT_23_INT;
return MT7992_EEPROM_DEFAULT_23;
case MT7992_VAR_TYPE_24:
return MT7992_EEPROM_DEFAULT_24;
case MT7992_VAR_TYPE_44:
default:
if (dev->var.fem == MT7996_FEM_INT)
@@ -153,7 +155,7 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default)
dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
dev->flash_mode = true;
dev->eeprom_mode = EEPROM_MODE_DEFAULT_BIN;
out:
release_firmware(fw);
@@ -163,26 +165,31 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default)
static int mt7996_eeprom_load(struct mt7996_dev *dev)
{
u32 eeprom_blk_size, block_num;
bool use_default = false;
int ret;
int ret, i;
ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
if (ret < 0)
return ret;
if (ret && !mt7996_check_eeprom(dev)) {
dev->flash_mode = true;
dev->eeprom_mode = EEPROM_MODE_FLASH;
goto out;
}
if (!dev->flash_mode) {
u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE);
if (mt7996_has_ext_eeprom(dev)) {
/* external eeprom mode */
dev->eeprom_mode = EEPROM_MODE_EXT;
eeprom_blk_size = MT7996_EXT_EEPROM_BLOCK_SIZE;
} else {
u8 free_block_num;
int i;
memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE);
ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num);
/* efuse mode */
dev->eeprom_mode = EEPROM_MODE_EFUSE;
eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
ret = mt7996_mcu_get_efuse_free_block(dev, &free_block_num);
if (ret < 0)
return ret;
@@ -191,27 +198,29 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
use_default = true;
goto out;
}
}
/* check if eeprom data from fw is valid */
if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) ||
mt7996_check_eeprom(dev)) {
/* check if eeprom data from fw is valid */
if (mt7996_mcu_get_eeprom(dev, 0, NULL, eeprom_blk_size,
dev->eeprom_mode) ||
mt7996_check_eeprom(dev)) {
use_default = true;
goto out;
}
/* read eeprom data from fw */
block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
for (i = 1; i < block_num; i++) {
u32 len = eeprom_blk_size;
if (i == block_num - 1)
len = MT7996_EEPROM_SIZE % eeprom_blk_size;
ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size,
NULL, len, dev->eeprom_mode);
if (ret && ret != -EINVAL) {
use_default = true;
goto out;
}
/* read eeprom data from fw */
for (i = 1; i < block_num; i++) {
u32 len = eeprom_blk_size;
if (i == block_num - 1)
len = MT7996_EEPROM_SIZE % eeprom_blk_size;
ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size,
NULL, len);
if (ret && ret != -EINVAL) {
use_default = true;
goto out;
}
}
}
out:
@@ -385,7 +394,8 @@ bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev)
return false;
break;
case MT7992_DEVICE_ID:
if (dev->var.type == MT7992_VAR_TYPE_23)
if (dev->var.type == MT7992_VAR_TYPE_23 ||
dev->var.type == MT7992_VAR_TYPE_24)
return false;
break;
case MT7990_DEVICE_ID: {

View File

@@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = {
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
.beacon_int_min_gcd = 100,
};
static const struct ieee80211_iface_combination if_comb_global_7992 = {
.limits = &if_limits_global,
.n_limits = 1,
.max_interfaces = 32,
.num_different_channels = MT7996_MAX_RADIOS - 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
.beacon_int_min_gcd = 100,
};
static const struct ieee80211_iface_limit if_limits[] = {
@@ -85,6 +99,7 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = {
.extended_capabilities_mask = if_types_ext_capa_ap,
.extended_capabilities_len = sizeof(if_types_ext_capa_ap),
.mld_capa_and_ops =
FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) |
FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS,
MT7996_MAX_RADIOS - 1),
},
@@ -485,7 +500,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
hw->vif_data_size = sizeof(struct mt7996_vif);
hw->chanctx_data_size = sizeof(struct mt76_chanctx);
wiphy->iface_combinations = &if_comb_global;
wiphy->iface_combinations = is_mt7996(&dev->mt76) ? &if_comb_global :
&if_comb_global_7992;
wiphy->n_iface_combinations = 1;
wiphy->radio = dev->radios;
@@ -521,8 +537,10 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR);
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
hw->max_tx_fragments = 4;
wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */
/* init led callbacks */
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
@@ -592,7 +610,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
void mt7996_mac_init(struct mt7996_dev *dev)
{
#define HIF_TXD_V2_1 0x21
int i;
int i, rx_path_type;
mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
@@ -606,11 +624,16 @@ void mt7996_mac_init(struct mt7996_dev *dev)
}
/* rro module init */
if (dev->hif2)
if (dev->hif2) {
if (mt76_npu_device_active(&dev->mt76))
rx_path_type = is_mt7996(&dev->mt76) ? 6 : 8;
else
rx_path_type = is_mt7996(&dev->mt76) ? 2 : 7;
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE,
is_mt7996(&dev->mt76) ? 2 : 7);
else
rx_path_type);
} else {
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0);
}
if (mt7996_has_hwrro(dev)) {
u16 timeout;
@@ -668,8 +691,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
return 0;
if (dev->hif2 &&
((is_mt7996(&dev->mt76) && band == MT_BAND2) ||
(is_mt7992(&dev->mt76) && band == MT_BAND1))) {
((is_mt7992(&dev->mt76) && band == MT_BAND1) ||
(is_mt7996(&dev->mt76) && band == MT_BAND2 &&
!mt76_npu_device_active(&dev->mt76)))) {
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
wed = &dev->mt76.mmio.wed_hif2;
}
@@ -709,14 +733,19 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
/* init wiphy according to mphy and phy */
mt7996_init_wiphy_band(mphy->hw, phy);
if (is_mt7996(&dev->mt76) && !dev->hif2 && band == MT_BAND1) {
if (is_mt7996(&dev->mt76) &&
((band == MT_BAND1 && !dev->hif2) ||
(band == MT_BAND2 && mt76_npu_device_active(&dev->mt76)))) {
int i;
for (i = 0; i <= MT_TXQ_PSD; i++)
mphy->q_tx[i] = dev->mt76.phys[MT_BAND0]->q_tx[0];
mphy->q_tx[i] = dev->mt76.phys[band - 1]->q_tx[0];
} else {
ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band),
MT7996_TX_RING_SIZE,
int size = is_mt7996(&dev->mt76) &&
mt76_npu_device_active(&dev->mt76)
? MT7996_NPU_TX_RING_SIZE / 2 : MT7996_TX_RING_SIZE;
ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), size,
MT_TXQ_RING_BASE(band) + hif1_ofs,
wed);
if (ret)
@@ -756,15 +785,41 @@ static void mt7996_init_work(struct work_struct *work)
mt7996_mcu_set_eeprom(dev);
mt7996_mac_init(dev);
mt7996_txbf_init(dev);
if (!is_mt7990(&dev->mt76))
mt7996_mcu_set_dup_wtbl(dev);
}
void mt7996_wfsys_reset(struct mt7996_dev *dev)
{
mt76_set(dev, MT_WF_SUBSYS_RST, 0x1);
if (!is_mt7990(&dev->mt76)) {
mt76_set(dev, MT_WF_SUBSYS_RST, 0x1);
msleep(20);
mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1);
msleep(20);
return;
}
if (!dev->recovery.hw_full_reset)
return;
mt76_set(dev, MT_WF_SUBSYS_RST,
MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT |
MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT |
MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT);
mt76_rmw(dev, MT_WF_SUBSYS_RST,
MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE,
u32_encode_bits(0x20, MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE));
mt76_clear(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK);
mt76_set(dev, MT_WF_SUBSYS_RST, MT_WF_SUBSYS_RST_WHOLE_PATH_RST);
msleep(20);
mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1);
msleep(20);
if (mt76_poll(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK, 0x1a, 1000))
return;
dev_err(dev->mt76.dev, "wfsys reset fail\n");
}
static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev)
@@ -842,8 +897,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
}
} else {
/* set emul 3.0 function */
mt76_wr(dev, MT_RRO_3_0_EMU_CONF,
MT_RRO_3_0_EMU_CONF_EN_MASK);
mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0,
dev->wed_rro.addr_elem[0].phy_addr);
@@ -935,6 +989,12 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
addr++;
}
if (is_mt7996(&dev->mt76) &&
mt76_npu_device_active(&dev->mt76))
mt76_npu_send_txrx_addr(&dev->mt76, 0, i,
dev->wed_rro.addr_elem[i].phy_addr,
0, 0);
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) {
@@ -995,6 +1055,10 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
addr++;
}
if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
mt76_npu_send_txrx_addr(&dev->mt76, 1, 0,
dev->wed_rro.session.phy_addr, 0, 0);
mt7996_rro_hw_init(dev);
return mt7996_dma_rro_init(dev);
@@ -1081,8 +1145,12 @@ static void mt7996_wed_rro_work(struct work_struct *work)
list);
list_del_init(&e->list);
if (mt76_npu_device_active(&dev->mt76))
if (mt76_npu_device_active(&dev->mt76)) {
if (is_mt7996(&dev->mt76))
mt76_npu_send_txrx_addr(&dev->mt76, 3, e->id,
0, 0, 0);
goto reset_session;
}
for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
void *ptr = dev->wed_rro.session.ptr;
@@ -1129,7 +1197,7 @@ static int mt7996_variant_type_init(struct mt7996_dev *dev)
else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992))
var_type = MT7992_VAR_TYPE_44;
else
return -EINVAL;
var_type = MT7992_VAR_TYPE_24;
break;
case MT7990_DEVICE_ID:
var_type = MT7990_VAR_TYPE_23;
@@ -1163,7 +1231,8 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev)
if (ret)
return ret;
ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf));
ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf),
EEPROM_MODE_EFUSE);
if (ret && ret != -EINVAL)
return ret;
@@ -1696,6 +1765,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
if (ret)
return ret;
mt7996_dma_rro_start(dev);
ret = mt76_register_device(&dev->mt76, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
@@ -1726,6 +1797,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
void mt7996_unregister_device(struct mt7996_dev *dev)
{
cancel_work_sync(&dev->dump_work);
cancel_work_sync(&dev->wed_rro.work);
mt7996_unregister_phy(mt7996_phy3(dev));
mt7996_unregister_phy(mt7996_phy2(dev));

View File

@@ -13,45 +13,6 @@
#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
[5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 },
[6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 },
[7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 },
[8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 },
[9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
[10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
[11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 },
[12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 },
},
};
static const struct mt7996_dfs_radar_spec fcc_radar_specs = {
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
[0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 },
[1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 },
[2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 },
[3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 },
[4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 },
},
};
static const struct mt7996_dfs_radar_spec jp_radar_specs = {
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
[0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 },
[1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 },
[2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 },
[3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 },
[4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 },
[13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 },
[14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 },
[15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 },
},
};
static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
u16 idx, u8 band_idx)
{
@@ -527,7 +488,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
!(csum_status & (BIT(0) | BIT(2) | BIT(3))))
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
if (rxd3 & MT_RXD3_NORMAL_FCS_ERR)
status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
@@ -700,6 +661,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
hdr = mt76_skb_get_hdr(skb);
fc = hdr->frame_control;
if (ieee80211_is_beacon(fc))
mt76_rx_beacon(mphy, skb);
if (ieee80211_is_data_qos(fc)) {
u8 *qos = ieee80211_get_qos_ctl(hdr);
@@ -1139,10 +1102,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
* req
*/
if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) {
u32 val;
u32 val, mac_txp_size = sizeof(struct mt76_connac_hw_txp);
ptr = (__le32 *)(txwi + MT_TXD_SIZE);
memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp));
memset((void *)ptr, 0, mac_txp_size);
val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) |
MT_TXP0_TOKEN_ID0_VALID_MASK;
@@ -1161,6 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
tx_info->buf[1].addr >> 32);
#endif
ptr[3] = cpu_to_le32(val);
tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size;
} else {
struct mt76_connac_txp_common *txp;
@@ -1270,8 +1235,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta,
if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
return;
if (!test_and_set_bit(tid, &wcid->ampdu_state))
ieee80211_start_tx_ba_session(link_sta->sta, tid, 0);
if (!test_and_set_bit(tid, &wcid->ampdu_state) &&
ieee80211_start_tx_ba_session(link_sta->sta, tid, 0))
clear_bit(tid, &wcid->ampdu_state);
}
static void
@@ -2203,9 +2169,14 @@ mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
for_each_vif_active_link(vif, link_conf, link_id) {
struct mt7996_vif_link *link;
struct mt7996_phy *link_phy;
link = mt7996_vif_link(dev, vif, link_id);
if (!link || link->phy != phy)
if (!link)
continue;
link_phy = mt7996_vif_link_phy(link);
if (link_phy != phy)
continue;
mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf,
@@ -2248,6 +2219,12 @@ void mt7996_tx_token_put(struct mt7996_dev *dev)
}
spin_unlock_bh(&dev->mt76.token_lock);
idr_destroy(&dev->mt76.token);
for (id = 0; id < __MT_MAX_BAND; id++) {
struct mt76_phy *phy = dev->mt76.phys[id];
if (phy)
atomic_set(&phy->mgmt_tx_pending, 0);
}
}
static int
@@ -2395,23 +2372,8 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta)
struct mt7996_dev *dev = data;
int i;
for (i = 0; i < ARRAY_SIZE(msta->link); i++) {
struct mt7996_sta_link *msta_link = NULL;
msta_link = rcu_replace_pointer(msta->link[i], msta_link,
lockdep_is_held(&dev->mt76.mutex));
if (!msta_link)
continue;
mt7996_mac_sta_deinit_link(dev, msta_link);
if (msta->deflink_id == i) {
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
continue;
}
kfree_rcu(msta_link, rcu_head);
}
for (i = 0; i < ARRAY_SIZE(msta->link); i++)
mt7996_mac_sta_remove_link(dev, sta, i, true);
}
static void
@@ -2544,6 +2506,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
if (mtk_wed_device_active(&dev->mt76.mmio.wed))
mtk_wed_device_stop(&dev->mt76.mmio.wed);
mt7996_npu_hw_stop(dev);
ieee80211_stop_queues(mt76_hw(dev));
set_bit(MT76_RESET, &dev->mphy.state);
@@ -2564,14 +2527,19 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
continue;
if (mt76_npu_device_active(&dev->mt76) &&
mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
continue;
if (mt76_queue_is_npu_txfree(&dev->mt76.q_rx[i]))
continue;
napi_disable(&dev->mt76.napi[i]);
}
napi_disable(&dev->mt76.tx_napi);
mutex_lock(&dev->mt76.mutex);
mt7996_npu_hw_stop(dev);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
@@ -2591,7 +2559,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt7996_dma_start(dev, false, false);
if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3)
mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 |
@@ -2610,6 +2578,8 @@ void mt7996_mac_reset_work(struct work_struct *work)
MT_INT_TX_RX_DONE_EXT);
}
__mt7996_npu_hw_init(dev);
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
mt7996_for_each_phy(dev, phy)
clear_bit(MT76_RESET, &phy->mt76->state);
@@ -2619,6 +2589,13 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
continue;
if (mt76_npu_device_active(&dev->mt76) &&
mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
continue;
if (mt76_queue_is_npu_txfree(&dev->mt76.q_rx[i]))
continue;
napi_enable(&dev->mt76.napi[i]);
local_bh_disable();
napi_schedule(&dev->mt76.napi[i]);
@@ -2639,8 +2616,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
mutex_unlock(&dev->mt76.mutex);
mt7996_npu_hw_init(dev);
mt7996_for_each_phy(dev, phy)
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
MT7996_WATCHDOG_TIME);
@@ -2737,6 +2712,11 @@ void mt7996_reset(struct mt7996_dev *dev)
return;
}
if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) {
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
}
queue_work(dev->mt76.wq, &dev->reset_work);
wake_up(&dev->reset_wait);
}
@@ -2955,6 +2935,7 @@ void mt7996_mac_work(struct work_struct *work)
mutex_unlock(&mphy->dev->mutex);
mt76_beacon_mon_check(mphy);
mt76_tx_status_check(mphy->dev, false);
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
@@ -2974,7 +2955,7 @@ static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx)
{
int err, region;
int region;
switch (dev->mt76.region) {
case NL80211_DFS_ETSI:
@@ -2989,11 +2970,7 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx)
break;
}
err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);
if (err < 0)
return err;
return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1);
return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);
}
static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
@@ -3015,40 +2992,6 @@ static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
return err;
}
static int
mt7996_dfs_init_radar_specs(struct mt7996_phy *phy)
{
const struct mt7996_dfs_radar_spec *radar_specs;
struct mt7996_dev *dev = phy->dev;
int err, i;
switch (dev->mt76.region) {
case NL80211_DFS_FCC:
radar_specs = &fcc_radar_specs;
err = mt7996_mcu_set_fcc5_lpn(dev, 8);
if (err < 0)
return err;
break;
case NL80211_DFS_ETSI:
radar_specs = &etsi_radar_specs;
break;
case NL80211_DFS_JP:
radar_specs = &jp_radar_specs;
break;
default:
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
err = mt7996_mcu_set_radar_th(dev, i,
&radar_specs->radar_pattern[i]);
if (err < 0)
return err;
}
return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
}
int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
{
struct mt7996_dev *dev = phy->dev;
@@ -3068,10 +3011,6 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
goto stop;
if (prev_state <= MT_DFS_STATE_DISABLED) {
err = mt7996_dfs_init_radar_specs(phy);
if (err < 0)
return err;
err = mt7996_dfs_start_radar_detector(phy);
if (err < 0)
return err;

View File

@@ -37,9 +37,4 @@ struct mt7996_dfs_pattern {
u32 min_stgpr_diff;
} __packed;
struct mt7996_dfs_radar_spec {
struct mt7996_dfs_pulse pulse_th;
struct mt7996_dfs_pattern radar_pattern[16];
};
#endif

View File

@@ -56,7 +56,7 @@ static int mt7996_start(struct ieee80211_hw *hw)
mutex_lock(&dev->mt76.mutex);
ret = mt7996_mcu_set_hdr_trans(dev, true);
if (!ret && is_mt7992(&dev->mt76)) {
if (!ret && !is_mt7996(&dev->mt76)) {
u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI);
ret = mt7996_mcu_cp_support(dev, queue);
@@ -79,6 +79,7 @@ static void mt7996_stop_phy(struct mt7996_phy *phy)
mutex_lock(&dev->mt76.mutex);
mt7996_mcu_rdd_resume_tx(phy);
mt7996_mcu_set_radio_en(phy, false);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
@@ -238,10 +239,13 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
link_conf = &vif->bss_conf;
if (cmd == SET_KEY && !sta && !link->mt76.cipher) {
struct mt7996_phy *phy = mt7996_vif_link_phy(link);
link->mt76.cipher =
mt76_connac_mcu_get_cipher(key->cipher);
mt7996_mcu_add_bss_info(link->phy, vif, link_conf,
&link->mt76, msta_link, true);
if (phy)
mt7996_mcu_add_bss_info(phy, vif, link_conf,
&link->mt76, msta_link, true);
}
if (cmd == SET_KEY)
@@ -300,9 +304,16 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
.cmd = SET_KEY,
.link_id = link_conf->link_id,
};
struct mt76_txq *mtxq;
int mld_idx, idx, ret;
if ((mvif->mt76.valid_links & BIT(link_conf->link_id)) &&
!mlink->offchannel) {
if (vif->type == NL80211_IFTYPE_AP)
return mt7996_mcu_mld_link_oper(dev, link_conf, link,
true);
return 0;
}
mlink->idx = __ffs64(~dev->mt76.vif_mask);
if (mlink->idx >= mt7996_max_interface_num(dev))
return -ENOSPC;
@@ -316,7 +327,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
return -ENOSPC;
link->mld_idx = mld_idx;
link->phy = phy;
mlink->omac_idx = idx;
mlink->band_idx = band_idx;
mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3;
@@ -343,11 +353,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
mt7996_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
if (vif->txq) {
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = idx;
}
if (vif->type != NL80211_IFTYPE_AP &&
(!mlink->omac_idx || mlink->omac_idx > 3))
vif->offload_flags = 0;
@@ -370,13 +375,81 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
if (!mlink->wcid->offchannel &&
mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED)
mvif->mt76.deflink_id = link_conf->link_id;
if (!mlink->wcid->offchannel) {
if (vif->txq &&
mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) {
struct mt76_txq *mtxq;
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mvif->mt76.deflink_id = link_conf->link_id;
mtxq->wcid = idx;
}
mvif->mt76.valid_links |= BIT(link_conf->link_id);
}
if (vif->type == NL80211_IFTYPE_STATION) {
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
if (vif->cfg.assoc && link_conf->beacon_int) {
mlink->beacon_mon_interval =
msecs_to_jiffies(ieee80211_tu_to_usec(
link_conf->beacon_int) / 1000);
WRITE_ONCE(mlink->beacon_mon_last, jiffies);
}
}
return 0;
}
static void mt7996_vif_link_destroy(struct mt7996_phy *phy,
struct mt7996_vif_link *link,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_sta_link *msta_link = &link->msta_link;
unsigned int link_id = msta_link->wcid.link_id;
struct mt76_vif_link *mlink = &link->mt76;
struct mt7996_key_iter_data it = {
.cmd = SET_KEY,
.link_id = link_id,
};
struct mt7996_dev *dev = phy->dev;
int idx = msta_link->wcid.idx;
if (!link_conf)
link_conf = &vif->bss_conf;
if (!mlink->wcid->offchannel)
ieee80211_iter_keys(phy->mt76->hw, vif, mt7996_key_iter, &it);
mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL,
CONN_STATE_DISCONNECT, false);
mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false);
mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx);
dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx);
phy->omac_mask &= ~BIT_ULL(mlink->omac_idx);
if (!mlink->wcid->offchannel)
mvif->mt76.valid_links &= ~BIT(link_id);
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (!list_empty(&msta_link->wcid.poll_list))
list_del_init(&msta_link->wcid.poll_list);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid);
if (mlink != (struct mt76_vif_link *)vif->drv_priv &&
!mlink->wcid->offchannel) {
rcu_assign_pointer(mlink->mvif->link[link_id], NULL);
kfree_rcu(mlink, rcu_head);
}
}
void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink)
@@ -384,49 +457,43 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76);
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_sta_link *msta_link = &link->msta_link;
unsigned int link_id = msta_link->wcid.link_id;
struct mt7996_phy *phy = mphy->priv;
struct mt7996_dev *dev = phy->dev;
struct mt7996_key_iter_data it = {
.cmd = SET_KEY,
.link_id = link_conf->link_id,
};
int idx = msta_link->wcid.idx;
if (!mlink->wcid->offchannel)
ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);
/* Hw requires to destroy active links tearing down the interface, so
* postpone it removing the interface.
*/
if (mlink->wcid->offchannel) {
mt7996_vif_link_destroy(phy, link, vif, link_conf);
} else {
if (vif->type == NL80211_IFTYPE_AP) {
mt7996_mcu_mld_reconf_stop_link(phy->dev, vif,
BIT(link_id));
mt7996_mcu_mld_link_oper(phy->dev, link_conf, link,
false);
}
mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL,
CONN_STATE_DISCONNECT, false);
mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false);
if (vif->txq && mvif->mt76.deflink_id == link_id) {
struct ieee80211_bss_conf *iter;
struct mt76_txq *mtxq;
mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false);
mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED;
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
/* Primary link will be removed, look for a new one */
for_each_vif_active_link(vif, iter, link_id) {
if (link_id == msta_link->wcid.link_id)
continue;
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
link = mt7996_vif_link(phy->dev, vif, link_id);
if (!link)
continue;
if (!mlink->wcid->offchannel &&
mvif->mt76.deflink_id == link_conf->link_id) {
struct ieee80211_bss_conf *iter;
unsigned int link_id;
mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED;
for_each_vif_active_link(vif, iter, link_id) {
if (link_id != IEEE80211_LINK_UNSPECIFIED) {
mtxq->wcid = link->msta_link.wcid.idx;
mvif->mt76.deflink_id = link_id;
break;
}
}
}
dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx);
dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx);
phy->omac_mask &= ~BIT_ULL(mlink->omac_idx);
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (!list_empty(&msta_link->wcid.poll_list))
list_del_init(&msta_link->wcid.poll_list);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid);
}
static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy)
@@ -472,6 +539,8 @@ static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled)
mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx),
MT_DMA_DCR0_RXD_G5_EN, enabled);
mt76_rmw_field(dev, MT_MDP_DCR0,
MT_MDP_DCR0_RX_HDR_TRANS_EN, !enabled);
mt7996_phy_set_rxfilter(phy);
mt7996_mcu_set_sniffer_mode(phy, enabled);
}
@@ -530,10 +599,29 @@ static void mt7996_remove_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
static void mt7996_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
unsigned long rem_links = mvif->mt76.valid_links;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_radio_data rdata = {};
unsigned int link_id;
int i;
/* Remove all active links */
for_each_set_bit(link_id, &rem_links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_vif_link *link;
struct mt7996_phy *phy;
link = mt7996_vif_link(dev, vif, link_id);
if (!link)
continue;
phy = __mt7996_phy(dev, link->msta_link.wcid.phy_idx);
if (!phy)
continue;
mt7996_vif_link_destroy(phy, link, vif, NULL);
}
ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter,
&rdata);
mt76_vif_cleanup(&dev->mt76, vif);
@@ -811,15 +899,24 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
for_each_vif_active_link(vif, link_conf, link_id) {
struct mt7996_vif_link *link;
struct mt7996_phy *phy;
link = mt7996_vif_link(dev, vif, link_id);
if (!link)
continue;
if (!link->phy)
if (vif->type == NL80211_IFTYPE_STATION) {
link->mt76.beacon_mon_interval =
msecs_to_jiffies(ieee80211_tu_to_usec(
link_conf->beacon_int) / 1000);
WRITE_ONCE(link->mt76.beacon_mon_last, jiffies);
}
phy = mt7996_vif_link_phy(link);
if (!phy)
continue;
mt7996_mcu_add_bss_info(link->phy, vif, link_conf,
mt7996_mcu_add_bss_info(phy, vif, link_conf,
&link->mt76, &link->msta_link,
true);
mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL,
@@ -828,6 +925,20 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
}
if ((changed & BSS_CHANGED_ASSOC) && !vif->cfg.assoc &&
vif->type == NL80211_IFTYPE_STATION) {
struct ieee80211_bss_conf *link_conf;
unsigned long link_id;
for_each_vif_active_link(vif, link_conf, link_id) {
struct mt7996_vif_link *link;
link = mt7996_vif_link(dev, vif, link_id);
if (link)
link->mt76.beacon_mon_interval = 0;
}
}
mutex_unlock(&dev->mt76.mutex);
}
@@ -864,6 +975,10 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
!!(changed & BSS_CHANGED_BSSID));
}
if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
mt7996_mcu_set_protection(phy, link, info->ht_operation_mode,
info->use_cts_prot);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = info->use_short_slot ? 9 : 20;
@@ -927,12 +1042,84 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
struct cfg80211_chan_def *chandef)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band);
struct ieee80211_bss_conf *link_conf;
unsigned int link_id;
mutex_lock(&dev->mt76.mutex);
mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf, vif->bss_conf.enable_beacon);
for_each_vif_active_link(vif, link_conf, link_id) {
struct mt7996_vif_link *link;
struct mt7996_phy *link_phy;
link = mt7996_vif_link(dev, vif, link_id);
if (!link)
continue;
link_phy = mt7996_vif_link_phy(link);
if (link_phy != phy)
continue;
/* Reset beacon when channel switch triggered during CAC to let
* FW correctly perform CSA countdown
*/
if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef,
vif->type))
mt7996_mcu_add_beacon(hw, vif, link_conf, false);
mt7996_mcu_add_beacon(hw, vif, link_conf, true);
break;
}
mutex_unlock(&dev->mt76.mutex);
}
static int
mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band);
struct mt7996_vif_link *link;
int ret = -EINVAL;
mutex_lock(&dev->mt76.mutex);
link = mt7996_vif_conf_link(dev, vif, link_conf);
if (!link)
goto out;
ret = mt7996_mcu_update_bss_rfch(phy, link);
if (ret)
goto out;
ieee80211_iterate_stations_mtx(hw, mt7996_mcu_update_sta_rec_bw, link);
ret = mt7996_mcu_rdd_resume_tx(phy);
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void
mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
struct mt76_txq *mtxq;
if (!sta->txq[i])
continue;
mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
mtxq->wcid = idx;
}
}
static int
mt7996_mac_sta_init_link(struct mt7996_dev *dev,
struct ieee80211_bss_conf *link_conf,
@@ -941,30 +1128,22 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
{
struct ieee80211_sta *sta = link_sta->sta;
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_phy *phy = link->phy;
struct mt7996_phy *phy = mt7996_vif_link_phy(link);
struct mt7996_sta_link *msta_link;
int idx;
if (!phy)
return -EINVAL;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
if (idx < 0)
return -ENOSPC;
if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) {
int i;
msta_link = &msta->deflink;
msta->deflink_id = link_id;
msta->seclink_id = msta->deflink_id;
for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
struct mt76_txq *mtxq;
if (!sta->txq[i])
continue;
mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
mtxq->wcid = idx;
}
mt7996_sta_init_txq_wcid(sta, idx);
} else {
msta_link = kzalloc_obj(*msta_link);
if (!msta_link)
@@ -1000,9 +1179,17 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
return 0;
}
void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link)
void mt7996_mac_sta_remove_link(struct mt7996_dev *dev,
struct ieee80211_sta *sta,
unsigned int link_id, bool flush)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_sta_link *msta_link;
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
if (!msta_link)
return;
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (!list_empty(&msta_link->wcid.poll_list))
list_del_init(&msta_link->wcid.poll_list);
@@ -1011,49 +1198,59 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid);
mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx);
}
static void
mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long links)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt76_dev *mdev = &dev->mt76;
unsigned int link_id;
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link = NULL;
struct mt7996_vif_link *link;
struct mt76_phy *mphy;
msta_link = rcu_replace_pointer(msta->link[link_id], msta_link,
lockdep_is_held(&mdev->mutex));
if (!msta_link)
continue;
if (msta_link->wcid.link_valid) {
struct mt7996_phy *phy;
mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
mt7996_mac_sta_deinit_link(dev, msta_link);
link = mt7996_vif_link(dev, vif, link_id);
if (!link)
continue;
phy = __mt7996_phy(dev, msta_link->wcid.phy_idx);
if (phy)
phy->mt76->num_sta--;
mphy = mt76_vif_link_phy(&link->mt76);
if (!mphy)
continue;
mphy->num_sta--;
if (msta->deflink_id == link_id) {
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
continue;
} else if (msta->seclink_id == link_id) {
msta->seclink_id = IEEE80211_LINK_UNSPECIFIED;
}
if (msta->seclink_id == link_id) {
/* no secondary link available */
msta->seclink_id = msta->deflink_id;
} else {
struct mt7996_sta_link *msta_seclink;
kfree_rcu(msta_link, rcu_head);
/* switch to the secondary link */
msta_seclink = mt76_dereference(
msta->link[msta->seclink_id],
&dev->mt76);
if (msta_seclink) {
msta->deflink_id = msta->seclink_id;
mt7996_sta_init_txq_wcid(sta,
msta_seclink->wcid.idx);
}
}
} else if (msta->seclink_id == link_id) {
msta->seclink_id = msta->deflink_id;
}
msta_link->wcid.link_valid = false;
}
if (flush) {
rcu_assign_pointer(msta->link[link_id], NULL);
rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL);
mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx);
if (msta_link != &msta->deflink)
kfree_rcu(msta_link, rcu_head);
}
}
static void
mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long links,
bool flush)
{
unsigned int link_id;
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS)
mt7996_mac_sta_remove_link(dev, sta, link_id, flush);
}
static int
@@ -1067,11 +1264,15 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_bss_conf *link_conf;
struct ieee80211_link_sta *link_sta;
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
struct mt76_phy *mphy;
if (rcu_access_pointer(msta->link[link_id]))
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
if (msta_link) {
msta_link->wcid.link_valid = true;
continue;
}
link_conf = link_conf_dereference_protected(vif, link_id);
if (!link_conf) {
@@ -1108,7 +1309,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
return 0;
error_unlink:
mt7996_mac_sta_remove_links(dev, vif, sta, new_links);
mt7996_mac_sta_remove_links(dev, vif, sta, new_links, true);
return err;
}
@@ -1125,7 +1326,7 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_lock(&dev->mt76.mutex);
mt7996_mac_sta_remove_links(dev, vif, sta, rem);
mt7996_mac_sta_remove_links(dev, vif, sta, rem, false);
ret = mt7996_mac_sta_add_links(dev, vif, sta, add);
mutex_unlock(&dev->mt76.mutex);
@@ -1234,10 +1435,12 @@ static void
mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
unsigned long links = sta->valid_links ? sta->valid_links : BIT(0);
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
int i;
mutex_lock(&dev->mt76.mutex);
mt7996_mac_sta_remove_links(dev, vif, sta, links);
for (i = 0; i < ARRAY_SIZE(msta->link); i++)
mt7996_mac_sta_remove_link(dev, sta, i, true);
mutex_unlock(&dev->mt76.mutex);
}
@@ -1489,8 +1692,8 @@ mt7996_get_stats(struct ieee80211_hw *hw,
u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link)
{
struct mt7996_phy *phy = mt7996_vif_link_phy(link);
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = link->phy;
union {
u64 t64;
u32 t32[2];
@@ -1549,7 +1752,7 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
: link->mt76.omac_idx;
phy = link->phy;
phy = mt7996_vif_link_phy(link);
if (!phy)
goto unlock;
@@ -1583,7 +1786,7 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!link)
goto unlock;
phy = link->phy;
phy = mt7996_vif_link_phy(link);
if (!phy)
goto unlock;
@@ -1713,9 +1916,14 @@ static void mt7996_link_rate_ctrl_update(void *data,
struct mt7996_sta_link *msta_link)
{
struct mt7996_sta *msta = msta_link->sta;
struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
struct mt7996_phy *phy = mt7996_vif_link_phy(&msta->vif->deflink);
struct mt7996_dev *dev;
u32 *changed = data;
if (!phy)
return;
dev = phy->dev;
spin_lock_bh(&dev->mt76.sta_poll_lock);
msta_link->changed |= *changed;
@@ -2204,6 +2412,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
path->mtk_wdma.wdma_idx = wed->wdma_idx;
else
#endif
if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76) &&
msta_link->wcid.phy_idx == MT_BAND2)
path->mtk_wdma.wdma_idx = 1;
else
path->mtk_wdma.wdma_idx = link->mt76.band_idx;
path->mtk_wdma.bss = link->mt76.idx;
path->mtk_wdma.queue = 0;
@@ -2275,6 +2487,21 @@ mt7996_reconfig_complete(struct ieee80211_hw *hw,
MT7996_WATCHDOG_TIME);
}
static int
mt7996_set_eml_op_mode(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_eml_params *eml_params)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
int ret;
mutex_lock(&dev->mt76.mutex);
ret = mt7996_mcu_set_emlsr_mode(dev, vif, sta, eml_params);
mutex_unlock(&dev->mt76.mutex);
return ret;
}
const struct ieee80211_ops mt7996_ops = {
.add_chanctx = mt76_add_chanctx,
.remove_chanctx = mt76_remove_chanctx,
@@ -2306,6 +2533,7 @@ const struct ieee80211_ops mt7996_ops = {
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt7996_get_txpower,
.channel_switch_beacon = mt7996_channel_switch_beacon,
.post_channel_switch = mt7996_post_channel_switch,
.get_stats = mt7996_get_stats,
.get_et_sset_count = mt7996_get_et_sset_count,
.get_et_stats = mt7996_get_et_stats,
@@ -2337,4 +2565,5 @@ const struct ieee80211_ops mt7996_ops = {
.change_vif_links = mt7996_change_vif_links,
.change_sta_links = mt7996_mac_sta_change_links,
.reconfig_complete = mt7996_reconfig_complete,
.set_eml_op_mode = mt7996_set_eml_op_mode,
};

File diff suppressed because it is too large Load Diff

View File

@@ -25,8 +25,8 @@ struct mt7996_mcu_rxd {
};
struct mt7996_mcu_uni_event {
u8 cid;
u8 __rsv[3];
__le16 cid;
u8 __rsv[2];
__le32 status; /* 0: success, others: fail */
} __packed;
@@ -52,12 +52,10 @@ struct mt7996_mcu_thermal_enable {
u8 rsv[2];
} __packed;
struct mt7996_mcu_csa_notify {
struct mt7996_mcu_rxd rxd;
struct mt7996_mcu_countdown_notify {
u8 omac_idx;
u8 csa_count;
u8 band_idx;
u8 count;
u8 csa_failure_reason; /* 0: success, 1: beacon disabled */
u8 rsv;
} __packed;
@@ -147,7 +145,7 @@ struct mt7996_mcu_background_chain_ctrl {
u8 rsv[2];
} __packed;
struct mt7996_mcu_eeprom {
struct mt7996_mcu_eeprom_update {
u8 _rsv[4];
__le16 tag;
@@ -157,6 +155,43 @@ struct mt7996_mcu_eeprom {
__le16 buf_len;
} __packed;
union eeprom_data {
struct {
__le32 data_len;
DECLARE_FLEX_ARRAY(u8, data);
} ext_eeprom;
DECLARE_FLEX_ARRAY(u8, efuse);
} __packed;
struct mt7996_mcu_eeprom_info {
u8 _rsv[4];
__le16 tag;
__le16 len;
__le32 addr;
__le32 valid;
} __packed;
struct mt7996_mcu_eeprom_access {
struct mt7996_mcu_eeprom_info info;
union eeprom_data eeprom;
} __packed;
struct mt7996_mcu_eeprom_access_event {
u8 _rsv[4];
__le16 tag;
__le16 len;
__le32 version;
__le32 addr;
__le32 valid;
__le32 size;
__le32 magic_no;
__le32 type;
__le32 rsv[4];
union eeprom_data eeprom;
} __packed;
struct mt7996_mcu_phy_rx_info {
u8 category;
u8 rate;
@@ -414,7 +449,16 @@ struct bss_bcn_cntdwn_tlv {
__le16 tag;
__le16 len;
u8 cnt;
u8 rsv[3];
union {
struct {
bool static_pp;
bool abort;
} csa;
struct {
bool abort;
} cca;
};
u8 rsv;
} __packed;
struct bss_bcn_mbss_tlv {
@@ -474,6 +518,24 @@ struct bss_mld_tlv {
u8 __rsv[2];
} __packed;
struct bss_prot_tlv {
__le16 tag;
__le16 len;
__le32 prot_mode;
} __packed;
struct bss_mld_link_op_tlv {
__le16 tag;
__le16 len;
u8 group_mld_id;
u8 own_mld_id;
u8 mac_addr[ETH_ALEN];
u8 remap_idx;
u8 link_operation;
u8 link_id;
u8 rsv[2];
} __packed;
struct sta_rec_ht_uni {
__le16 tag;
__le16 len;
@@ -647,6 +709,28 @@ struct mld_setup_link {
u8 __rsv;
} __packed;
struct mld_req_hdr {
u8 ver;
u8 mld_addr[ETH_ALEN];
u8 mld_idx;
u8 flag;
u8 rsv[3];
u8 buf[];
} __packed;
struct mld_reconf_stop_link {
__le16 tag;
__le16 len;
__le16 link_bitmap;
u8 rsv[2];
u8 bss_idx[16];
} __packed;
enum {
UNI_CMD_MLD_RECONF_AP_REM_TIMER = 0x03,
UNI_CMD_MLD_RECONF_STOP_LINK = 0x04,
};
struct hdr_trans_en {
__le16 tag;
__le16 len;
@@ -791,6 +875,11 @@ enum {
UNI_CHANNEL_RX_PATH,
};
enum {
UNI_CHIP_CONFIG_NIC_CAPA = 3,
UNI_CHIP_CONFIG_DUP_WTBL = 4,
};
#define MT7996_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \
sizeof(struct mt76_connac_bss_basic_tlv) + \
sizeof(struct bss_rlm_tlv) + \
@@ -837,6 +926,7 @@ enum {
enum {
UNI_BAND_CONFIG_RADIO_ENABLE,
UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c,
};
enum {
@@ -856,6 +946,10 @@ enum {
UNI_EFUSE_BUFFER_RD,
};
enum {
UNI_EXT_EEPROM_ACCESS = 1,
};
enum {
UNI_VOW_DRR_CTRL,
UNI_VOW_RX_AT_AIRTIME_EN = 0x0b,

View File

@@ -29,6 +29,10 @@
#define MT7996_RX_RING_SIZE 1536
#define MT7996_RX_MCU_RING_SIZE 512
#define MT7996_RX_MCU_RING_SIZE_WA 1024
#define MT7996_NPU_TX_RING_SIZE 1024
#define MT7996_NPU_RX_RING_SIZE 1024
#define MT7996_NPU_TXD_SIZE 3
/* scatter-gather of mcu event is not supported in connac3 */
#define MT7996_RX_MCU_BUF_SIZE (2048 + \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
@@ -60,6 +64,11 @@
#define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin"
#define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin"
#define MT7992_FIRMWARE_WA_24 "mediatek/mt7996/mt7992_wa_24.bin"
#define MT7992_FIRMWARE_WM_24 "mediatek/mt7996/mt7992_wm_24.bin"
#define MT7992_FIRMWARE_DSP_24 "mediatek/mt7996/mt7992_dsp_24.bin"
#define MT7992_ROM_PATCH_24 "mediatek/mt7996/mt7992_rom_patch_24.bin"
#define MT7990_FIRMWARE_WA ""
#define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin"
#define MT7990_FIRMWARE_DSP ""
@@ -75,12 +84,14 @@
#define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin"
#define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin"
#define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin"
#define MT7992_EEPROM_DEFAULT_24 "mediatek/mt7996/mt7992_eeprom_24_2i5i.bin"
#define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin"
#define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin"
#define MT7996_EEPROM_SIZE 7680
#define MT7996_EEPROM_BLOCK_SIZE 16
#define MT7996_EXT_EEPROM_BLOCK_SIZE 1024
#define MT7996_TOKEN_SIZE 16384
#define MT7996_HW_TOKEN_SIZE 8192
@@ -153,6 +164,7 @@ enum mt7996_var_type {
enum mt7992_var_type {
MT7992_VAR_TYPE_44,
MT7992_VAR_TYPE_23,
MT7992_VAR_TYPE_24,
};
enum mt7990_var_type {
@@ -165,6 +177,18 @@ enum mt7996_fem_type {
MT7996_FEM_MIX,
};
enum mt7996_eeprom_mode {
EEPROM_MODE_DEFAULT_BIN,
EEPROM_MODE_EFUSE,
EEPROM_MODE_FLASH,
EEPROM_MODE_EXT,
};
#define MT7996_EFUSE_BASE_OFFS_ADIE0 0x400
#define MT7996_EFUSE_BASE_OFFS_ADIE1 0x1e00
#define MT7996_EFUSE_BASE_OFFS_ADIE2 0x1200
#define MT7992_EFUSE_BASE_OFFS_ADIE1 0x1200
enum mt7996_txq_id {
MT7996_TXQ_FWDL = 16,
MT7996_TXQ_MCU_WM,
@@ -252,8 +276,6 @@ struct mt7996_vif_link {
struct mt76_vif_link mt76; /* must be first */
struct mt7996_sta_link msta_link;
struct mt7996_phy *phy;
struct cfg80211_bitrate_mask bitrate_mask;
u8 mld_idx;
@@ -377,6 +399,7 @@ struct mt7996_phy {
bool has_aux_rx;
bool counter_reset;
bool rdd_tx_paused;
};
struct mt7996_dev {
@@ -436,7 +459,7 @@ struct mt7996_dev {
u32 hw_pattern;
bool flash_mode:1;
u8 eeprom_mode;
bool has_eht:1;
struct {
@@ -473,6 +496,8 @@ struct mt7996_dev {
struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE];
} wed_rro;
dma_addr_t npu_txd_addr[2 * MT7996_NPU_TXD_SIZE];
bool ibf;
u8 fw_debug_wm;
u8 fw_debug_wa;
@@ -669,6 +694,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink,
struct mt7996_sta_link *msta_link, int enable);
int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy,
struct mt7996_vif_link *link);
int mt7996_mcu_add_sta(struct mt7996_dev *dev,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
@@ -678,6 +705,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev,
int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link);
void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta);
int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
struct ieee80211_ampdu_params *params,
struct ieee80211_vif *vif, bool enable);
@@ -707,8 +735,9 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
void *data, u8 link_id, u32 field);
int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len);
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len,
enum mt7996_eeprom_mode mode);
int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num);
int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap);
int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band);
int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action);
@@ -719,6 +748,8 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
const struct mt7996_dfs_pattern *pattern);
int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link,
u8 ht_mode, bool use_cts_prot);
int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
@@ -726,6 +757,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val);
int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
struct cfg80211_chan_def *chandef);
@@ -743,6 +775,13 @@ void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled);
int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev);
int mt7996_mcu_mld_reconf_stop_link(struct mt7996_dev *dev,
struct ieee80211_vif *vif,
u16 removed_links);
int mt7996_mcu_mld_link_oper(struct mt7996_dev *dev,
struct ieee80211_bss_conf *link_conf,
struct mt7996_vif_link *link, bool add);
static inline bool mt7996_has_hwrro(struct mt7996_dev *dev)
{
@@ -802,6 +841,11 @@ static inline bool mt7996_has_wa(struct mt7996_dev *dev)
return !is_mt7990(&dev->mt76);
}
static inline bool mt7996_has_ext_eeprom(struct mt7996_dev *dev)
{
return !is_mt7996(&dev->mt76);
}
void mt7996_mac_init(struct mt7996_dev *dev);
u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw);
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
@@ -823,8 +867,9 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link,
u8 flowid);
void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link);
void mt7996_mac_sta_remove_link(struct mt7996_dev *dev,
struct ieee80211_sta *sta,
unsigned int link_id, bool flush);
void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct ieee80211_twt_setup *twt);
@@ -861,6 +906,10 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link);
int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode);
int mt7996_mcu_set_emlsr_mode(struct mt7996_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_eml_params *eml_params);
#ifdef CONFIG_MAC80211_DEBUGFS
void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
@@ -877,12 +926,19 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
#endif
int mt7996_dma_rro_init(struct mt7996_dev *dev);
void mt7996_dma_rro_start(struct mt7996_dev *dev);
#ifdef CONFIG_MT7996_NPU
int __mt7996_npu_hw_init(struct mt7996_dev *dev);
int mt7996_npu_hw_init(struct mt7996_dev *dev);
int mt7996_npu_hw_stop(struct mt7996_dev *dev);
int mt7996_npu_rx_queues_init(struct mt7996_dev *dev);
#else
static inline int __mt7996_npu_hw_init(struct mt7996_dev *dev)
{
return 0;
}
static inline int mt7996_npu_hw_init(struct mt7996_dev *dev)
{
return 0;

View File

@@ -8,55 +8,20 @@
#include "mt7996.h"
static int mt7996_npu_offload_init(struct mt7996_dev *dev,
struct airoha_npu *npu)
static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev,
struct airoha_npu *npu)
{
u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
phys_addr_t phy_addr = dev->mt76.mmio.phy_addr;
u32 val, hif1_ofs = 0, dma_addr;
u32 dma_addr;
int i, err;
err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev, "failed getting NPU fw version\n");
return err;
}
dev_info(dev->mt76.dev, "NPU version: %0d.%d\n",
(val >> 16) & 0xffff, val & 0xffff);
err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE,
dev->mt76.mmio.npu_type, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe port type\n");
return err;
}
if (dev->hif2)
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
for (i = MT_BAND0; i < MT_BAND2; i++) {
dma_addr = phy_addr;
if (i)
dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90 +
hif1_ofs;
else
dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80;
err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_DESC,
MT7996_RX_RING_SIZE, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc size\n");
"failed setting NPU wlan rx desc size\n");
return err;
}
@@ -97,10 +62,173 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev,
phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rro_ack_sn desc addr\n");
"failed setting NPU wlan tx desc addr\n");
return err;
}
return 0;
}
static int mt7996_npu_txrx_offload_init(struct mt7996_dev *dev,
struct airoha_npu *npu)
{
u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
phys_addr_t phy_addr = dev->mt76.mmio.phy_addr;
u32 dma_addr;
int err;
/* npu rx rro ring0 */
err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_DESC,
MT7996_RX_RING_SIZE, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rx desc size\n");
return err;
}
/* npu rx rro ring1 */
err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_DESC,
MT7996_NPU_RX_RING_SIZE, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rx desc size\n");
return err;
}
/* msdu pg 2GHz */
dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0) + 0xa0;
err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_DESC,
MT7996_NPU_RX_RING_SIZE / 4, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rx desc size\n");
return err;
}
/* msdu pg 5GHz */
dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1) + 0xb0;
err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_DESC,
MT7996_NPU_RX_RING_SIZE / 2, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rx desc size\n");
return err;
}
/* msdu pg 6GHz */
dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2) + 0xc0;
err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_DESC,
MT7996_NPU_RX_RING_SIZE, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rx desc size\n");
return err;
}
/* ind cmd ring */
err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
phy_addr + MT_RXQ_RRO_IND_RING_BASE,
GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_DESC,
MT7996_RX_RING_SIZE, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan rx desc size\n");
return err;
}
err = mt76_npu_send_msg(npu, 3, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR,
phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan tx desc addr\n");
return err;
}
/* npu tx */
dma_addr = phy_addr + MT_TXQ_RING_BASE(1) + 0x120;
err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan tx desc addr\n");
return err;
}
dma_addr = phy_addr + MT_TXQ_RING_BASE(0) + 0x150 + hif1_ofs;
err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan tx desc addr\n");
return err;
}
return 0;
}
static int mt7996_npu_offload_init(struct mt7996_dev *dev,
struct airoha_npu *npu)
{
u32 val;
int err;
err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev, "failed getting NPU fw version\n");
return err;
}
dev_info(dev->mt76.dev, "NPU version: %0d.%d\n",
(val >> 16) & 0xffff, val & 0xffff);
err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE,
dev->mt76.mmio.npu_type, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe port type\n");
return err;
}
if (is_mt7996(&dev->mt76))
err = mt7996_npu_txrx_offload_init(dev, npu);
else
err = mt7992_npu_txrx_offload_init(dev, npu);
if (err)
return err;
err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE,
MT7996_HW_TOKEN_SIZE, GFP_KERNEL);
if (err)
@@ -111,6 +239,41 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev,
return 0;
}
static int mt7992_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
{
u32 val;
int err;
err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retrieving NPU wlan rx ring0 addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base);
err = mt76_npu_get_msg(npu, 1, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retrieving NPU wlan rx ring1 addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND1].regs->desc_base);
err = mt76_npu_get_msg(npu, 9, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retrieving NPU wlan rxdmad_c ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_RXDMAD_C].regs->desc_base);
return 0;
}
static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
{
u32 val;
@@ -125,80 +288,107 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base);
err = mt76_npu_get_msg(npu, 1, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
err = mt76_npu_get_msg(npu, 2, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan rx ring1 addr\n");
"failed retriving NPU wlan rx ring2 addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND1].regs->desc_base);
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2].regs->desc_base);
err = mt76_npu_get_msg(npu, 9, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
/* msdu pg ring */
err = mt76_npu_get_msg(npu, 10, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan rxdmad_c ring addr\n");
"failed retriving NPU wlan msdu pg ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_RXDMAD_C].regs->desc_base);
writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND0].regs->desc_base);
err = mt76_npu_get_msg(npu, 11, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan msdu pg ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND1].regs->desc_base);
err = mt76_npu_get_msg(npu, 12, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan msdu pg ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND2].regs->desc_base);
/* ind_cmd ring */
err = mt76_npu_get_msg(npu, 8, WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan ind_cmd ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_IND].regs->desc_base);
return 0;
}
static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
{
int i, err;
const enum mt76_band_id band_list[] = {
MT_BAND0,
is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND1,
};
int i, index = 0;
for (i = MT_BAND0; i < MT_BAND2; i++) {
dma_addr_t dma_addr;
BUILD_BUG_ON(ARRAY_SIZE(band_list) * 3 !=
ARRAY_SIZE(dev->npu_txd_addr));
for (i = 0; i < ARRAY_SIZE(band_list); i++) {
int err, band = band_list[i], phy_id;
u32 val;
err = mt76_npu_get_msg(npu, i + 5,
err = mt76_npu_get_msg(npu, band + 5,
WLAN_FUNC_GET_WAIT_RXDESC_BASE,
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan tx ring addr\n");
"failed retrieving NPU wlan tx ring addr\n");
return err;
}
writel(val, &dev->mt76.phys[i]->q_tx[0]->regs->desc_base);
if (!dmam_alloc_coherent(dev->mt76.dma_dev,
256 * MT7996_TX_RING_SIZE,
&dma_addr, GFP_KERNEL))
return -ENOMEM;
phy_id = is_mt7996(&dev->mt76) ? band == MT_BAND0 ? 1 : 0
: band;
writel(val, &dev->mt76.phys[phy_id]->q_tx[0]->regs->desc_base);
err = mt76_npu_send_msg(npu, i,
err = mt76_npu_send_msg(npu, band,
WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE,
dma_addr, GFP_KERNEL);
dev->npu_txd_addr[index++], GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan queue buf addr\n");
return err;
}
if (!dmam_alloc_coherent(dev->mt76.dma_dev,
256 * MT7996_TX_RING_SIZE,
&dma_addr, GFP_KERNEL))
return -ENOMEM;
err = mt76_npu_send_msg(npu, i + 5,
err = mt76_npu_send_msg(npu, band + 5,
WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE,
dma_addr, GFP_KERNEL);
dev->npu_txd_addr[index++],
GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan tx buf addr\n");
return err;
}
if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024,
&dma_addr, GFP_KERNEL))
return -ENOMEM;
err = mt76_npu_send_msg(npu, i + 10,
err = mt76_npu_send_msg(npu, band + 10,
WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE,
dma_addr, GFP_KERNEL);
dev->npu_txd_addr[index++],
GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan tx buf base\n");
@@ -212,8 +402,9 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
static int mt7996_npu_rx_event_init(struct mt7996_dev *dev,
struct airoha_npu *npu)
{
struct mt76_queue *q = &dev->mt76.q_rx[MT_RXQ_MAIN_WA];
int qid = is_mt7996(&dev->mt76) ? MT_RXQ_TXFREE_BAND0 : MT_RXQ_MAIN_WA;
phys_addr_t phy_addr = dev->mt76.mmio.phy_addr;
struct mt76_queue *q = &dev->mt76.q_rx[qid];
int err;
err = mt76_npu_send_msg(npu, 0,
@@ -233,7 +424,8 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev,
return err;
}
phy_addr += MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA) + 0x20;
phy_addr += MT_RXQ_RING_BASE(qid);
phy_addr += is_mt7996(&dev->mt76) ? 0x90 : 0x20;
err = mt76_npu_send_msg(npu, 10, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
phy_addr, GFP_KERNEL);
if (err)
@@ -242,11 +434,54 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev,
return err;
}
static int mt7996_npu_set_pcie_addr(struct mt7996_dev *dev,
struct airoha_npu *npu)
{
u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
dma_addr_t dma_addr = dev->mt76.mmio.phy_addr;
int err;
dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80;
err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
dma_addr = dev->mt76.mmio.phy_addr + hif1_ofs;
if (is_mt7996(&dev->mt76)) {
dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + 0x60;
err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
} else {
dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90;
err = mt76_npu_send_msg(npu, 1, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
dma_addr, GFP_KERNEL);
}
if (err)
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
static int mt7996_npu_tx_done_init(struct mt7996_dev *dev,
struct airoha_npu *npu)
{
int err;
/* rro ring cpu idx */
err = mt76_npu_send_msg(npu, 15, WLAN_FUNC_SET_WAIT_PCIE_ADDR,
0, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed setting NPU wlan PCIe desc addr\n");
return err;
}
err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
0, GFP_KERNEL);
if (err) {
@@ -278,40 +513,79 @@ int mt7996_npu_rx_queues_init(struct mt7996_dev *dev)
&dev->mt76.q_rx[MT_RXQ_NPU1]);
}
int mt7996_npu_hw_init(struct mt7996_dev *dev)
int __mt7996_npu_hw_init(struct mt7996_dev *dev)
{
struct airoha_npu *npu;
int i, err = 0;
mutex_lock(&dev->mt76.mutex);
int i, err;
npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex);
if (!npu)
goto unlock;
return 0;
err = mt7996_npu_offload_init(dev, npu);
if (err)
goto unlock;
return err;
if (is_mt7996(&dev->mt76))
err = mt7996_npu_rxd_init(dev, npu);
else
err = mt7992_npu_rxd_init(dev, npu);
err = mt7996_npu_rxd_init(dev, npu);
if (err)
goto unlock;
return err;
err = mt7996_npu_txd_init(dev, npu);
if (err)
goto unlock;
return err;
err = mt7996_npu_rx_event_init(dev, npu);
if (err)
goto unlock;
return err;
err = mt7996_npu_set_pcie_addr(dev, npu);
if (err)
return err;
err = mt7996_npu_tx_done_init(dev, npu);
if (err)
goto unlock;
return err;
for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++)
airoha_npu_wlan_enable_irq(npu, i - MT_RXQ_NPU0);
unlock:
return 0;
}
int mt7996_npu_hw_init(struct mt7996_dev *dev)
{
int i, err;
BUILD_BUG_ON(ARRAY_SIZE(dev->npu_txd_addr) % 3);
for (i = 0; i < ARRAY_SIZE(dev->npu_txd_addr); i += 3) {
int band = i && is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND0;
u32 size = is_mt7996(&dev->mt76) ? band == MT_BAND2
? MT7996_NPU_TX_RING_SIZE
: MT7996_NPU_RX_RING_SIZE / 2
: MT7996_TX_RING_SIZE;
if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size,
&dev->npu_txd_addr[i], GFP_KERNEL))
return -ENOMEM;
if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size,
&dev->npu_txd_addr[i + 1],
GFP_KERNEL))
return -ENOMEM;
if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024,
&dev->npu_txd_addr[i + 2],
GFP_KERNEL))
return -ENOMEM;
}
mutex_lock(&dev->mt76.mutex);
err = __mt7996_npu_hw_init(dev);
mutex_unlock(&dev->mt76.mutex);
return err;
@@ -320,33 +594,38 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev)
int mt7996_npu_hw_stop(struct mt7996_dev *dev)
{
struct airoha_npu *npu;
int i, err;
int i, err = 0;
u32 info;
mutex_lock(&dev->mt76.mutex);
npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex);
if (!npu)
return 0;
goto unlock;
err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
0, GFP_KERNEL);
if (err)
return err;
goto unlock;
for (i = 0; i < 10; i++) {
err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO,
&info, GFP_KERNEL);
if (err)
continue;
if (!err && !info)
break;
if (info) {
err = -ETIMEDOUT;
continue;
}
err = -ETIMEDOUT;
usleep_range(10000, 15000);
}
if (!err)
err = mt76_npu_send_msg(npu, 6,
WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
0, GFP_KERNEL);
else
dev_err(dev->mt76.dev, "npu stop failed\n");
unlock:
mutex_unlock(&dev->mt76.mutex);
return err;
}

View File

@@ -159,6 +159,9 @@ enum offs_rev {
#define MT_MDP_BASE 0x820cc000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))
#define MT_MDP_DCR0 MT_MDP(0x800)
#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19)
#define MT_MDP_DCR2 MT_MDP(0x8e8)
#define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2)
@@ -733,7 +736,15 @@ enum offs_rev {
#define MT_HW_REV 0x70010204
#define MT_HW_REV1 0x8a00
#define MT_WF_L05_RST 0x70028550
#define MT_WF_L05_RST_WF_RST_MASK GENMASK(4, 0)
#define MT_WF_SUBSYS_RST 0x70028600
#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST BIT(0)
#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT BIT(5)
#define MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT BIT(6)
#define MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT BIT(16)
#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE GENMASK(15, 8)
/* PCIE MAC */
#define MT_PCIE_MAC_BASE 0x74030000

View File

@@ -390,6 +390,36 @@ int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc);
int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
u32 direction, u32 i_count_addr,
u32 o_status_addr, u32 o_count_addr)
{
struct {
__le32 dir;
__le32 in_count_addr;
__le32 out_status_addr;
__le32 out_count_addr;
} info = {
.dir = cpu_to_le32(direction),
.in_count_addr = cpu_to_le32(i_count_addr),
.out_status_addr = cpu_to_le32(o_status_addr),
.out_count_addr = cpu_to_le32(o_count_addr),
};
struct airoha_npu *npu;
int err = -ENODEV;
rcu_read_lock();
npu = rcu_dereference(dev->mmio.npu);
if (npu)
err = airoha_npu_wlan_send_msg(npu, ifindex,
WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR,
&info, sizeof(info), GFP_ATOMIC);
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL_GPL(mt76_npu_send_txrx_addr);
void mt76_npu_disable_irqs(struct mt76_dev *dev)
{
struct airoha_npu *npu;
@@ -420,10 +450,6 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type)
struct airoha_npu *npu;
int err = 0;
/* NPU offloading is only supported by MT7992 */
if (!is_mt7992(dev))
return 0;
mutex_lock(&dev->mutex);
npu = airoha_npu_get(dev->dev);
@@ -456,7 +482,8 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type)
dev->mmio.phy_addr = phy_addr;
dev->mmio.npu_type = type;
/* NPU offloading requires HW-RRO for RX packet reordering. */
dev->hwrro_mode = MT76_HWRRO_V3_1;
dev->hwrro_mode = is_mt7996(dev) ? MT76_HWRRO_V3 : MT76_HWRRO_V3_1;
dev->rx_token_size = 32768;
rcu_assign_pointer(dev->mmio.npu, npu);
rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev);

View File

@@ -16,9 +16,11 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
clear_bit(MT76_SCANNING, &phy->state);
if (dev->scan.chan && phy->main_chandef.chan &&
!test_bit(MT76_MCU_RESET, &dev->phy.state))
if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel &&
!test_bit(MT76_MCU_RESET, &dev->phy.state)) {
mt76_set_channel(phy, &phy->main_chandef, false);
mt76_offchannel_notify(phy, false);
}
mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
memset(&dev->scan, 0, sizeof(dev->scan));
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
@@ -27,6 +29,10 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
void mt76_abort_scan(struct mt76_dev *dev)
{
spin_lock_bh(&dev->scan_lock);
dev->scan.beacon_wait = false;
spin_unlock_bh(&dev->scan_lock);
cancel_delayed_work_sync(&dev->scan_work);
mt76_scan_complete(dev, true);
}
@@ -79,6 +85,27 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_unlock();
}
void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan)
{
struct mt76_phy *phy;
spin_lock(&dev->scan_lock);
if (!dev->scan.beacon_wait || dev->scan.beacon_received ||
dev->scan.chan != chan)
goto out;
phy = dev->scan.phy;
if (!phy)
goto out;
dev->scan.beacon_received = true;
ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0);
out:
spin_unlock(&dev->scan_lock);
}
void mt76_scan_work(struct work_struct *work)
{
struct mt76_dev *dev = container_of(work, struct mt76_dev,
@@ -87,35 +114,60 @@ void mt76_scan_work(struct work_struct *work)
struct cfg80211_chan_def chandef = {};
struct mt76_phy *phy = dev->scan.phy;
int duration = HZ / 9; /* ~110 ms */
bool beacon_rx, offchannel = true;
int i;
if (!phy || !req)
return;
spin_lock_bh(&dev->scan_lock);
beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received;
dev->scan.beacon_wait = false;
spin_unlock_bh(&dev->scan_lock);
if (beacon_rx)
goto probe;
if (dev->scan.chan_idx >= req->n_channels) {
mt76_scan_complete(dev, false);
return;
}
if (dev->scan.chan && phy->num_sta) {
if (dev->scan.chan && phy->num_sta && phy->offchannel) {
dev->scan.chan = NULL;
mt76_set_channel(phy, &phy->main_chandef, false);
mt76_offchannel_notify(phy, false);
goto out;
}
dev->scan.chan = req->channels[dev->scan.chan_idx++];
cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20);
mt76_set_channel(phy, &chandef, true);
offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef);
if (!req->n_ssids ||
chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
if (offchannel)
mt76_offchannel_notify(phy, true);
mt76_set_channel(phy, &chandef, offchannel);
if (!req->n_ssids)
goto out;
duration = HZ / 16; /* ~60 ms */
if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) {
spin_lock_bh(&dev->scan_lock);
dev->scan.beacon_received = false;
dev->scan.beacon_wait = true;
spin_unlock_bh(&dev->scan_lock);
goto out;
}
probe:
if (phy->offchannel)
duration = HZ / 16; /* ~60 ms */
local_bh_disable();
for (i = 0; i < req->n_ssids; i++)
mt76_scan_send_probe(dev, &req->ssids[i]);
local_bh_enable();
out:
if (dev->scan.chan)
if (dev->scan.chan && phy->offchannel)
duration = max_t(int, duration,
msecs_to_jiffies(req->duration +
(req->duration >> 5)));

View File

@@ -227,7 +227,9 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta;
int pending;
int i;
if (!wcid || info->tx_time_est)
return;
@@ -235,6 +237,17 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
pending = atomic_dec_return(&wcid->non_aql_packets);
if (pending < 0)
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
sta = wcid_to_sta(wcid);
if (!sta || pending != MT_MAX_NON_AQL_PKT - 1)
return;
for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
if (!sta->txq[i])
continue;
ieee80211_schedule_txq(dev->hw, sta->txq[i]);
}
}
void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb,
@@ -542,6 +555,9 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags))
continue;
if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
continue;
phy = mt76_dev_phy(dev, wcid->phy_idx);
if (test_bit(MT76_RESET, &phy->state) || phy->offchannel)
continue;
@@ -616,7 +632,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data(hdr->frame_control) &&
!ieee80211_is_data_present(hdr->frame_control) &&
(!ieee80211_is_bufferable_mmpdu(skb) ||
ieee80211_is_deauth(hdr->frame_control) ||
head == &wcid->tx_offchannel))
@@ -644,7 +660,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
return ret;
}
static void mt76_txq_schedule_pending(struct mt76_phy *phy)
void mt76_txq_schedule_pending(struct mt76_phy *phy)
{
LIST_HEAD(tx_list);
int ret = 0;
@@ -850,9 +866,15 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
token = idr_alloc(&dev->token, *ptxwi, dev->token_start,
dev->token_start + dev->token_size,
GFP_ATOMIC);
if (token >= dev->token_start)
if (token >= dev->token_start) {
dev->token_count++;
if ((*ptxwi)->qid == MT_TXQ_PSD) {
struct mt76_phy *mphy = mt76_dev_phy(dev, (*ptxwi)->phy_idx);
atomic_inc(&mphy->mgmt_tx_pending);
}
}
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
if (mtk_wed_device_active(&dev->mmio.wed) &&
token >= dev->mmio.wed.wlan.token_start)
@@ -897,6 +919,12 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
if (txwi) {
dev->token_count--;
if (txwi->qid == MT_TXQ_PSD) {
struct mt76_phy *mphy = mt76_dev_phy(dev, txwi->phy_idx);
if (atomic_dec_and_test(&mphy->mgmt_tx_pending))
wake_up(&dev->tx_wait);
}
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
if (mtk_wed_device_active(&dev->mmio.wed) &&
token >= dev->mmio.wed.wlan.token_start &&

View File

@@ -403,12 +403,18 @@ mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw)
return ret;
}
static const char * const mt7601u_fw_paths[] = {
"mediatek/" MT7601U_FIRMWARE,
MT7601U_FIRMWARE,
};
static int mt7601u_load_firmware(struct mt7601u_dev *dev)
{
const struct firmware *fw;
const struct mt76_fw_header *hdr;
int len, ret;
u32 val;
int i;
mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN));
@@ -416,7 +422,14 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev)
if (firmware_running(dev))
return firmware_request_cache(dev->dev, MT7601U_FIRMWARE);
ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev);
/* Try loading firmware from multiple locations */
fw = NULL;
for (i = 0; i < MT7601U_FIRMWARE_PATHS; i++) {
ret = request_firmware(&fw, mt7601u_fw_paths[i], dev->dev);
if (ret == 0)
break;
}
if (ret)
return ret;

View File

@@ -9,6 +9,7 @@
#include "mt7601u.h"
#define MT7601U_FIRMWARE "mt7601u.bin"
#define MT7601U_FIRMWARE_PATHS ARRAY_SIZE(mt7601u_fw_paths)
#define MT_VEND_REQ_MAX_RETRY 10
#define MT_VEND_REQ_TOUT_MS 300