162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2023 MediaTek Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "mt792x.h" 762306a36Sopenharmony_ci#include "mt792x_regs.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_civoid mt792x_mac_work(struct work_struct *work) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci struct mt792x_phy *phy; 1262306a36Sopenharmony_ci struct mt76_phy *mphy; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, 1562306a36Sopenharmony_ci mac_work.work); 1662306a36Sopenharmony_ci phy = mphy->priv; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci mt792x_mutex_acquire(phy->dev); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci mt76_update_survey(mphy); 2162306a36Sopenharmony_ci if (++mphy->mac_work_count == 2) { 2262306a36Sopenharmony_ci mphy->mac_work_count = 0; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci mt792x_mac_update_mib_stats(phy); 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci mt792x_mutex_release(phy->dev); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci mt76_tx_status_check(mphy->dev, false); 3062306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, 3162306a36Sopenharmony_ci MT792x_WATCHDOG_TIME); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_mac_work); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid mt792x_mac_set_timeing(struct mt792x_phy *phy) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci s16 coverage_class = phy->coverage_class; 3862306a36Sopenharmony_ci struct mt792x_dev *dev = phy->dev; 3962306a36Sopenharmony_ci u32 val, reg_offset; 4062306a36Sopenharmony_ci u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | 4162306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); 4262306a36Sopenharmony_ci u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | 4362306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); 4462306a36Sopenharmony_ci bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ; 4562306a36Sopenharmony_ci int sifs = is_2ghz ? 10 : 16, offset; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 4862306a36Sopenharmony_ci return; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci mt76_set(dev, MT_ARB_SCR(0), 5162306a36Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 5262306a36Sopenharmony_ci udelay(1); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci offset = 3 * coverage_class; 5562306a36Sopenharmony_ci reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | 5662306a36Sopenharmony_ci FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset); 5962306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset); 6062306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_ICR0(0), 6162306a36Sopenharmony_ci FIELD_PREP(MT_IFS_EIFS, 360) | 6262306a36Sopenharmony_ci FIELD_PREP(MT_IFS_RIFS, 2) | 6362306a36Sopenharmony_ci FIELD_PREP(MT_IFS_SIFS, sifs) | 6462306a36Sopenharmony_ci FIELD_PREP(MT_IFS_SLOT, phy->slottime)); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (phy->slottime < 20 || !is_2ghz) 6762306a36Sopenharmony_ci val = MT792x_CFEND_RATE_DEFAULT; 6862306a36Sopenharmony_ci else 6962306a36Sopenharmony_ci val = MT792x_CFEND_RATE_11B; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val); 7262306a36Sopenharmony_ci mt76_clear(dev, MT_ARB_SCR(0), 7362306a36Sopenharmony_ci MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_mac_set_timeing); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_civoid mt792x_mac_update_mib_stats(struct mt792x_phy *phy) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 8062306a36Sopenharmony_ci struct mt792x_dev *dev = phy->dev; 8162306a36Sopenharmony_ci int i, aggr0 = 0, aggr1; 8262306a36Sopenharmony_ci u32 val; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0), 8562306a36Sopenharmony_ci MT_MIB_SDR3_FCS_ERR_MASK); 8662306a36Sopenharmony_ci mib->ack_fail_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR3(0), 8762306a36Sopenharmony_ci MT_MIB_ACK_FAIL_COUNT_MASK); 8862306a36Sopenharmony_ci mib->ba_miss_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR2(0), 8962306a36Sopenharmony_ci MT_MIB_BA_FAIL_COUNT_MASK); 9062306a36Sopenharmony_ci mib->rts_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR0(0), 9162306a36Sopenharmony_ci MT_MIB_RTS_COUNT_MASK); 9262306a36Sopenharmony_ci mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0), 9362306a36Sopenharmony_ci MT_MIB_RTS_FAIL_COUNT_MASK); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0)); 9662306a36Sopenharmony_ci mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0)); 9762306a36Sopenharmony_ci mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci val = mt76_rr(dev, MT_MIB_SDR32(0)); 10062306a36Sopenharmony_ci mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val); 10162306a36Sopenharmony_ci mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0)); 10462306a36Sopenharmony_ci mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val); 10562306a36Sopenharmony_ci mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0)); 10862306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val); 10962306a36Sopenharmony_ci mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val); 11062306a36Sopenharmony_ci mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val); 11162306a36Sopenharmony_ci mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0)); 11462306a36Sopenharmony_ci mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0)); 11562306a36Sopenharmony_ci mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0)); 11662306a36Sopenharmony_ci mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0)); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { 11962306a36Sopenharmony_ci val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); 12062306a36Sopenharmony_ci mib->tx_amsdu[i] += val; 12162306a36Sopenharmony_ci mib->tx_amsdu_cnt += val; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) { 12562306a36Sopenharmony_ci u32 val2; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci val = mt76_rr(dev, MT_TX_AGG_CNT(0, i)); 12862306a36Sopenharmony_ci val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr0++] += val & 0xffff; 13162306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr0++] += val >> 16; 13262306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr1++] += val2 & 0xffff; 13362306a36Sopenharmony_ci phy->mt76->aggr_stats[aggr1++] += val2 >> 16; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_mac_update_mib_stats); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistruct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx, 13962306a36Sopenharmony_ci bool unicast) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct mt792x_sta *sta; 14262306a36Sopenharmony_ci struct mt76_wcid *wcid; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(dev->mt76.wcid)) 14562306a36Sopenharmony_ci return NULL; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci wcid = rcu_dereference(dev->mt76.wcid[idx]); 14862306a36Sopenharmony_ci if (unicast || !wcid) 14962306a36Sopenharmony_ci return wcid; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!wcid->sta) 15262306a36Sopenharmony_ci return NULL; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci sta = container_of(wcid, struct mt792x_sta, wcid); 15562306a36Sopenharmony_ci if (!sta->vif) 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return &sta->vif->sta.wcid; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_rx_get_wcid); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void 16362306a36Sopenharmony_cimt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct sk_buff *skb = priv; 16662306a36Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 16762306a36Sopenharmony_ci struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 16862306a36Sopenharmony_ci struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (status->signal > 0) 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!ether_addr_equal(vif->addr, hdr->addr1)) 17462306a36Sopenharmony_ci return; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ewma_rssi_add(&mvif->rssi, -status->signal); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_civoid mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!ieee80211_is_assoc_resp(hdr->frame_control) && 18462306a36Sopenharmony_ci !ieee80211_is_auth(hdr->frame_control)) 18562306a36Sopenharmony_ci return; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), 18862306a36Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 18962306a36Sopenharmony_ci mt792x_mac_rssi_iter, skb); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_mac_assoc_rssi); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_civoid mt792x_mac_reset_counters(struct mt792x_phy *phy) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct mt792x_dev *dev = phy->dev; 19662306a36Sopenharmony_ci int i; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 19962306a36Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT(0, i)); 20062306a36Sopenharmony_ci mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci dev->mt76.phy.survey_time = ktime_get_boottime(); 20462306a36Sopenharmony_ci memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* reset airtime counters */ 20762306a36Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR9(0)); 20862306a36Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR36(0)); 20962306a36Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR37(0)); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); 21262306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_mac_reset_counters); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic u8 21762306a36Sopenharmony_cimt792x_phy_get_nf(struct mt792x_phy *phy, int idx) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic void 22362306a36Sopenharmony_cimt792x_phy_update_channel(struct mt76_phy *mphy, int idx) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); 22662306a36Sopenharmony_ci struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; 22762306a36Sopenharmony_ci struct mt76_channel_state *state; 22862306a36Sopenharmony_ci u64 busy_time, tx_time, rx_time, obss_time; 22962306a36Sopenharmony_ci int nf; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), 23262306a36Sopenharmony_ci MT_MIB_SDR9_BUSY_MASK); 23362306a36Sopenharmony_ci tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), 23462306a36Sopenharmony_ci MT_MIB_SDR36_TXTIME_MASK); 23562306a36Sopenharmony_ci rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), 23662306a36Sopenharmony_ci MT_MIB_SDR37_RXTIME_MASK); 23762306a36Sopenharmony_ci obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), 23862306a36Sopenharmony_ci MT_MIB_OBSSTIME_MASK); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci nf = mt792x_phy_get_nf(phy, idx); 24162306a36Sopenharmony_ci if (!phy->noise) 24262306a36Sopenharmony_ci phy->noise = nf << 4; 24362306a36Sopenharmony_ci else if (nf) 24462306a36Sopenharmony_ci phy->noise += nf - (phy->noise >> 4); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci state = mphy->chan_state; 24762306a36Sopenharmony_ci state->cc_busy += busy_time; 24862306a36Sopenharmony_ci state->cc_tx += tx_time; 24962306a36Sopenharmony_ci state->cc_rx += rx_time + obss_time; 25062306a36Sopenharmony_ci state->cc_bss_rx += rx_time; 25162306a36Sopenharmony_ci state->noise = -(phy->noise >> 4); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_civoid mt792x_update_channel(struct mt76_phy *mphy) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (mt76_connac_pm_wake(mphy, &dev->pm)) 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mt792x_phy_update_channel(mphy, 0); 26262306a36Sopenharmony_ci /* reset obss airtime */ 26362306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); 26462306a36Sopenharmony_ci mt76_connac_power_save_sched(mphy, &dev->pm); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_update_channel); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_civoid mt792x_reset(struct mt76_dev *mdev) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); 27162306a36Sopenharmony_ci struct mt76_connac_pm *pm = &dev->pm; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (!dev->hw_init_done) 27462306a36Sopenharmony_ci return; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (dev->hw_full_reset) 27762306a36Sopenharmony_ci return; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (pm->suspended) 28062306a36Sopenharmony_ci return; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci queue_work(dev->mt76.wq, &dev->reset_work); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_reset); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_civoid mt792x_mac_init_band(struct mt792x_dev *dev, u8 band) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci u32 mask, set; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mt76_rmw_field(dev, MT_TMAC_CTCR0(band), 29162306a36Sopenharmony_ci MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); 29262306a36Sopenharmony_ci mt76_set(dev, MT_TMAC_CTCR0(band), 29362306a36Sopenharmony_ci MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | 29462306a36Sopenharmony_ci MT_TMAC_CTCR0_INS_DDLMT_EN); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); 29762306a36Sopenharmony_ci mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* enable MIB tx-rx time reporting */ 30062306a36Sopenharmony_ci mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN); 30162306a36Sopenharmony_ci mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536); 30462306a36Sopenharmony_ci /* disable rx rate report by default due to hw issues */ 30562306a36Sopenharmony_ci mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* filter out non-resp frames and get instantaneous signal reporting */ 30862306a36Sopenharmony_ci mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM; 30962306a36Sopenharmony_ci set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) | 31062306a36Sopenharmony_ci FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3); 31162306a36Sopenharmony_ci mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_mac_init_band); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_civoid mt792x_pm_wake_work(struct work_struct *work) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct mt792x_dev *dev; 31862306a36Sopenharmony_ci struct mt76_phy *mphy; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev, 32162306a36Sopenharmony_ci pm.wake_work); 32262306a36Sopenharmony_ci mphy = dev->phy.mt76; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!mt792x_mcu_drv_pmctrl(dev)) { 32562306a36Sopenharmony_ci struct mt76_dev *mdev = &dev->mt76; 32662306a36Sopenharmony_ci int i; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (mt76_is_sdio(mdev)) { 32962306a36Sopenharmony_ci mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); 33062306a36Sopenharmony_ci mt76_worker_schedule(&mdev->sdio.txrx_worker); 33162306a36Sopenharmony_ci } else { 33262306a36Sopenharmony_ci local_bh_disable(); 33362306a36Sopenharmony_ci mt76_for_each_q_rx(mdev, i) 33462306a36Sopenharmony_ci napi_schedule(&mdev->napi[i]); 33562306a36Sopenharmony_ci local_bh_enable(); 33662306a36Sopenharmony_ci mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); 33762306a36Sopenharmony_ci mt76_connac_tx_cleanup(mdev); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci if (test_bit(MT76_STATE_RUNNING, &mphy->state)) 34062306a36Sopenharmony_ci ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, 34162306a36Sopenharmony_ci MT792x_WATCHDOG_TIME); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ieee80211_wake_queues(mphy->hw); 34562306a36Sopenharmony_ci wake_up(&dev->pm.wait); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_pm_wake_work); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_civoid mt792x_pm_power_save_work(struct work_struct *work) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct mt792x_dev *dev; 35262306a36Sopenharmony_ci unsigned long delta; 35362306a36Sopenharmony_ci struct mt76_phy *mphy; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev, 35662306a36Sopenharmony_ci pm.ps_work.work); 35762306a36Sopenharmony_ci mphy = dev->phy.mt76; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci delta = dev->pm.idle_timeout; 36062306a36Sopenharmony_ci if (test_bit(MT76_HW_SCANNING, &mphy->state) || 36162306a36Sopenharmony_ci test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) || 36262306a36Sopenharmony_ci dev->fw_assert) 36362306a36Sopenharmony_ci goto out; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (mutex_is_locked(&dev->mt76.mutex)) 36662306a36Sopenharmony_ci /* if mt76 mutex is held we should not put the device 36762306a36Sopenharmony_ci * to sleep since we are currently accessing device 36862306a36Sopenharmony_ci * register map. We need to wait for the next power_save 36962306a36Sopenharmony_ci * trigger. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci goto out; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (time_is_after_jiffies(dev->pm.last_activity + delta)) { 37462306a36Sopenharmony_ci delta = dev->pm.last_activity + delta - jiffies; 37562306a36Sopenharmony_ci goto out; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!mt792x_mcu_fw_pmctrl(dev)) { 37962306a36Sopenharmony_ci cancel_delayed_work_sync(&mphy->mac_work); 38062306a36Sopenharmony_ci return; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ciout: 38362306a36Sopenharmony_ci queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt792x_pm_power_save_work); 386