11c099ab4SSean Wang // SPDX-License-Identifier: ISC 21c099ab4SSean Wang /* Copyright (C) 2020 MediaTek Inc. */ 31c099ab4SSean Wang 41c099ab4SSean Wang #include <linux/fs.h> 523bdc5d8SMing Yen Hsieh #include <linux/firmware.h> 61c099ab4SSean Wang #include "mt7921.h" 72afd17b4SLorenzo Bianconi #include "mt7921_trace.h" 81c099ab4SSean Wang #include "mcu.h" 9140efef3SLorenzo Bianconi #include "../mt76_connac2_mac.h" 101c099ab4SSean Wang 111c099ab4SSean Wang #define MT_STA_BFER BIT(0) 121c099ab4SSean Wang #define MT_STA_BFEE BIT(1) 131c099ab4SSean Wang 1423bdc5d8SMing Yen Hsieh static bool mt7921_disable_clc; 1523bdc5d8SMing Yen Hsieh module_param_named(disable_clc, mt7921_disable_clc, bool, 0644); 1623bdc5d8SMing Yen Hsieh MODULE_PARM_DESC(disable_clc, "disable CLC support"); 1723bdc5d8SMing Yen Hsieh 18dfc7743dSSean Wang int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, 191c099ab4SSean Wang struct sk_buff *skb, int seq) 201c099ab4SSean Wang { 21680a2eadSLorenzo Bianconi int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); 22fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd; 231c099ab4SSean Wang int ret = 0; 241c099ab4SSean Wang 251c099ab4SSean Wang if (!skb) { 2653d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", 271c099ab4SSean Wang cmd, seq); 28d43b3257SLorenzo Bianconi mt7921_reset(mdev); 29d43b3257SLorenzo Bianconi 301c099ab4SSean Wang return -ETIMEDOUT; 311c099ab4SSean Wang } 321c099ab4SSean Wang 33fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 341c099ab4SSean Wang if (seq != rxd->seq) 351c099ab4SSean Wang return -EAGAIN; 361c099ab4SSean Wang 3745b6f9cbSYN Chen if (cmd == MCU_CMD(PATCH_SEM_CONTROL) || 3845b6f9cbSYN Chen cmd == MCU_CMD(PATCH_FINISH_REQ)) { 391c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4); 401c099ab4SSean Wang ret = *skb->data; 419d8d136cSLorenzo Bianconi } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { 421c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4); 431c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data); 4454722402SLorenzo Bianconi } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || 4554722402SLorenzo Bianconi cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) || 4654722402SLorenzo Bianconi cmd == MCU_UNI_CMD(STA_REC_UPDATE) || 4754722402SLorenzo Bianconi cmd == MCU_UNI_CMD(HIF_CTRL) || 4854722402SLorenzo Bianconi cmd == MCU_UNI_CMD(OFFLOAD) || 4954722402SLorenzo Bianconi cmd == MCU_UNI_CMD(SUSPEND)) { 5061d1f545SLorenzo Bianconi struct mt76_connac_mcu_uni_event *event; 511c099ab4SSean Wang 521c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 5361d1f545SLorenzo Bianconi event = (struct mt76_connac_mcu_uni_event *)skb->data; 541c099ab4SSean Wang ret = le32_to_cpu(event->status); 55cd3f3873SDeren Wu /* skip invalid event */ 56cd3f3873SDeren Wu if (mcu_cmd != event->cid) 57cd3f3873SDeren Wu ret = -EAGAIN; 58680a2eadSLorenzo Bianconi } else if (cmd == MCU_CE_QUERY(REG_READ)) { 5961d1f545SLorenzo Bianconi struct mt76_connac_mcu_reg_event *event; 601c099ab4SSean Wang 611c099ab4SSean Wang skb_pull(skb, sizeof(*rxd)); 6261d1f545SLorenzo Bianconi event = (struct mt76_connac_mcu_reg_event *)skb->data; 631c099ab4SSean Wang ret = (int)le32_to_cpu(event->val); 64e6d2070dSLorenzo Bianconi } else { 65fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); 661c099ab4SSean Wang } 671c099ab4SSean Wang 681c099ab4SSean Wang return ret; 691c099ab4SSean Wang } 708910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); 711c099ab4SSean Wang 7223bdc5d8SMing Yen Hsieh static int mt7921_mcu_read_eeprom(struct mt7921_dev *dev, u32 offset, u8 *val) 7323bdc5d8SMing Yen Hsieh { 7423bdc5d8SMing Yen Hsieh struct mt7921_mcu_eeprom_info *res, req = { 7523bdc5d8SMing Yen Hsieh .addr = cpu_to_le32(round_down(offset, 7623bdc5d8SMing Yen Hsieh MT7921_EEPROM_BLOCK_SIZE)), 7723bdc5d8SMing Yen Hsieh }; 7823bdc5d8SMing Yen Hsieh struct sk_buff *skb; 7923bdc5d8SMing Yen Hsieh int ret; 8023bdc5d8SMing Yen Hsieh 8123bdc5d8SMing Yen Hsieh ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), 8223bdc5d8SMing Yen Hsieh &req, sizeof(req), true, &skb); 8323bdc5d8SMing Yen Hsieh if (ret) 8423bdc5d8SMing Yen Hsieh return ret; 8523bdc5d8SMing Yen Hsieh 8623bdc5d8SMing Yen Hsieh res = (struct mt7921_mcu_eeprom_info *)skb->data; 8723bdc5d8SMing Yen Hsieh *val = res->data[offset % MT7921_EEPROM_BLOCK_SIZE]; 8823bdc5d8SMing Yen Hsieh dev_kfree_skb(skb); 8923bdc5d8SMing Yen Hsieh 9023bdc5d8SMing Yen Hsieh return 0; 9123bdc5d8SMing Yen Hsieh } 9223bdc5d8SMing Yen Hsieh 935fc201aaSDeren Wu #ifdef CONFIG_PM 945fc201aaSDeren Wu 955fc201aaSDeren Wu static int 965fc201aaSDeren Wu mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev, 975fc201aaSDeren Wu struct ieee80211_vif *vif, bool suspend) 985fc201aaSDeren Wu { 99*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 1005fc201aaSDeren Wu struct { 1015fc201aaSDeren Wu struct { 1025fc201aaSDeren Wu u8 bss_idx; 1035fc201aaSDeren Wu u8 pad[3]; 1045fc201aaSDeren Wu } __packed hdr; 1055fc201aaSDeren Wu struct mt76_connac_arpns_tlv arpns; 1065fc201aaSDeren Wu } req = { 1075fc201aaSDeren Wu .hdr = { 1085fc201aaSDeren Wu .bss_idx = mvif->mt76.idx, 1095fc201aaSDeren Wu }, 1105fc201aaSDeren Wu .arpns = { 1115fc201aaSDeren Wu .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), 1125fc201aaSDeren Wu .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), 1135fc201aaSDeren Wu .mode = suspend, 1145fc201aaSDeren Wu }, 1155fc201aaSDeren Wu }; 1165fc201aaSDeren Wu 1175fc201aaSDeren Wu return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req), 1185fc201aaSDeren Wu true); 1195fc201aaSDeren Wu } 1205fc201aaSDeren Wu 1215fc201aaSDeren Wu void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) 1225fc201aaSDeren Wu { 1235fc201aaSDeren Wu if (IS_ENABLED(CONFIG_IPV6)) { 1245fc201aaSDeren Wu struct mt76_phy *phy = priv; 1255fc201aaSDeren Wu 1265fc201aaSDeren Wu mt7921_mcu_set_ipv6_ns_filter(phy->dev, vif, 1275fc201aaSDeren Wu !test_bit(MT76_STATE_RUNNING, 1285fc201aaSDeren Wu &phy->state)); 1295fc201aaSDeren Wu } 1305fc201aaSDeren Wu 1315fc201aaSDeren Wu mt76_connac_mcu_set_suspend_iter(priv, mac, vif); 1325fc201aaSDeren Wu } 1335fc201aaSDeren Wu 1345fc201aaSDeren Wu #endif /* CONFIG_PM */ 1355fc201aaSDeren Wu 1361c099ab4SSean Wang static void 137034ae28bSSean Wang mt7921_mcu_uni_roc_event(struct mt7921_dev *dev, struct sk_buff *skb) 138034ae28bSSean Wang { 139034ae28bSSean Wang struct mt7921_roc_grant_tlv *grant; 140034ae28bSSean Wang struct mt76_connac2_mcu_rxd *rxd; 141034ae28bSSean Wang int duration; 142034ae28bSSean Wang 143034ae28bSSean Wang rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 144034ae28bSSean Wang grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4); 145034ae28bSSean Wang 146034ae28bSSean Wang /* should never happen */ 147034ae28bSSean Wang WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT)); 148034ae28bSSean Wang 149034ae28bSSean Wang if (grant->reqtype == MT7921_ROC_REQ_ROC) 150034ae28bSSean Wang ieee80211_ready_on_channel(dev->mt76.phy.hw); 151034ae28bSSean Wang 152034ae28bSSean Wang dev->phy.roc_grant = true; 153034ae28bSSean Wang wake_up(&dev->phy.roc_wait); 154034ae28bSSean Wang duration = le32_to_cpu(grant->max_interval); 155034ae28bSSean Wang mod_timer(&dev->phy.roc_timer, 156c36457a8SDeren Wu jiffies + msecs_to_jiffies(duration)); 157034ae28bSSean Wang } 158034ae28bSSean Wang 159034ae28bSSean Wang static void 1601c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) 1611c099ab4SSean Wang { 1621c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 1631c099ab4SSean Wang struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; 1641c099ab4SSean Wang 1651c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock); 1661c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb); 1671c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock); 1681c099ab4SSean Wang 1691c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, 1701c099ab4SSean Wang MT7921_HW_SCAN_TIMEOUT); 1711c099ab4SSean Wang } 1721c099ab4SSean Wang 1731c099ab4SSean Wang static void 17410de032aSSean Wang mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, 17510de032aSSean Wang struct ieee80211_vif *vif) 17610de032aSSean Wang { 17710de032aSSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 17810de032aSSean Wang struct mt76_connac_beacon_loss_event *event = priv; 17910de032aSSean Wang 18010de032aSSean Wang if (mvif->idx != event->bss_idx) 18110de032aSSean Wang return; 18210de032aSSean Wang 183116c6960SSean Wang if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) || 184116c6960SSean Wang vif->type != NL80211_IFTYPE_STATION) 18510de032aSSean Wang return; 18610de032aSSean Wang 18710de032aSSean Wang ieee80211_connection_loss(vif); 18810de032aSSean Wang } 18910de032aSSean Wang 19010de032aSSean Wang static void 19110de032aSSean Wang mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) 192b88f5c64SSean Wang { 19367aa2743SLorenzo Bianconi struct mt76_connac_beacon_loss_event *event; 19410de032aSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 195b88f5c64SSean Wang 196fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); 19767aa2743SLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data; 198b88f5c64SSean Wang 199b88f5c64SSean Wang ieee80211_iterate_active_interfaces_atomic(mphy->hw, 200b88f5c64SSean Wang IEEE80211_IFACE_ITER_RESUME_ALL, 20110de032aSSean Wang mt7921_mcu_connection_loss_iter, event); 202b88f5c64SSean Wang } 203b88f5c64SSean Wang 204b88f5c64SSean Wang static void 2051c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) 2061c099ab4SSean Wang { 207c7cc5ec5SLorenzo Bianconi struct mt7921_debug_msg { 2081c099ab4SSean Wang __le16 id; 2091c099ab4SSean Wang u8 type; 2101c099ab4SSean Wang u8 flag; 2111c099ab4SSean Wang __le32 value; 2121c099ab4SSean Wang __le16 len; 2131c099ab4SSean Wang u8 content[512]; 214c7cc5ec5SLorenzo Bianconi } __packed * msg; 215c7cc5ec5SLorenzo Bianconi 216fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); 217c7cc5ec5SLorenzo Bianconi msg = (struct mt7921_debug_msg *)skb->data; 218c7cc5ec5SLorenzo Bianconi 219c7cc5ec5SLorenzo Bianconi if (msg->type == 3) { /* fw log */ 220c7cc5ec5SLorenzo Bianconi u16 len = min_t(u16, le16_to_cpu(msg->len), 512); 2211c099ab4SSean Wang int i; 2221c099ab4SSean Wang 223c7cc5ec5SLorenzo Bianconi for (i = 0 ; i < len; i++) { 224c7cc5ec5SLorenzo Bianconi if (!msg->content[i]) 225c7cc5ec5SLorenzo Bianconi msg->content[i] = ' '; 226c7cc5ec5SLorenzo Bianconi } 2272bf301bcSDan Carpenter wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content); 2281c099ab4SSean Wang } 2291c099ab4SSean Wang } 2301c099ab4SSean Wang 2311c099ab4SSean Wang static void 2322afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) 2332afd17b4SLorenzo Bianconi { 2342afd17b4SLorenzo Bianconi struct mt7921_mcu_lp_event { 2352afd17b4SLorenzo Bianconi u8 state; 2362afd17b4SLorenzo Bianconi u8 reserved[3]; 2372afd17b4SLorenzo Bianconi } __packed * event; 2382afd17b4SLorenzo Bianconi 239fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); 2402afd17b4SLorenzo Bianconi event = (struct mt7921_mcu_lp_event *)skb->data; 2412afd17b4SLorenzo Bianconi 2422afd17b4SLorenzo Bianconi trace_lp_event(dev, event->state); 2432afd17b4SLorenzo Bianconi } 2442afd17b4SLorenzo Bianconi 2452afd17b4SLorenzo Bianconi static void 246e0bf699aSDeren Wu mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) 247e0bf699aSDeren Wu { 248e0bf699aSDeren Wu struct mt7921_mcu_tx_done_event *event; 249e0bf699aSDeren Wu 250fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); 251e0bf699aSDeren Wu event = (struct mt7921_mcu_tx_done_event *)skb->data; 252e0bf699aSDeren Wu 253e0bf699aSDeren Wu mt7921_mac_add_txs(dev, event->txs); 254e0bf699aSDeren Wu } 255e0bf699aSDeren Wu 256e0bf699aSDeren Wu static void 2571c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 2581c099ab4SSean Wang { 259fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd; 2601c099ab4SSean Wang 261fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 2621c099ab4SSean Wang switch (rxd->eid) { 2631c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS: 26410de032aSSean Wang mt7921_mcu_connection_loss_event(dev, skb); 2651c099ab4SSean Wang break; 2661c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE: 2671c099ab4SSean Wang case MCU_EVENT_SCAN_DONE: 2681c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb); 2691c099ab4SSean Wang return; 2701c099ab4SSean Wang case MCU_EVENT_DBG_MSG: 2711c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb); 2721c099ab4SSean Wang break; 2730da3c795SSean Wang case MCU_EVENT_COREDUMP: 274ca74b9b9SSean Wang dev->fw_assert = true; 2750da3c795SSean Wang mt76_connac_mcu_coredump_event(&dev->mt76, skb, 2760da3c795SSean Wang &dev->coredump); 2770da3c795SSean Wang return; 2782afd17b4SLorenzo Bianconi case MCU_EVENT_LP_INFO: 2792afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(dev, skb); 2802afd17b4SLorenzo Bianconi break; 281e0bf699aSDeren Wu case MCU_EVENT_TX_DONE: 282e0bf699aSDeren Wu mt7921_mcu_tx_done_event(dev, skb); 283e0bf699aSDeren Wu break; 2841c099ab4SSean Wang default: 2851c099ab4SSean Wang break; 2861c099ab4SSean Wang } 2871c099ab4SSean Wang dev_kfree_skb(skb); 2881c099ab4SSean Wang } 2891c099ab4SSean Wang 2905b55b6daSQuan Zhou static void 2915b55b6daSQuan Zhou mt7921_mcu_uni_rx_unsolicited_event(struct mt7921_dev *dev, 2925b55b6daSQuan Zhou struct sk_buff *skb) 2935b55b6daSQuan Zhou { 2945b55b6daSQuan Zhou struct mt76_connac2_mcu_rxd *rxd; 2955b55b6daSQuan Zhou 2965b55b6daSQuan Zhou rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 2975b55b6daSQuan Zhou 2985b55b6daSQuan Zhou switch (rxd->eid) { 2995b55b6daSQuan Zhou case MCU_UNI_EVENT_ROC: 300034ae28bSSean Wang mt7921_mcu_uni_roc_event(dev, skb); 3015b55b6daSQuan Zhou break; 3025b55b6daSQuan Zhou default: 3035b55b6daSQuan Zhou break; 3045b55b6daSQuan Zhou } 3055b55b6daSQuan Zhou dev_kfree_skb(skb); 3065b55b6daSQuan Zhou } 3075b55b6daSQuan Zhou 3081c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) 3091c099ab4SSean Wang { 310fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd; 311f0ff5d3aSSean Wang 312f0ff5d3aSSean Wang if (skb_linearize(skb)) 313f0ff5d3aSSean Wang return; 314f0ff5d3aSSean Wang 315fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 3161c099ab4SSean Wang 3175b55b6daSQuan Zhou if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) { 3185b55b6daSQuan Zhou mt7921_mcu_uni_rx_unsolicited_event(dev, skb); 3195b55b6daSQuan Zhou return; 3205b55b6daSQuan Zhou } 3215b55b6daSQuan Zhou 3221c099ab4SSean Wang if (rxd->eid == 0x6) { 3231c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 3241c099ab4SSean Wang return; 3251c099ab4SSean Wang } 3261c099ab4SSean Wang 3271c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || 3281c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || 3291c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || 3301c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE || 3313cce2b98SDeren Wu rxd->eid == MCU_EVENT_TX_DONE || 3321c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG || 3330da3c795SSean Wang rxd->eid == MCU_EVENT_COREDUMP || 3342afd17b4SLorenzo Bianconi rxd->eid == MCU_EVENT_LP_INFO || 3351c099ab4SSean Wang !rxd->seq) 3361c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb); 3371c099ab4SSean Wang else 3381c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb); 3391c099ab4SSean Wang } 3401c099ab4SSean Wang 3411c099ab4SSean Wang /** starec & wtbl **/ 3421c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, 3431c099ab4SSean Wang struct ieee80211_ampdu_params *params, 3441c099ab4SSean Wang bool enable) 3451c099ab4SSean Wang { 34667aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 34767aa2743SLorenzo Bianconi 34867aa2743SLorenzo Bianconi if (enable && !params->amsdu) 34967aa2743SLorenzo Bianconi msta->wcid.amsdu = false; 35067aa2743SLorenzo Bianconi 35167aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 352b5322e44SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), 35367aa2743SLorenzo Bianconi enable, true); 3541c099ab4SSean Wang } 3551c099ab4SSean Wang 3561c099ab4SSean Wang int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, 3571c099ab4SSean Wang struct ieee80211_ampdu_params *params, 3581c099ab4SSean Wang bool enable) 3591c099ab4SSean Wang { 36067aa2743SLorenzo Bianconi struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; 3611c099ab4SSean Wang 36267aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, 363b5322e44SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE), 36467aa2743SLorenzo Bianconi enable, false); 3651c099ab4SSean Wang } 3661c099ab4SSean Wang 36768808872SDeren Wu static char *mt7921_patch_name(struct mt7921_dev *dev) 36868808872SDeren Wu { 36968808872SDeren Wu char *ret; 37068808872SDeren Wu 37168808872SDeren Wu if (is_mt7922(&dev->mt76)) 37268808872SDeren Wu ret = MT7922_ROM_PATCH; 37368808872SDeren Wu else 37468808872SDeren Wu ret = MT7921_ROM_PATCH; 37568808872SDeren Wu 37668808872SDeren Wu return ret; 37768808872SDeren Wu } 37868808872SDeren Wu 37968808872SDeren Wu static char *mt7921_ram_name(struct mt7921_dev *dev) 38068808872SDeren Wu { 38168808872SDeren Wu char *ret; 38268808872SDeren Wu 38368808872SDeren Wu if (is_mt7922(&dev->mt76)) 38468808872SDeren Wu ret = MT7922_FIRMWARE_WM; 38568808872SDeren Wu else 38668808872SDeren Wu ret = MT7921_FIRMWARE_WM; 38768808872SDeren Wu 38868808872SDeren Wu return ret; 38968808872SDeren Wu } 39068808872SDeren Wu 39123bdc5d8SMing Yen Hsieh static int mt7921_load_clc(struct mt7921_dev *dev, const char *fw_name) 39223bdc5d8SMing Yen Hsieh { 39323bdc5d8SMing Yen Hsieh const struct mt76_connac2_fw_trailer *hdr; 39423bdc5d8SMing Yen Hsieh const struct mt76_connac2_fw_region *region; 39523bdc5d8SMing Yen Hsieh const struct mt7921_clc *clc; 39623bdc5d8SMing Yen Hsieh struct mt76_dev *mdev = &dev->mt76; 39723bdc5d8SMing Yen Hsieh struct mt7921_phy *phy = &dev->phy; 39823bdc5d8SMing Yen Hsieh const struct firmware *fw; 39923bdc5d8SMing Yen Hsieh int ret, i, len, offset = 0; 40023bdc5d8SMing Yen Hsieh u8 *clc_base = NULL, hw_encap = 0; 40123bdc5d8SMing Yen Hsieh 40223bdc5d8SMing Yen Hsieh if (mt7921_disable_clc || 40323bdc5d8SMing Yen Hsieh mt76_is_usb(&dev->mt76)) 40423bdc5d8SMing Yen Hsieh return 0; 40523bdc5d8SMing Yen Hsieh 40623bdc5d8SMing Yen Hsieh if (mt76_is_mmio(&dev->mt76)) { 40723bdc5d8SMing Yen Hsieh ret = mt7921_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap); 40823bdc5d8SMing Yen Hsieh if (ret) 40923bdc5d8SMing Yen Hsieh return ret; 41023bdc5d8SMing Yen Hsieh hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP); 41123bdc5d8SMing Yen Hsieh } 41223bdc5d8SMing Yen Hsieh 41323bdc5d8SMing Yen Hsieh ret = request_firmware(&fw, fw_name, mdev->dev); 41423bdc5d8SMing Yen Hsieh if (ret) 41523bdc5d8SMing Yen Hsieh return ret; 41623bdc5d8SMing Yen Hsieh 41723bdc5d8SMing Yen Hsieh if (!fw || !fw->data || fw->size < sizeof(*hdr)) { 41823bdc5d8SMing Yen Hsieh dev_err(mdev->dev, "Invalid firmware\n"); 41923bdc5d8SMing Yen Hsieh ret = -EINVAL; 42023bdc5d8SMing Yen Hsieh goto out; 42123bdc5d8SMing Yen Hsieh } 42223bdc5d8SMing Yen Hsieh 42323bdc5d8SMing Yen Hsieh hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); 42423bdc5d8SMing Yen Hsieh for (i = 0; i < hdr->n_region; i++) { 42523bdc5d8SMing Yen Hsieh region = (const void *)((const u8 *)hdr - 42623bdc5d8SMing Yen Hsieh (hdr->n_region - i) * sizeof(*region)); 42723bdc5d8SMing Yen Hsieh len = le32_to_cpu(region->len); 42823bdc5d8SMing Yen Hsieh 42923bdc5d8SMing Yen Hsieh /* check if we have valid buffer size */ 43023bdc5d8SMing Yen Hsieh if (offset + len > fw->size) { 43123bdc5d8SMing Yen Hsieh dev_err(mdev->dev, "Invalid firmware region\n"); 43223bdc5d8SMing Yen Hsieh ret = -EINVAL; 43323bdc5d8SMing Yen Hsieh goto out; 43423bdc5d8SMing Yen Hsieh } 43523bdc5d8SMing Yen Hsieh 43623bdc5d8SMing Yen Hsieh if ((region->feature_set & FW_FEATURE_NON_DL) && 43723bdc5d8SMing Yen Hsieh region->type == FW_TYPE_CLC) { 43823bdc5d8SMing Yen Hsieh clc_base = (u8 *)(fw->data + offset); 43923bdc5d8SMing Yen Hsieh break; 44023bdc5d8SMing Yen Hsieh } 44123bdc5d8SMing Yen Hsieh offset += len; 44223bdc5d8SMing Yen Hsieh } 44323bdc5d8SMing Yen Hsieh 44423bdc5d8SMing Yen Hsieh if (!clc_base) 44523bdc5d8SMing Yen Hsieh goto out; 44623bdc5d8SMing Yen Hsieh 44723bdc5d8SMing Yen Hsieh for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) { 44823bdc5d8SMing Yen Hsieh clc = (const struct mt7921_clc *)(clc_base + offset); 44923bdc5d8SMing Yen Hsieh 45023bdc5d8SMing Yen Hsieh /* do not init buf again if chip reset triggered */ 45123bdc5d8SMing Yen Hsieh if (phy->clc[clc->idx]) 45223bdc5d8SMing Yen Hsieh continue; 45323bdc5d8SMing Yen Hsieh 45423bdc5d8SMing Yen Hsieh /* header content sanity */ 45523bdc5d8SMing Yen Hsieh if (clc->idx == MT7921_CLC_POWER && 45623bdc5d8SMing Yen Hsieh u8_get_bits(clc->type, MT_EE_HW_TYPE_ENCAP) != hw_encap) 45723bdc5d8SMing Yen Hsieh continue; 45823bdc5d8SMing Yen Hsieh 45923bdc5d8SMing Yen Hsieh phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc, 46023bdc5d8SMing Yen Hsieh le32_to_cpu(clc->len), 46123bdc5d8SMing Yen Hsieh GFP_KERNEL); 46223bdc5d8SMing Yen Hsieh 46323bdc5d8SMing Yen Hsieh if (!phy->clc[clc->idx]) { 46423bdc5d8SMing Yen Hsieh ret = -ENOMEM; 46523bdc5d8SMing Yen Hsieh goto out; 46623bdc5d8SMing Yen Hsieh } 46723bdc5d8SMing Yen Hsieh } 46823bdc5d8SMing Yen Hsieh ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR); 46923bdc5d8SMing Yen Hsieh out: 47023bdc5d8SMing Yen Hsieh release_firmware(fw); 47123bdc5d8SMing Yen Hsieh 47223bdc5d8SMing Yen Hsieh return ret; 47323bdc5d8SMing Yen Hsieh } 47423bdc5d8SMing Yen Hsieh 4751c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev) 4761c099ab4SSean Wang { 4771c099ab4SSean Wang int ret; 4781c099ab4SSean Wang 47928fec923SLorenzo Bianconi ret = mt76_connac2_load_patch(&dev->mt76, mt7921_patch_name(dev)); 4801c099ab4SSean Wang if (ret) 4811c099ab4SSean Wang return ret; 4821c099ab4SSean Wang 483c132fc7dSLorenzo Bianconi if (mt76_is_sdio(&dev->mt76)) { 484c132fc7dSLorenzo Bianconi /* activate again */ 485c132fc7dSLorenzo Bianconi ret = __mt7921_mcu_fw_pmctrl(dev); 486c132fc7dSLorenzo Bianconi if (!ret) 487c132fc7dSLorenzo Bianconi ret = __mt7921_mcu_drv_pmctrl(dev); 488c132fc7dSLorenzo Bianconi } 489c132fc7dSLorenzo Bianconi 490b9ec2710SLorenzo Bianconi ret = mt76_connac2_load_ram(&dev->mt76, mt7921_ram_name(dev), NULL); 4911c099ab4SSean Wang if (ret) 4921c099ab4SSean Wang return ret; 4931c099ab4SSean Wang 4941c099ab4SSean Wang if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, 4951c099ab4SSean Wang MT_TOP_MISC2_FW_N9_RDY, 1500)) { 4961c099ab4SSean Wang dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 4971c099ab4SSean Wang 4981c099ab4SSean Wang return -EIO; 4991c099ab4SSean Wang } 5001c099ab4SSean Wang 501ffa1bf97SSean Wang #ifdef CONFIG_PM 502022159b0SLorenzo Bianconi dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; 503ffa1bf97SSean Wang #endif /* CONFIG_PM */ 504ffa1bf97SSean Wang 50581a88b1eSTzung-Bi Shih dev_dbg(dev->mt76.dev, "Firmware init done\n"); 5061c099ab4SSean Wang 5071c099ab4SSean Wang return 0; 5081c099ab4SSean Wang } 5091c099ab4SSean Wang 5101c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 5111c099ab4SSean Wang { 5121c099ab4SSean Wang struct { 5131c099ab4SSean Wang u8 ctrl_val; 5141c099ab4SSean Wang u8 pad[3]; 5151c099ab4SSean Wang } data = { 5161c099ab4SSean Wang .ctrl_val = ctrl 5171c099ab4SSean Wang }; 5181c099ab4SSean Wang 519680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(FWLOG_2_HOST), 520680a2eadSLorenzo Bianconi &data, sizeof(data), false); 5211c099ab4SSean Wang } 5221c099ab4SSean Wang 523d32464e6SLorenzo Bianconi int mt7921_run_firmware(struct mt7921_dev *dev) 524d32464e6SLorenzo Bianconi { 525d32464e6SLorenzo Bianconi int err; 526d32464e6SLorenzo Bianconi 527d32464e6SLorenzo Bianconi err = mt7921_load_firmware(dev); 528d32464e6SLorenzo Bianconi if (err) 529d32464e6SLorenzo Bianconi return err; 530d32464e6SLorenzo Bianconi 53116d98b54SSean Wang err = mt76_connac_mcu_get_nic_capability(&dev->mphy); 53216d98b54SSean Wang if (err) 53316d98b54SSean Wang return err; 534d32464e6SLorenzo Bianconi 53516d98b54SSean Wang set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 53623bdc5d8SMing Yen Hsieh err = mt7921_load_clc(dev, mt7921_ram_name(dev)); 53723bdc5d8SMing Yen Hsieh if (err) 53823bdc5d8SMing Yen Hsieh return err; 53923bdc5d8SMing Yen Hsieh 54016d98b54SSean Wang return mt7921_mcu_fw_log_2_host(dev, 1); 541d32464e6SLorenzo Bianconi } 5428910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_run_firmware); 543d32464e6SLorenzo Bianconi 5441c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) 5451c099ab4SSean Wang { 546*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 5471c099ab4SSean Wang struct edca { 54866ca1a7bSSean Wang __le16 cw_min; 5491c099ab4SSean Wang __le16 cw_max; 5501c099ab4SSean Wang __le16 txop; 55166ca1a7bSSean Wang __le16 aifs; 55266ca1a7bSSean Wang u8 guardtime; 55366ca1a7bSSean Wang u8 acm; 55466ca1a7bSSean Wang } __packed; 5551c099ab4SSean Wang struct mt7921_mcu_tx { 5561c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS]; 55766ca1a7bSSean Wang u8 bss_idx; 55866ca1a7bSSean Wang u8 qos; 55966ca1a7bSSean Wang u8 wmm_idx; 56066ca1a7bSSean Wang u8 pad; 5611c099ab4SSean Wang } __packed req = { 56266ca1a7bSSean Wang .bss_idx = mvif->mt76.idx, 56366ca1a7bSSean Wang .qos = vif->bss_conf.qos, 56466ca1a7bSSean Wang .wmm_idx = mvif->mt76.wmm_idx, 5651c099ab4SSean Wang }; 566bb0ae4cfSSean Wang struct mu_edca { 567bb0ae4cfSSean Wang u8 cw_min; 568bb0ae4cfSSean Wang u8 cw_max; 569bb0ae4cfSSean Wang u8 aifsn; 570bb0ae4cfSSean Wang u8 acm; 571bb0ae4cfSSean Wang u8 timer; 572bb0ae4cfSSean Wang u8 padding[3]; 573bb0ae4cfSSean Wang }; 574bb0ae4cfSSean Wang struct mt7921_mcu_mu_tx { 575bb0ae4cfSSean Wang u8 ver; 576bb0ae4cfSSean Wang u8 pad0; 577bb0ae4cfSSean Wang __le16 len; 578bb0ae4cfSSean Wang u8 bss_idx; 579bb0ae4cfSSean Wang u8 qos; 580bb0ae4cfSSean Wang u8 wmm_idx; 581bb0ae4cfSSean Wang u8 pad1; 582bb0ae4cfSSean Wang struct mu_edca edca[IEEE80211_NUM_ACS]; 583bb0ae4cfSSean Wang u8 pad3[32]; 584bb0ae4cfSSean Wang } __packed req_mu = { 585bb0ae4cfSSean Wang .bss_idx = mvif->mt76.idx, 586bb0ae4cfSSean Wang .qos = vif->bss_conf.qos, 587bb0ae4cfSSean Wang .wmm_idx = mvif->mt76.wmm_idx, 588bb0ae4cfSSean Wang }; 5894abe5b92SLorenzo Bianconi static const int to_aci[] = { 1, 0, 2, 3 }; 590bb0ae4cfSSean Wang int ac, ret; 5911c099ab4SSean Wang 5921c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 5931c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 59466ca1a7bSSean Wang struct edca *e = &req.edca[to_aci[ac]]; 5951c099ab4SSean Wang 5964abe5b92SLorenzo Bianconi e->aifs = cpu_to_le16(q->aifs); 5971c099ab4SSean Wang e->txop = cpu_to_le16(q->txop); 5981c099ab4SSean Wang 5991c099ab4SSean Wang if (q->cw_min) 60066ca1a7bSSean Wang e->cw_min = cpu_to_le16(q->cw_min); 6011c099ab4SSean Wang else 6024abe5b92SLorenzo Bianconi e->cw_min = cpu_to_le16(5); 6031c099ab4SSean Wang 6041c099ab4SSean Wang if (q->cw_max) 60566ca1a7bSSean Wang e->cw_max = cpu_to_le16(q->cw_max); 6061c099ab4SSean Wang else 6071c099ab4SSean Wang e->cw_max = cpu_to_le16(10); 6081c099ab4SSean Wang } 609bb0ae4cfSSean Wang 61066ca1a7bSSean Wang ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_EDCA_PARMS), &req, 61166ca1a7bSSean Wang sizeof(req), false); 612bb0ae4cfSSean Wang if (ret) 613bb0ae4cfSSean Wang return ret; 614bb0ae4cfSSean Wang 615bb0ae4cfSSean Wang if (!vif->bss_conf.he_support) 616bb0ae4cfSSean Wang return 0; 617bb0ae4cfSSean Wang 618bb0ae4cfSSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 619bb0ae4cfSSean Wang struct ieee80211_he_mu_edca_param_ac_rec *q; 620bb0ae4cfSSean Wang struct mu_edca *e; 621bb0ae4cfSSean Wang 622bb0ae4cfSSean Wang if (!mvif->queue_params[ac].mu_edca) 623bb0ae4cfSSean Wang break; 624bb0ae4cfSSean Wang 625bb0ae4cfSSean Wang q = &mvif->queue_params[ac].mu_edca_param_rec; 626bb0ae4cfSSean Wang e = &(req_mu.edca[to_aci[ac]]); 627bb0ae4cfSSean Wang 628bb0ae4cfSSean Wang e->cw_min = q->ecw_min_max & 0xf; 629bb0ae4cfSSean Wang e->cw_max = (q->ecw_min_max & 0xf0) >> 4; 630bb0ae4cfSSean Wang e->aifsn = q->aifsn; 631bb0ae4cfSSean Wang e->timer = q->mu_edca_timer; 632bb0ae4cfSSean Wang } 633bb0ae4cfSSean Wang 634680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_MU_EDCA_PARMS), 635680a2eadSLorenzo Bianconi &req_mu, sizeof(req_mu), false); 6361c099ab4SSean Wang } 6371c099ab4SSean Wang 638*15ca8970SLorenzo Bianconi int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt792x_vif *vif, 6395b55b6daSQuan Zhou struct ieee80211_channel *chan, int duration, 6405b55b6daSQuan Zhou enum mt7921_roc_req type, u8 token_id) 6415b55b6daSQuan Zhou { 6425b55b6daSQuan Zhou int center_ch = ieee80211_frequency_to_channel(chan->center_freq); 6435b55b6daSQuan Zhou struct mt7921_dev *dev = phy->dev; 6445b55b6daSQuan Zhou struct { 6455b55b6daSQuan Zhou struct { 6465b55b6daSQuan Zhou u8 rsv[4]; 6475b55b6daSQuan Zhou } __packed hdr; 6485b55b6daSQuan Zhou struct roc_acquire_tlv { 6495b55b6daSQuan Zhou __le16 tag; 6505b55b6daSQuan Zhou __le16 len; 6515b55b6daSQuan Zhou u8 bss_idx; 6525b55b6daSQuan Zhou u8 tokenid; 6535b55b6daSQuan Zhou u8 control_channel; 6545b55b6daSQuan Zhou u8 sco; 6555b55b6daSQuan Zhou u8 band; 6565b55b6daSQuan Zhou u8 bw; 6575b55b6daSQuan Zhou u8 center_chan; 6585b55b6daSQuan Zhou u8 center_chan2; 6595b55b6daSQuan Zhou u8 bw_from_ap; 6605b55b6daSQuan Zhou u8 center_chan_from_ap; 6615b55b6daSQuan Zhou u8 center_chan2_from_ap; 6625b55b6daSQuan Zhou u8 reqtype; 6635b55b6daSQuan Zhou __le32 maxinterval; 6645b55b6daSQuan Zhou u8 dbdcband; 6655b55b6daSQuan Zhou u8 rsv[3]; 6665b55b6daSQuan Zhou } __packed roc; 6675b55b6daSQuan Zhou } __packed req = { 6685b55b6daSQuan Zhou .roc = { 6695b55b6daSQuan Zhou .tag = cpu_to_le16(UNI_ROC_ACQUIRE), 6705b55b6daSQuan Zhou .len = cpu_to_le16(sizeof(struct roc_acquire_tlv)), 6715b55b6daSQuan Zhou .tokenid = token_id, 6725b55b6daSQuan Zhou .reqtype = type, 6735b55b6daSQuan Zhou .maxinterval = cpu_to_le32(duration), 6745b55b6daSQuan Zhou .bss_idx = vif->mt76.idx, 6755b55b6daSQuan Zhou .control_channel = chan->hw_value, 6765b55b6daSQuan Zhou .bw = CMD_CBW_20MHZ, 6775b55b6daSQuan Zhou .bw_from_ap = CMD_CBW_20MHZ, 6785b55b6daSQuan Zhou .center_chan = center_ch, 6795b55b6daSQuan Zhou .center_chan_from_ap = center_ch, 6805b55b6daSQuan Zhou .dbdcband = 0xff, /* auto */ 6815b55b6daSQuan Zhou }, 6825b55b6daSQuan Zhou }; 6835b55b6daSQuan Zhou 6845b55b6daSQuan Zhou if (chan->hw_value < center_ch) 6855b55b6daSQuan Zhou req.roc.sco = 1; /* SCA */ 6865b55b6daSQuan Zhou else if (chan->hw_value > center_ch) 6875b55b6daSQuan Zhou req.roc.sco = 3; /* SCB */ 6885b55b6daSQuan Zhou 6895b55b6daSQuan Zhou switch (chan->band) { 6905b55b6daSQuan Zhou case NL80211_BAND_6GHZ: 6915b55b6daSQuan Zhou req.roc.band = 3; 6925b55b6daSQuan Zhou break; 6935b55b6daSQuan Zhou case NL80211_BAND_5GHZ: 6945b55b6daSQuan Zhou req.roc.band = 2; 6955b55b6daSQuan Zhou break; 6965b55b6daSQuan Zhou default: 6975b55b6daSQuan Zhou req.roc.band = 1; 6985b55b6daSQuan Zhou break; 6995b55b6daSQuan Zhou } 7005b55b6daSQuan Zhou 7015b55b6daSQuan Zhou return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC), 7025b55b6daSQuan Zhou &req, sizeof(req), false); 7035b55b6daSQuan Zhou } 7045b55b6daSQuan Zhou 705*15ca8970SLorenzo Bianconi int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt792x_vif *vif, 7065b55b6daSQuan Zhou u8 token_id) 7075b55b6daSQuan Zhou { 7085b55b6daSQuan Zhou struct mt7921_dev *dev = phy->dev; 7095b55b6daSQuan Zhou struct { 7105b55b6daSQuan Zhou struct { 7115b55b6daSQuan Zhou u8 rsv[4]; 7125b55b6daSQuan Zhou } __packed hdr; 7135b55b6daSQuan Zhou struct roc_abort_tlv { 7145b55b6daSQuan Zhou __le16 tag; 7155b55b6daSQuan Zhou __le16 len; 7165b55b6daSQuan Zhou u8 bss_idx; 7175b55b6daSQuan Zhou u8 tokenid; 7185b55b6daSQuan Zhou u8 dbdcband; 7195b55b6daSQuan Zhou u8 rsv[5]; 7205b55b6daSQuan Zhou } __packed abort; 7215b55b6daSQuan Zhou } __packed req = { 7225b55b6daSQuan Zhou .abort = { 7235b55b6daSQuan Zhou .tag = cpu_to_le16(UNI_ROC_ABORT), 7245b55b6daSQuan Zhou .len = cpu_to_le16(sizeof(struct roc_abort_tlv)), 7255b55b6daSQuan Zhou .tokenid = token_id, 7265b55b6daSQuan Zhou .bss_idx = vif->mt76.idx, 7275b55b6daSQuan Zhou .dbdcband = 0xff, /* auto*/ 7285b55b6daSQuan Zhou }, 7295b55b6daSQuan Zhou }; 7305b55b6daSQuan Zhou 7315b55b6daSQuan Zhou return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC), 7325b55b6daSQuan Zhou &req, sizeof(req), false); 7335b55b6daSQuan Zhou } 7345b55b6daSQuan Zhou 7351c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) 7361c099ab4SSean Wang { 7371c099ab4SSean Wang struct mt7921_dev *dev = phy->dev; 7381c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 7391c099ab4SSean Wang int freq1 = chandef->center_freq1; 7401c099ab4SSean Wang struct { 7411c099ab4SSean Wang u8 control_ch; 7421c099ab4SSean Wang u8 center_ch; 7431c099ab4SSean Wang u8 bw; 7441c099ab4SSean Wang u8 tx_streams_num; 7451c099ab4SSean Wang u8 rx_streams; /* mask or num */ 7461c099ab4SSean Wang u8 switch_reason; 7471c099ab4SSean Wang u8 band_idx; 7481c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */ 7491c099ab4SSean Wang __le16 cac_case; 7501c099ab4SSean Wang u8 channel_band; 7511c099ab4SSean Wang u8 rsv0; 7521c099ab4SSean Wang __le32 outband_freq; 7531c099ab4SSean Wang u8 txpower_drop; 7541c099ab4SSean Wang u8 ap_bw; 7551c099ab4SSean Wang u8 ap_center_ch; 7561c099ab4SSean Wang u8 rsv1[57]; 7571c099ab4SSean Wang } __packed req = { 7581c099ab4SSean Wang .control_ch = chandef->chan->hw_value, 7591c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1), 76044c73d17SLorenzo Bianconi .bw = mt76_connac_chan_bw(chandef), 7611c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask), 7621c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask, 7631c099ab4SSean Wang .band_idx = phy != &dev->phy, 7641c099ab4SSean Wang }; 7651c099ab4SSean Wang 76650ac15a5SLorenzo Bianconi if (chandef->chan->band == NL80211_BAND_6GHZ) 76750ac15a5SLorenzo Bianconi req.channel_band = 2; 76850ac15a5SLorenzo Bianconi else 76950ac15a5SLorenzo Bianconi req.channel_band = chandef->chan->band; 77050ac15a5SLorenzo Bianconi 77124e69f6bSDeren Wu if (cmd == MCU_EXT_CMD(SET_RX_PATH) || 77224e69f6bSDeren Wu dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) 77300a883e6SFelix Fietkau req.switch_reason = CH_SWITCH_NORMAL; 77400a883e6SFelix Fietkau else if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 7751c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 77600a883e6SFelix Fietkau else if (!cfg80211_reg_can_beacon(dev->mt76.hw->wiphy, chandef, 77700a883e6SFelix Fietkau NL80211_IFTYPE_AP)) 7781c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS; 7791c099ab4SSean Wang else 7801c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL; 7811c099ab4SSean Wang 782e6d2070dSLorenzo Bianconi if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) 7831c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams); 7841c099ab4SSean Wang 7851c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 7861c099ab4SSean Wang int freq2 = chandef->center_freq2; 7871c099ab4SSean Wang 7881c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2); 7891c099ab4SSean Wang } 7901c099ab4SSean Wang 7911c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 7921c099ab4SSean Wang } 7931c099ab4SSean Wang 7941c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) 7951c099ab4SSean Wang { 7961c099ab4SSean Wang struct req_hdr { 7971c099ab4SSean Wang u8 buffer_mode; 7981c099ab4SSean Wang u8 format; 7991c099ab4SSean Wang __le16 len; 8001c099ab4SSean Wang } __packed req = { 8011c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE, 8021c099ab4SSean Wang .format = EE_FORMAT_WHOLE, 8031c099ab4SSean Wang }; 8041c099ab4SSean Wang 805e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE), 8061c099ab4SSean Wang &req, sizeof(req), true); 8071c099ab4SSean Wang } 8088910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom); 8091c099ab4SSean Wang 81056d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) 81156d965daSSean Wang { 812*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 81356d965daSSean Wang struct { 81456d965daSSean Wang struct { 81556d965daSSean Wang u8 bss_idx; 81656d965daSSean Wang u8 pad[3]; 81756d965daSSean Wang } __packed hdr; 81856d965daSSean Wang struct ps_tlv { 81956d965daSSean Wang __le16 tag; 82056d965daSSean Wang __le16 len; 82156d965daSSean Wang u8 ps_state; /* 0: device awake 82256d965daSSean Wang * 1: static power save 82356d965daSSean Wang * 2: dynamic power saving 82456d965daSSean Wang * 3: enter TWT power saving 82556d965daSSean Wang * 4: leave TWT power saving 82656d965daSSean Wang */ 82756d965daSSean Wang u8 pad[3]; 82856d965daSSean Wang } __packed ps; 82956d965daSSean Wang } __packed ps_req = { 83056d965daSSean Wang .hdr = { 83156d965daSSean Wang .bss_idx = mvif->mt76.idx, 83256d965daSSean Wang }, 83356d965daSSean Wang .ps = { 83456d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS), 83556d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)), 836a3b8008dSJohannes Berg .ps_state = vif->cfg.ps ? 2 : 0, 83756d965daSSean Wang }, 83856d965daSSean Wang }; 83956d965daSSean Wang 84056d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION) 84156d965daSSean Wang return -EOPNOTSUPP; 84256d965daSSean Wang 84354722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), 84456d965daSSean Wang &ps_req, sizeof(ps_req), true); 84556d965daSSean Wang } 8464086ee28SSean Wang 847890809caSLorenzo Bianconi static int 848890809caSLorenzo Bianconi mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, 8494086ee28SSean Wang bool enable) 8504086ee28SSean Wang { 851*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 8524086ee28SSean Wang struct { 8534086ee28SSean Wang struct { 8544086ee28SSean Wang u8 bss_idx; 8554086ee28SSean Wang u8 pad[3]; 8564086ee28SSean Wang } __packed hdr; 8574086ee28SSean Wang struct bcnft_tlv { 8584086ee28SSean Wang __le16 tag; 8594086ee28SSean Wang __le16 len; 8604086ee28SSean Wang __le16 bcn_interval; 8614086ee28SSean Wang u8 dtim_period; 8624086ee28SSean Wang u8 pad; 8634086ee28SSean Wang } __packed bcnft; 8644086ee28SSean Wang } __packed bcnft_req = { 8654086ee28SSean Wang .hdr = { 8664086ee28SSean Wang .bss_idx = mvif->mt76.idx, 8674086ee28SSean Wang }, 8684086ee28SSean Wang .bcnft = { 8694086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), 8704086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)), 8714086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 8724086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 8734086ee28SSean Wang }, 8744086ee28SSean Wang }; 8754086ee28SSean Wang 8764086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION) 8774086ee28SSean Wang return 0; 8784086ee28SSean Wang 87954722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), 8804086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true); 8814086ee28SSean Wang } 8824086ee28SSean Wang 8839d958b60SDeren Wu int 884890809caSLorenzo Bianconi mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, 8854086ee28SSean Wang bool enable) 8864086ee28SSean Wang { 887*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 8884086ee28SSean Wang struct { 8894086ee28SSean Wang u8 bss_idx; 8904086ee28SSean Wang u8 dtim_period; 8914086ee28SSean Wang __le16 aid; 8924086ee28SSean Wang __le16 bcn_interval; 8934086ee28SSean Wang __le16 atim_window; 8944086ee28SSean Wang u8 uapsd; 8954086ee28SSean Wang u8 bmc_delivered_ac; 8964086ee28SSean Wang u8 bmc_triggered_ac; 8974086ee28SSean Wang u8 pad; 8984086ee28SSean Wang } req = { 8994086ee28SSean Wang .bss_idx = mvif->mt76.idx, 900f276e20bSJohannes Berg .aid = cpu_to_le16(vif->cfg.aid), 9014086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period, 9024086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), 9034086ee28SSean Wang }; 9044086ee28SSean Wang struct { 9054086ee28SSean Wang u8 bss_idx; 9064086ee28SSean Wang u8 pad[3]; 9074086ee28SSean Wang } req_hdr = { 9084086ee28SSean Wang .bss_idx = mvif->mt76.idx, 9094086ee28SSean Wang }; 9104086ee28SSean Wang int err; 9114086ee28SSean Wang 912680a2eadSLorenzo Bianconi err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT), 913680a2eadSLorenzo Bianconi &req_hdr, sizeof(req_hdr), false); 9144086ee28SSean Wang if (err < 0 || !enable) 9154086ee28SSean Wang return err; 9164086ee28SSean Wang 917680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED), 918680a2eadSLorenzo Bianconi &req, sizeof(req), false); 9194086ee28SSean Wang } 9201d8efc74SSean Wang 921f5056657SSean Wang int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, 922f5056657SSean Wang struct ieee80211_vif *vif, bool enable, 923f5056657SSean Wang enum mt76_sta_info_state state) 92436fcc8cfSLorenzo Bianconi { 925*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 92636fcc8cfSLorenzo Bianconi int rssi = -ewma_rssi_read(&mvif->rssi); 92736fcc8cfSLorenzo Bianconi struct mt76_sta_cmd_info info = { 92836fcc8cfSLorenzo Bianconi .sta = sta, 92936fcc8cfSLorenzo Bianconi .vif = vif, 93036fcc8cfSLorenzo Bianconi .enable = enable, 93154722402SLorenzo Bianconi .cmd = MCU_UNI_CMD(STA_REC_UPDATE), 932f5056657SSean Wang .state = state, 93382453b1cSLorenzo Bianconi .offload_fw = true, 93436fcc8cfSLorenzo Bianconi .rcpi = to_rcpi(rssi), 93536fcc8cfSLorenzo Bianconi }; 93636fcc8cfSLorenzo Bianconi struct mt7921_sta *msta; 93736fcc8cfSLorenzo Bianconi 93836fcc8cfSLorenzo Bianconi msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; 93936fcc8cfSLorenzo Bianconi info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; 940f5056657SSean Wang info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; 94136fcc8cfSLorenzo Bianconi 942f5056657SSean Wang return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); 94336fcc8cfSLorenzo Bianconi } 94436fcc8cfSLorenzo Bianconi 9457bf0a71eSSean Wang int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) 9467bf0a71eSSean Wang { 9477bf0a71eSSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 9487bf0a71eSSean Wang struct mt76_connac_pm *pm = &dev->pm; 9497bf0a71eSSean Wang int err = 0; 9507bf0a71eSSean Wang 9517bf0a71eSSean Wang mutex_lock(&pm->mutex); 9527bf0a71eSSean Wang 9537bf0a71eSSean Wang if (!test_bit(MT76_STATE_PM, &mphy->state)) 9547bf0a71eSSean Wang goto out; 9557bf0a71eSSean Wang 9567bf0a71eSSean Wang err = __mt7921_mcu_drv_pmctrl(dev); 9577bf0a71eSSean Wang out: 95836873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 9591d8efc74SSean Wang 960fad90e43SLorenzo Bianconi if (err) 961fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 962fad90e43SLorenzo Bianconi 963fad90e43SLorenzo Bianconi return err; 9641d8efc74SSean Wang } 9658910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl); 9661d8efc74SSean Wang 9671d8efc74SSean Wang int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) 9681d8efc74SSean Wang { 9691d8efc74SSean Wang struct mt76_phy *mphy = &dev->mt76.phy; 97036873246SLorenzo Bianconi struct mt76_connac_pm *pm = &dev->pm; 971dfc7743dSSean Wang int err = 0; 972fad90e43SLorenzo Bianconi 97336873246SLorenzo Bianconi mutex_lock(&pm->mutex); 9741d8efc74SSean Wang 97536873246SLorenzo Bianconi if (mt76_connac_skip_fw_pmctrl(mphy, pm)) 976fad90e43SLorenzo Bianconi goto out; 9771d8efc74SSean Wang 978dfc7743dSSean Wang err = __mt7921_mcu_fw_pmctrl(dev); 979fad90e43SLorenzo Bianconi out: 98036873246SLorenzo Bianconi mutex_unlock(&pm->mutex); 9811d8efc74SSean Wang 982fad90e43SLorenzo Bianconi if (err) 983fad90e43SLorenzo Bianconi mt7921_reset(&dev->mt76); 984fad90e43SLorenzo Bianconi 985fad90e43SLorenzo Bianconi return err; 9861d8efc74SSean Wang } 9878910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl); 9881d8efc74SSean Wang 989890809caSLorenzo Bianconi int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, 990890809caSLorenzo Bianconi struct ieee80211_vif *vif, 991890809caSLorenzo Bianconi bool enable) 9921d8efc74SSean Wang { 993c222f77fSNeil Chen #define MT7921_FIF_BIT_CLR BIT(1) 994c222f77fSNeil Chen #define MT7921_FIF_BIT_SET BIT(0) 995890809caSLorenzo Bianconi int err; 9961d8efc74SSean Wang 997890809caSLorenzo Bianconi if (enable) { 998890809caSLorenzo Bianconi err = mt7921_mcu_uni_bss_bcnft(dev, vif, true); 999890809caSLorenzo Bianconi if (err) 1000890809caSLorenzo Bianconi return err; 1001159f6dd6SSean Wang 1002c222f77fSNeil Chen err = mt7921_mcu_set_rxfilter(dev, 0, 1003c222f77fSNeil Chen MT7921_FIF_BIT_SET, 1004c222f77fSNeil Chen MT_WF_RFCR_DROP_OTHER_BEACON); 1005c222f77fSNeil Chen if (err) 1006c222f77fSNeil Chen return err; 1007890809caSLorenzo Bianconi 1008890809caSLorenzo Bianconi return 0; 1009890809caSLorenzo Bianconi } 1010890809caSLorenzo Bianconi 1011890809caSLorenzo Bianconi err = mt7921_mcu_set_bss_pm(dev, vif, false); 1012890809caSLorenzo Bianconi if (err) 1013890809caSLorenzo Bianconi return err; 1014890809caSLorenzo Bianconi 1015c222f77fSNeil Chen err = mt7921_mcu_set_rxfilter(dev, 0, 1016c222f77fSNeil Chen MT7921_FIF_BIT_CLR, 1017c222f77fSNeil Chen MT_WF_RFCR_DROP_OTHER_BEACON); 1018c222f77fSNeil Chen if (err) 1019c222f77fSNeil Chen return err; 1020890809caSLorenzo Bianconi 1021890809caSLorenzo Bianconi return 0; 10221d8efc74SSean Wang } 10239c9d8321SSean Wang 1024ea29acc9SSean Wang int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr) 1025ea29acc9SSean Wang { 1026ea29acc9SSean Wang struct mt7921_txpwr_event *event; 1027ea29acc9SSean Wang struct mt7921_txpwr_req req = { 1028ea29acc9SSean Wang .dbdc_idx = 0, 1029ea29acc9SSean Wang }; 1030ea29acc9SSean Wang struct sk_buff *skb; 1031ea29acc9SSean Wang int ret; 1032ea29acc9SSean Wang 1033680a2eadSLorenzo Bianconi ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(GET_TXPWR), 1034ea29acc9SSean Wang &req, sizeof(req), true, &skb); 1035ea29acc9SSean Wang if (ret) 1036ea29acc9SSean Wang return ret; 1037ea29acc9SSean Wang 1038ea29acc9SSean Wang event = (struct mt7921_txpwr_event *)skb->data; 1039ea29acc9SSean Wang WARN_ON(skb->len != le16_to_cpu(event->len)); 1040ea29acc9SSean Wang memcpy(txpwr, &event->txpwr, sizeof(event->txpwr)); 1041ea29acc9SSean Wang 1042ea29acc9SSean Wang dev_kfree_skb(skb); 1043ea29acc9SSean Wang 1044ea29acc9SSean Wang return 0; 1045ea29acc9SSean Wang } 1046cbaa0a40SSean Wang 1047cbaa0a40SSean Wang int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif, 1048cbaa0a40SSean Wang bool enable) 1049cbaa0a40SSean Wang { 1050cbaa0a40SSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 1051cbaa0a40SSean Wang struct { 1052cbaa0a40SSean Wang struct { 1053cbaa0a40SSean Wang u8 band_idx; 1054cbaa0a40SSean Wang u8 pad[3]; 1055cbaa0a40SSean Wang } __packed hdr; 1056cbaa0a40SSean Wang struct sniffer_enable_tlv { 1057cbaa0a40SSean Wang __le16 tag; 1058cbaa0a40SSean Wang __le16 len; 1059cbaa0a40SSean Wang u8 enable; 1060cbaa0a40SSean Wang u8 pad[3]; 1061cbaa0a40SSean Wang } __packed enable; 1062cbaa0a40SSean Wang } req = { 1063cbaa0a40SSean Wang .hdr = { 1064cbaa0a40SSean Wang .band_idx = mvif->band_idx, 1065cbaa0a40SSean Wang }, 1066cbaa0a40SSean Wang .enable = { 1067cbaa0a40SSean Wang .tag = cpu_to_le16(0), 1068cbaa0a40SSean Wang .len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)), 1069cbaa0a40SSean Wang .enable = enable, 1070cbaa0a40SSean Wang }, 1071cbaa0a40SSean Wang }; 1072cbaa0a40SSean Wang 1073cbaa0a40SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), 1074cbaa0a40SSean Wang true); 1075cbaa0a40SSean Wang } 1076116c6960SSean Wang 1077*15ca8970SLorenzo Bianconi int mt7921_mcu_config_sniffer(struct mt792x_vif *vif, 1078914189afSDeren Wu struct ieee80211_chanctx_conf *ctx) 1079914189afSDeren Wu { 1080914189afSDeren Wu struct cfg80211_chan_def *chandef = &ctx->def; 1081914189afSDeren Wu int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; 1082914189afSDeren Wu const u8 ch_band[] = { 1083914189afSDeren Wu [NL80211_BAND_2GHZ] = 1, 1084914189afSDeren Wu [NL80211_BAND_5GHZ] = 2, 1085914189afSDeren Wu [NL80211_BAND_6GHZ] = 3, 1086914189afSDeren Wu }; 1087914189afSDeren Wu const u8 ch_width[] = { 1088914189afSDeren Wu [NL80211_CHAN_WIDTH_20_NOHT] = 0, 1089914189afSDeren Wu [NL80211_CHAN_WIDTH_20] = 0, 1090914189afSDeren Wu [NL80211_CHAN_WIDTH_40] = 0, 1091914189afSDeren Wu [NL80211_CHAN_WIDTH_80] = 1, 1092914189afSDeren Wu [NL80211_CHAN_WIDTH_160] = 2, 1093914189afSDeren Wu [NL80211_CHAN_WIDTH_80P80] = 3, 1094914189afSDeren Wu [NL80211_CHAN_WIDTH_5] = 4, 1095914189afSDeren Wu [NL80211_CHAN_WIDTH_10] = 5, 1096914189afSDeren Wu [NL80211_CHAN_WIDTH_320] = 6, 1097914189afSDeren Wu }; 1098914189afSDeren Wu struct { 1099914189afSDeren Wu struct { 1100914189afSDeren Wu u8 band_idx; 1101914189afSDeren Wu u8 pad[3]; 1102914189afSDeren Wu } __packed hdr; 1103914189afSDeren Wu struct config_tlv { 1104914189afSDeren Wu __le16 tag; 1105914189afSDeren Wu __le16 len; 1106914189afSDeren Wu u16 aid; 1107914189afSDeren Wu u8 ch_band; 1108914189afSDeren Wu u8 bw; 1109914189afSDeren Wu u8 control_ch; 1110914189afSDeren Wu u8 sco; 1111914189afSDeren Wu u8 center_ch; 1112914189afSDeren Wu u8 center_ch2; 1113914189afSDeren Wu u8 drop_err; 1114914189afSDeren Wu u8 pad[3]; 1115914189afSDeren Wu } __packed tlv; 1116914189afSDeren Wu } __packed req = { 1117914189afSDeren Wu .hdr = { 1118914189afSDeren Wu .band_idx = vif->mt76.band_idx, 1119914189afSDeren Wu }, 1120914189afSDeren Wu .tlv = { 1121914189afSDeren Wu .tag = cpu_to_le16(1), 1122914189afSDeren Wu .len = cpu_to_le16(sizeof(req.tlv)), 1123914189afSDeren Wu .control_ch = chandef->chan->hw_value, 1124914189afSDeren Wu .center_ch = ieee80211_frequency_to_channel(freq1), 1125914189afSDeren Wu .drop_err = 1, 1126914189afSDeren Wu }, 1127914189afSDeren Wu }; 1128914189afSDeren Wu if (chandef->chan->band < ARRAY_SIZE(ch_band)) 1129914189afSDeren Wu req.tlv.ch_band = ch_band[chandef->chan->band]; 1130914189afSDeren Wu if (chandef->width < ARRAY_SIZE(ch_width)) 1131914189afSDeren Wu req.tlv.bw = ch_width[chandef->width]; 1132914189afSDeren Wu 1133914189afSDeren Wu if (freq2) 1134914189afSDeren Wu req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2); 1135914189afSDeren Wu 1136914189afSDeren Wu if (req.tlv.control_ch < req.tlv.center_ch) 1137914189afSDeren Wu req.tlv.sco = 1; /* SCA */ 1138914189afSDeren Wu else if (req.tlv.control_ch > req.tlv.center_ch) 1139914189afSDeren Wu req.tlv.sco = 3; /* SCB */ 1140914189afSDeren Wu 1141914189afSDeren Wu return mt76_mcu_send_msg(vif->phy->mt76->dev, MCU_UNI_CMD(SNIFFER), 1142914189afSDeren Wu &req, sizeof(req), true); 1143914189afSDeren Wu } 1144914189afSDeren Wu 1145116c6960SSean Wang int 1146116c6960SSean Wang mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, 1147116c6960SSean Wang struct ieee80211_hw *hw, 1148116c6960SSean Wang struct ieee80211_vif *vif, 1149116c6960SSean Wang bool enable) 1150116c6960SSean Wang { 1151*15ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; 1152116c6960SSean Wang struct mt76_wcid *wcid = &dev->mt76.global_wcid; 1153116c6960SSean Wang struct ieee80211_mutable_offsets offs; 1154116c6960SSean Wang struct { 1155116c6960SSean Wang struct req_hdr { 1156116c6960SSean Wang u8 bss_idx; 1157116c6960SSean Wang u8 pad[3]; 1158116c6960SSean Wang } __packed hdr; 1159116c6960SSean Wang struct bcn_content_tlv { 1160116c6960SSean Wang __le16 tag; 1161116c6960SSean Wang __le16 len; 1162116c6960SSean Wang __le16 tim_ie_pos; 1163116c6960SSean Wang __le16 csa_ie_pos; 1164116c6960SSean Wang __le16 bcc_ie_pos; 1165116c6960SSean Wang /* 0: disable beacon offload 1166116c6960SSean Wang * 1: enable beacon offload 1167116c6960SSean Wang * 2: update probe respond offload 1168116c6960SSean Wang */ 1169116c6960SSean Wang u8 enable; 1170116c6960SSean Wang /* 0: legacy format (TXD + payload) 1171116c6960SSean Wang * 1: only cap field IE 1172116c6960SSean Wang */ 1173116c6960SSean Wang u8 type; 1174116c6960SSean Wang __le16 pkt_len; 1175116c6960SSean Wang u8 pkt[512]; 1176116c6960SSean Wang } __packed beacon_tlv; 1177116c6960SSean Wang } req = { 1178116c6960SSean Wang .hdr = { 1179116c6960SSean Wang .bss_idx = mvif->mt76.idx, 1180116c6960SSean Wang }, 1181116c6960SSean Wang .beacon_tlv = { 1182116c6960SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), 1183116c6960SSean Wang .len = cpu_to_le16(sizeof(struct bcn_content_tlv)), 1184116c6960SSean Wang .enable = enable, 1185116c6960SSean Wang }, 1186116c6960SSean Wang }; 1187116c6960SSean Wang struct sk_buff *skb; 1188116c6960SSean Wang 1189c149d3a9SDeren Wu /* support enable/update process only 1190c149d3a9SDeren Wu * disable flow would be handled in bss stop handler automatically 1191c149d3a9SDeren Wu */ 1192116c6960SSean Wang if (!enable) 1193c149d3a9SDeren Wu return -EOPNOTSUPP; 1194116c6960SSean Wang 11956e8912a5SShaul Triebitz skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); 1196116c6960SSean Wang if (!skb) 1197116c6960SSean Wang return -EINVAL; 1198116c6960SSean Wang 1199116c6960SSean Wang if (skb->len > 512 - MT_TXD_SIZE) { 1200116c6960SSean Wang dev_err(dev->mt76.dev, "beacon size limit exceed\n"); 1201116c6960SSean Wang dev_kfree_skb(skb); 1202116c6960SSean Wang return -EINVAL; 1203116c6960SSean Wang } 1204116c6960SSean Wang 1205182071cdSLorenzo Bianconi mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt), 12061d5af0acSFelix Fietkau skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON); 1207116c6960SSean Wang memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); 1208116c6960SSean Wang req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); 1209116c6960SSean Wang req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); 1210116c6960SSean Wang 1211116c6960SSean Wang if (offs.cntdwn_counter_offs[0]) { 1212116c6960SSean Wang u16 csa_offs; 1213116c6960SSean Wang 1214116c6960SSean Wang csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4; 1215116c6960SSean Wang req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs); 1216116c6960SSean Wang } 1217116c6960SSean Wang dev_kfree_skb(skb); 1218116c6960SSean Wang 1219116c6960SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), 1220116c6960SSean Wang &req, sizeof(req), true); 1221116c6960SSean Wang } 122223bdc5d8SMing Yen Hsieh 122323bdc5d8SMing Yen Hsieh static 122423bdc5d8SMing Yen Hsieh int __mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2, 122523bdc5d8SMing Yen Hsieh enum environment_cap env_cap, 122623bdc5d8SMing Yen Hsieh struct mt7921_clc *clc, 122723bdc5d8SMing Yen Hsieh u8 idx) 122823bdc5d8SMing Yen Hsieh { 122923bdc5d8SMing Yen Hsieh struct sk_buff *skb; 123023bdc5d8SMing Yen Hsieh struct { 123123bdc5d8SMing Yen Hsieh u8 ver; 123223bdc5d8SMing Yen Hsieh u8 pad0; 123323bdc5d8SMing Yen Hsieh __le16 len; 123423bdc5d8SMing Yen Hsieh u8 idx; 123523bdc5d8SMing Yen Hsieh u8 env; 12367176fe65SQuan Zhou u8 acpi_conf; 12377176fe65SQuan Zhou u8 pad1; 123823bdc5d8SMing Yen Hsieh u8 alpha2[2]; 123923bdc5d8SMing Yen Hsieh u8 type[2]; 124023bdc5d8SMing Yen Hsieh u8 rsvd[64]; 124123bdc5d8SMing Yen Hsieh } __packed req = { 124223bdc5d8SMing Yen Hsieh .idx = idx, 124323bdc5d8SMing Yen Hsieh .env = env_cap, 12447176fe65SQuan Zhou .acpi_conf = mt7921_acpi_get_flags(&dev->phy), 124523bdc5d8SMing Yen Hsieh }; 124623bdc5d8SMing Yen Hsieh int ret, valid_cnt = 0; 124723bdc5d8SMing Yen Hsieh u8 i, *pos; 124823bdc5d8SMing Yen Hsieh 124923bdc5d8SMing Yen Hsieh if (!clc) 125023bdc5d8SMing Yen Hsieh return 0; 125123bdc5d8SMing Yen Hsieh 125223bdc5d8SMing Yen Hsieh pos = clc->data; 125323bdc5d8SMing Yen Hsieh for (i = 0; i < clc->nr_country; i++) { 125423bdc5d8SMing Yen Hsieh struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos; 125523bdc5d8SMing Yen Hsieh u16 len = le16_to_cpu(rule->len); 125623bdc5d8SMing Yen Hsieh 125723bdc5d8SMing Yen Hsieh pos += len + sizeof(*rule); 125823bdc5d8SMing Yen Hsieh if (rule->alpha2[0] != alpha2[0] || 125923bdc5d8SMing Yen Hsieh rule->alpha2[1] != alpha2[1]) 126023bdc5d8SMing Yen Hsieh continue; 126123bdc5d8SMing Yen Hsieh 126223bdc5d8SMing Yen Hsieh memcpy(req.alpha2, rule->alpha2, 2); 126323bdc5d8SMing Yen Hsieh memcpy(req.type, rule->type, 2); 126423bdc5d8SMing Yen Hsieh 126523bdc5d8SMing Yen Hsieh req.len = cpu_to_le16(sizeof(req) + len); 126623bdc5d8SMing Yen Hsieh skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, 126723bdc5d8SMing Yen Hsieh le16_to_cpu(req.len), 126823bdc5d8SMing Yen Hsieh sizeof(req), GFP_KERNEL); 126923bdc5d8SMing Yen Hsieh if (!skb) 127023bdc5d8SMing Yen Hsieh return -ENOMEM; 127123bdc5d8SMing Yen Hsieh skb_put_data(skb, rule->data, len); 127223bdc5d8SMing Yen Hsieh 127323bdc5d8SMing Yen Hsieh ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, 127423bdc5d8SMing Yen Hsieh MCU_CE_CMD(SET_CLC), false); 127523bdc5d8SMing Yen Hsieh if (ret < 0) 127623bdc5d8SMing Yen Hsieh return ret; 127723bdc5d8SMing Yen Hsieh valid_cnt++; 127823bdc5d8SMing Yen Hsieh } 127923bdc5d8SMing Yen Hsieh 128023bdc5d8SMing Yen Hsieh if (!valid_cnt) 128123bdc5d8SMing Yen Hsieh return -ENOENT; 128223bdc5d8SMing Yen Hsieh 128323bdc5d8SMing Yen Hsieh return 0; 128423bdc5d8SMing Yen Hsieh } 128523bdc5d8SMing Yen Hsieh 128623bdc5d8SMing Yen Hsieh int mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2, 128723bdc5d8SMing Yen Hsieh enum environment_cap env_cap) 128823bdc5d8SMing Yen Hsieh { 128923bdc5d8SMing Yen Hsieh struct mt7921_phy *phy = (struct mt7921_phy *)&dev->phy; 129023bdc5d8SMing Yen Hsieh int i, ret; 129123bdc5d8SMing Yen Hsieh 129223bdc5d8SMing Yen Hsieh /* submit all clc config */ 129323bdc5d8SMing Yen Hsieh for (i = 0; i < ARRAY_SIZE(phy->clc); i++) { 129423bdc5d8SMing Yen Hsieh ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap, 129523bdc5d8SMing Yen Hsieh phy->clc[i], i); 129623bdc5d8SMing Yen Hsieh 129723bdc5d8SMing Yen Hsieh /* If no country found, set "00" as default */ 129823bdc5d8SMing Yen Hsieh if (ret == -ENOENT) 129923bdc5d8SMing Yen Hsieh ret = __mt7921_mcu_set_clc(dev, "00", 130023bdc5d8SMing Yen Hsieh ENVIRON_INDOOR, 130123bdc5d8SMing Yen Hsieh phy->clc[i], i); 130223bdc5d8SMing Yen Hsieh if (ret < 0) 130323bdc5d8SMing Yen Hsieh return ret; 130423bdc5d8SMing Yen Hsieh } 130523bdc5d8SMing Yen Hsieh return 0; 130623bdc5d8SMing Yen Hsieh } 1307c222f77fSNeil Chen 13086ae39b7cSBen Greear int mt7921_mcu_get_temperature(struct mt7921_phy *phy) 13096ae39b7cSBen Greear { 13106ae39b7cSBen Greear struct mt7921_dev *dev = phy->dev; 13116ae39b7cSBen Greear struct { 13126ae39b7cSBen Greear u8 ctrl_id; 13136ae39b7cSBen Greear u8 action; 13146ae39b7cSBen Greear u8 band_idx; 13156ae39b7cSBen Greear u8 rsv[5]; 13166ae39b7cSBen Greear } req = { 13176ae39b7cSBen Greear .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, 13186ae39b7cSBen Greear .band_idx = phy->mt76->band_idx, 13196ae39b7cSBen Greear }; 13206ae39b7cSBen Greear 13216ae39b7cSBen Greear return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, 13226ae39b7cSBen Greear sizeof(req), true); 13236ae39b7cSBen Greear } 13246ae39b7cSBen Greear 1325c222f77fSNeil Chen int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif, 1326c222f77fSNeil Chen u8 bit_op, u32 bit_map) 1327c222f77fSNeil Chen { 1328c222f77fSNeil Chen struct { 1329c222f77fSNeil Chen u8 rsv[4]; 1330c222f77fSNeil Chen u8 mode; 1331c222f77fSNeil Chen u8 rsv2[3]; 1332c222f77fSNeil Chen __le32 fif; 1333c222f77fSNeil Chen __le32 bit_map; /* bit_* for bitmap update */ 1334c222f77fSNeil Chen u8 bit_op; 1335c222f77fSNeil Chen u8 pad[51]; 1336c222f77fSNeil Chen } __packed data = { 1337c222f77fSNeil Chen .mode = fif ? 1 : 2, 1338c222f77fSNeil Chen .fif = cpu_to_le32(fif), 1339c222f77fSNeil Chen .bit_map = cpu_to_le32(bit_map), 1340c222f77fSNeil Chen .bit_op = bit_op, 1341c222f77fSNeil Chen }; 1342c222f77fSNeil Chen 1343c222f77fSNeil Chen return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_RX_FILTER), 1344c222f77fSNeil Chen &data, sizeof(data), false); 1345c222f77fSNeil Chen } 1346