// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2022 MediaTek Inc.
*/
#include "mt7996.h"
#include "mcu.h"
#include "mac.h"
static bool mt7996_dev_running(struct mt7996_dev *dev)
{
struct mt7996_phy *phy;
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
return true;
phy = mt7996_phy2(dev);
if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
return true;
phy = mt7996_phy3(dev);
return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
}
int mt7996_run(struct ieee80211_hw *hw)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
bool running;
int ret;
running = mt7996_dev_running(dev);
if (!running) {
ret = mt7996_mcu_set_hdr_trans(dev, true);
if (ret)
goto out;
if (is_mt7992(&dev->mt76)) {
u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI);
ret = mt7996_mcu_cp_support(dev, queue);
if (ret)
goto out;
}
}
mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
if (ret)
goto out;
ret = mt7996_mcu_set_radio_en(phy, true);
if (ret)
goto out;
ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH);
if (ret)
goto out;
ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
if (ret)
goto out;
ret = mt7996_mcu_set_thermal_protect(phy, true);
if (ret)
goto out;
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
MT7996_WATCHDOG_TIME);
if (!running)
mt7996_mac_reset_counters(phy);
out:
return ret;
}
static int mt7996_start(struct ieee80211_hw *hw)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
int ret;
flush_work(&dev->init_work);
mutex_lock(&dev->mt76.mutex);
ret = mt7996_run(hw);
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void mt7996_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
cancel_delayed_work_sync(&phy->mt76->mac_work);
mutex_lock(&dev->mt76.mutex);
mt7996_mcu_set_radio_en(phy, false);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
mutex_unlock(&dev->mt76.mutex);
}
static inline int get_free_idx(u32 mask, u8 start, u8 end)
{
return ffs(~mask & GENMASK(end, start));
}
static int get_omac_idx(enum nl80211_iftype type, u64 mask)
{
int i;
switch (type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_STATION:
/* prefer hw bssid slot 1-3 */
i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
if (i)
return i - 1;
if (type != NL80211_IFTYPE_STATION)
break;
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
break;
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP:
/* ap uses hw bssid 0 and ext bssid */
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
break;
default:
WARN_ON(1);
break;
}
return -1;
}
static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
int i;
for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) {
mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI;
mvif->bitrate_mask.control[i].he_gi = 0xff;
mvif->bitrate_mask.control[i].he_ltf = 0xff;
mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0);
memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff,
sizeof(mvif->bitrate_mask.control[i].ht_mcs));
memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff,
sizeof(mvif->bitrate_mask.control[i].vht_mcs));
memset(mvif->bitrate_mask.control[i].he_mcs, 0xff,
sizeof(mvif->bitrate_mask.control[i].he_mcs));
}
}
static int mt7996_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt76_txq *mtxq;
u8 band_idx = phy->mt76->band_idx;
int idx, ret = 0;
mutex_lock(&dev->mt76.mutex);
if (vif->type == NL80211_IFTYPE_MONITOR &&
is_zero_ether_addr(vif->addr))
phy->monitor_vif = vif;
mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask);
if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) {
ret = -ENOSPC;
goto out;
}
idx = get_omac_idx(vif->type, phy->omac_mask);
if (idx < 0) {
ret = -ENOSPC;
goto out;
}
mvif->mt76.omac_idx = idx;
mvif->phy = phy;
mvif->mt76.band_idx = band_idx;
mvif->mt76.wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3;
ret = mt7996_mcu_add_dev_info(phy, vif, true);
if (ret)
goto out;
dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
idx = MT7996_WTBL_RESERVED - mvif->mt76.idx;
INIT_LIST_HEAD(&mvif->sta.rc_list);
INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.phy_idx = band_idx;
mvif->sta.wcid.hw_key_idx = -1;
mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET;
mt76_wcid_init(&mvif->sta.wcid);
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 &&
(!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3))
vif->offload_flags = 0;
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
else
mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
mt7996_init_bitrate_mask(vif);
mt7996_mcu_add_bss_info(phy, vif, true);
/* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA
* interface, since firmware only records BSSID when the entry is new
*/
if (vif->type != NL80211_IFTYPE_STATION)
mt7996_mcu_add_sta(dev, vif, NULL, true, true);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void mt7996_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_sta *msta = &mvif->sta;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
int idx = msta->wcid.idx;
mt7996_mcu_add_sta(dev, vif, NULL, false, false);
mt7996_mcu_add_bss_info(phy, vif, false);
if (vif == phy->monitor_vif)
phy->monitor_vif = NULL;
mt7996_mcu_add_dev_info(phy, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mutex_lock(&dev->mt76.mutex);
dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
mutex_unlock(&dev->mt76.mutex);
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (!list_empty(&msta->wcid.poll_list))
list_del_init(&msta->wcid.poll_list);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_wcid_cleanup(&dev->mt76, &msta->wcid);
}
int mt7996_set_channel(struct mt76_phy *mphy)
{
struct mt7996_phy *phy = mphy->priv;
int ret;
ret
|