Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7925/mcu.c
107416 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/* Copyright (C) 2023 MediaTek Inc. */23#if defined(__FreeBSD__)4#define LINUXKPI_PARAM_PREFIX mt7925_5#endif67#include <linux/fs.h>8#include <linux/firmware.h>9#include "mt7925.h"10#include "regd.h"11#include "mcu.h"12#include "mac.h"1314#define MT_STA_BFER BIT(0)15#define MT_STA_BFEE BIT(1)1617int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd,18struct sk_buff *skb, int seq)19{20int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);21struct mt7925_mcu_rxd *rxd;22int ret = 0;2324if (!skb) {25dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq);26mt792x_reset(mdev);2728return -ETIMEDOUT;29}3031rxd = (struct mt7925_mcu_rxd *)skb->data;32if (seq != rxd->seq)33return -EAGAIN;3435if (cmd == MCU_CMD(PATCH_SEM_CONTROL) ||36cmd == MCU_CMD(PATCH_FINISH_REQ)) {37skb_pull(skb, sizeof(*rxd) - 4);38ret = *skb->data;39} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||40cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||41cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||42cmd == MCU_UNI_CMD(OFFLOAD) ||43cmd == MCU_UNI_CMD(SUSPEND)) {44struct mt7925_mcu_uni_event *event;4546skb_pull(skb, sizeof(*rxd));47event = (struct mt7925_mcu_uni_event *)skb->data;48ret = le32_to_cpu(event->status);49/* skip invalid event */50if (mcu_cmd != event->cid)51ret = -EAGAIN;52} else {53skb_pull(skb, sizeof(*rxd));54}5556return ret;57}58EXPORT_SYMBOL_GPL(mt7925_mcu_parse_response);5960int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set)61{62#define MT_RF_REG_HDR GENMASK(31, 24)63#define MT_RF_REG_ANT GENMASK(23, 16)64#define RF_REG_PREFIX 0x9965struct {66u8 __rsv[4];67union {68struct uni_cmd_access_reg_basic {69__le16 tag;70__le16 len;71__le32 idx;72__le32 data;73} __packed reg;74struct uni_cmd_access_rf_reg_basic {75__le16 tag;76__le16 len;77__le16 ant;78u8 __rsv[2];79__le32 idx;80__le32 data;81} __packed rf_reg;82};83} __packed * res, req;84struct sk_buff *skb;85int ret;8687if (u32_get_bits(regidx, MT_RF_REG_HDR) == RF_REG_PREFIX) {88req.rf_reg.tag = cpu_to_le16(UNI_CMD_ACCESS_RF_REG_BASIC);89req.rf_reg.len = cpu_to_le16(sizeof(req.rf_reg));90req.rf_reg.ant = cpu_to_le16(u32_get_bits(regidx, MT_RF_REG_ANT));91req.rf_reg.idx = cpu_to_le32(regidx);92req.rf_reg.data = set ? cpu_to_le32(*val) : 0;93} else {94req.reg.tag = cpu_to_le16(UNI_CMD_ACCESS_REG_BASIC);95req.reg.len = cpu_to_le16(sizeof(req.reg));96req.reg.idx = cpu_to_le32(regidx);97req.reg.data = set ? cpu_to_le32(*val) : 0;98}99100if (set)101return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REG_ACCESS),102&req, sizeof(req), true);103104ret = mt76_mcu_send_and_get_msg(&dev->mt76,105MCU_WM_UNI_CMD_QUERY(REG_ACCESS),106&req, sizeof(req), true, &skb);107if (ret)108return ret;109110res = (void *)skb->data;111if (u32_get_bits(regidx, MT_RF_REG_HDR) == RF_REG_PREFIX)112*val = le32_to_cpu(res->rf_reg.data);113else114*val = le32_to_cpu(res->reg.data);115116dev_kfree_skb(skb);117118return 0;119}120EXPORT_SYMBOL_GPL(mt7925_mcu_regval);121122int mt7925_mcu_update_arp_filter(struct mt76_dev *dev,123struct ieee80211_bss_conf *link_conf)124{125struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);126struct ieee80211_vif *mvif = link_conf->vif;127struct sk_buff *skb;128int i, len = min_t(int, mvif->cfg.arp_addr_cnt,129IEEE80211_BSS_ARP_ADDR_LIST_LEN);130struct {131struct {132u8 bss_idx;133u8 pad[3];134} __packed hdr;135struct mt7925_arpns_tlv arp;136} req = {137.hdr = {138.bss_idx = mconf->mt76.idx,139},140.arp = {141.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),142.len = cpu_to_le16(sizeof(req) - 4 + len * 2 * sizeof(__be32)),143.ips_num = len,144.enable = true,145},146};147148skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(req) + len * 2 * sizeof(__be32));149if (!skb)150return -ENOMEM;151152skb_put_data(skb, &req, sizeof(req));153for (i = 0; i < len; i++) {154skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32));155skb_put_zero(skb, sizeof(__be32));156}157158return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true);159}160161#ifdef CONFIG_PM162static int163mt7925_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,164bool suspend, struct cfg80211_wowlan *wowlan)165{166struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;167struct ieee80211_scan_ies ies = {};168struct mt76_dev *dev = phy->dev;169struct {170struct {171u8 bss_idx;172u8 pad[3];173} __packed hdr;174struct mt76_connac_wow_ctrl_tlv wow_ctrl_tlv;175struct mt76_connac_wow_gpio_param_tlv gpio_tlv;176} req = {177.hdr = {178.bss_idx = mvif->idx,179},180.wow_ctrl_tlv = {181.tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL),182.len = cpu_to_le16(sizeof(struct mt76_connac_wow_ctrl_tlv)),183.cmd = suspend ? 1 : 2,184},185.gpio_tlv = {186.tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM),187.len = cpu_to_le16(sizeof(struct mt76_connac_wow_gpio_param_tlv)),188.gpio_pin = 0xff, /* follow fw about GPIO pin */189},190};191192if (wowlan->magic_pkt)193req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC;194if (wowlan->disconnect)195req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT |196UNI_WOW_DETECT_TYPE_BCN_LOST);197if (wowlan->nd_config) {198mt7925_mcu_sched_scan_req(phy, vif, wowlan->nd_config, &ies);199req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT;200mt7925_mcu_sched_scan_enable(phy, vif, suspend);201}202if (wowlan->n_patterns)203req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP;204205if (mt76_is_mmio(dev))206req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE;207else if (mt76_is_usb(dev))208req.wow_ctrl_tlv.wakeup_hif = WOW_USB;209else if (mt76_is_sdio(dev))210req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO;211212return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req,213sizeof(req), true);214}215216static int217mt7925_mcu_set_wow_pattern(struct mt76_dev *dev,218struct ieee80211_vif *vif,219u8 index, bool enable,220struct cfg80211_pkt_pattern *pattern)221{222struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;223struct mt7925_wow_pattern_tlv *tlv;224struct sk_buff *skb;225struct {226u8 bss_idx;227u8 pad[3];228} __packed hdr = {229.bss_idx = mvif->idx,230};231232skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*tlv));233if (!skb)234return -ENOMEM;235236skb_put_data(skb, &hdr, sizeof(hdr));237tlv = (struct mt7925_wow_pattern_tlv *)skb_put(skb, sizeof(*tlv));238tlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN);239tlv->len = cpu_to_le16(sizeof(*tlv));240tlv->bss_idx = 0xF;241tlv->data_len = pattern->pattern_len;242tlv->enable = enable;243tlv->index = index;244tlv->offset = 0;245246memcpy(tlv->pattern, pattern->pattern, pattern->pattern_len);247memcpy(tlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8));248249return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SUSPEND), true);250}251252void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac,253struct ieee80211_vif *vif)254{255struct mt76_phy *phy = priv;256bool suspend = !test_bit(MT76_STATE_RUNNING, &phy->state);257struct ieee80211_hw *hw = phy->hw;258struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config;259int i;260261mt76_connac_mcu_set_gtk_rekey(phy->dev, vif, suspend);262263mt76_connac_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true);264265for (i = 0; i < wowlan->n_patterns; i++)266mt7925_mcu_set_wow_pattern(phy->dev, vif, i, suspend,267&wowlan->patterns[i]);268mt7925_connac_mcu_set_wow_ctrl(phy, vif, suspend, wowlan);269}270271#endif /* CONFIG_PM */272273static void274mt7925_mcu_connection_loss_iter(void *priv, u8 *mac,275struct ieee80211_vif *vif)276{277struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;278struct mt7925_uni_beacon_loss_event *event = priv;279280if (mvif->idx != event->hdr.bss_idx)281return;282283if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) ||284vif->type != NL80211_IFTYPE_STATION)285return;286287ieee80211_connection_loss(vif);288}289290static void291mt7925_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb)292{293struct mt7925_uni_beacon_loss_event *event;294struct mt76_phy *mphy = &dev->mt76.phy;295296skb_pull(skb, sizeof(struct mt7925_mcu_rxd));297event = (struct mt7925_uni_beacon_loss_event *)skb->data;298299ieee80211_iterate_active_interfaces_atomic(mphy->hw,300IEEE80211_IFACE_ITER_RESUME_ALL,301mt7925_mcu_connection_loss_iter, event);302}303304static void305mt7925_mcu_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)306{307struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;308struct mt7925_roc_grant_tlv *grant = priv;309310if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION)311return;312313if (mvif->idx != grant->bss_idx)314return;315316mvif->band_idx = grant->dbdcband;317}318319static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev,320struct tlv *tlv)321{322struct ieee80211_hw *hw = dev->mt76.hw;323struct mt7925_roc_grant_tlv *grant;324int duration;325326grant = (struct mt7925_roc_grant_tlv *)tlv;327328/* should never happen */329WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT));330331if (grant->reqtype == MT7925_ROC_REQ_ROC)332ieee80211_ready_on_channel(hw);333else if (grant->reqtype == MT7925_ROC_REQ_JOIN)334ieee80211_iterate_active_interfaces_atomic(hw,335IEEE80211_IFACE_ITER_RESUME_ALL,336mt7925_mcu_roc_iter, grant);337dev->phy.roc_grant = true;338wake_up(&dev->phy.roc_wait);339duration = le32_to_cpu(grant->max_interval);340mod_timer(&dev->phy.roc_timer,341jiffies + msecs_to_jiffies(duration));342}343344static void345mt7925_mcu_handle_hif_ctrl_basic(struct mt792x_dev *dev, struct tlv *tlv)346{347struct mt7925_mcu_hif_ctrl_basic_tlv *basic;348349basic = (struct mt7925_mcu_hif_ctrl_basic_tlv *)tlv;350351if (basic->hifsuspend) {352dev->hif_idle = true;353if (!(basic->hif_tx_traffic_status == HIF_TRAFFIC_IDLE &&354basic->hif_rx_traffic_status == HIF_TRAFFIC_IDLE))355dev_info(dev->mt76.dev, "Hif traffic not idle.\n");356} else {357dev->hif_resumed = true;358}359wake_up(&dev->wait);360}361362static void363mt7925_mcu_uni_hif_ctrl_event(struct mt792x_dev *dev, struct sk_buff *skb)364{365struct tlv *tlv;366u32 tlv_len;367368skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);369tlv = (struct tlv *)skb->data;370tlv_len = skb->len;371372while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) {373switch (le16_to_cpu(tlv->tag)) {374case UNI_EVENT_HIF_CTRL_BASIC:375mt7925_mcu_handle_hif_ctrl_basic(dev, tlv);376break;377default:378break;379}380tlv_len -= le16_to_cpu(tlv->len);381tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len));382}383}384385static void386mt7925_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb)387{388struct tlv *tlv;389int i = 0;390391skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);392393while (i < skb->len) {394tlv = (struct tlv *)(skb->data + i);395396switch (le16_to_cpu(tlv->tag)) {397case UNI_EVENT_ROC_GRANT:398mt7925_mcu_roc_handle_grant(dev, tlv);399break;400case UNI_EVENT_ROC_GRANT_SUB_LINK:401break;402}403404i += le16_to_cpu(tlv->len);405}406}407408static void409mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)410{411struct mt76_phy *mphy = &dev->mt76.phy;412struct mt792x_phy *phy = mphy->priv;413414spin_lock_bh(&dev->mt76.lock);415__skb_queue_tail(&phy->scan_event_list, skb);416spin_unlock_bh(&dev->mt76.lock);417418ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,419MT792x_HW_SCAN_TIMEOUT);420}421422static void423mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb)424{425#define UNI_EVENT_TX_DONE_MSG 0426#define UNI_EVENT_TX_DONE_RAW 1427struct mt7925_mcu_txs_event {428u8 ver;429u8 rsv[3];430u8 data[];431} __packed * txs;432struct tlv *tlv;433u32 tlv_len;434435skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);436tlv = (struct tlv *)skb->data;437tlv_len = skb->len;438439while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) {440switch (le16_to_cpu(tlv->tag)) {441case UNI_EVENT_TX_DONE_RAW:442txs = (struct mt7925_mcu_txs_event *)tlv->data;443mt7925_mac_add_txs(dev, txs->data);444break;445default:446break;447}448tlv_len -= le16_to_cpu(tlv->len);449tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len));450}451}452453static void454mt7925_mcu_rssi_monitor_iter(void *priv, u8 *mac,455struct ieee80211_vif *vif)456{457struct mt7925_uni_rssi_monitor_event *event = priv;458enum nl80211_cqm_rssi_threshold_event nl_event;459s32 rssi = le32_to_cpu(event->rssi);460461if (vif->type != NL80211_IFTYPE_STATION)462return;463464if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))465return;466467if (rssi > vif->bss_conf.cqm_rssi_thold)468nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;469else470nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;471472ieee80211_cqm_rssi_notify(vif, nl_event, rssi, GFP_KERNEL);473}474475static void476mt7925_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb)477{478struct tlv *tlv;479u32 tlv_len;480struct mt7925_uni_rssi_monitor_event *event;481482skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);483tlv = (struct tlv *)skb->data;484tlv_len = skb->len;485486while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) {487switch (le16_to_cpu(tlv->tag)) {488case UNI_EVENT_RSSI_MONITOR_INFO:489event = (struct mt7925_uni_rssi_monitor_event *)skb->data;490ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw,491IEEE80211_IFACE_ITER_RESUME_ALL,492mt7925_mcu_rssi_monitor_iter,493event);494break;495default:496break;497}498tlv_len -= le16_to_cpu(tlv->len);499tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len));500}501}502503static void504mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)505{506struct mt7925_uni_debug_msg {507__le16 tag;508__le16 len;509u8 fmt;510u8 rsv[3];511u8 id;512u8 type:3;513u8 nr_args:5;514union {515struct idxlog {516__le16 rsv;517__le32 ts;518__le32 idx;519u8 data[];520} __packed idx;521struct txtlog {522u8 len;523u8 rsv;524__le32 ts;525u8 data[];526} __packed txt;527};528} __packed * hdr;529530skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);531hdr = (struct mt7925_uni_debug_msg *)skb->data;532533if (hdr->id == 0x28) {534skb_pull(skb, offsetof(struct mt7925_uni_debug_msg, id));535wiphy_info(mt76_hw(dev)->wiphy, "%.*s", skb->len, skb->data);536return;537} else if (hdr->id != 0xa8) {538return;539}540541if (hdr->type == 0) { /* idx log */542int i, ret, len = PAGE_SIZE - 1, nr_val;543struct page *page = dev_alloc_pages(get_order(len));544__le32 *val;545char *buf, *cur;546547if (!page)548return;549550buf = page_address(page);551cur = buf;552553nr_val = (le16_to_cpu(hdr->len) - sizeof(*hdr)) / 4;554val = (__le32 *)hdr->idx.data;555for (i = 0; i < nr_val && len > 0; i++) {556ret = snprintf(cur, len, "0x%x,", le32_to_cpu(val[i]));557if (ret <= 0)558break;559560cur += ret;561len -= ret;562}563if (cur > buf)564wiphy_info(mt76_hw(dev)->wiphy, "idx: 0x%X,%d,%s",565le32_to_cpu(hdr->idx.idx), nr_val, buf);566put_page(page);567} else if (hdr->type == 2) { /* str log */568wiphy_info(mt76_hw(dev)->wiphy, "%.*s", hdr->txt.len, hdr->txt.data);569}570}571572static void573mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,574struct sk_buff *skb)575{576struct mt7925_mcu_rxd *rxd;577578rxd = (struct mt7925_mcu_rxd *)skb->data;579580switch (rxd->eid) {581case MCU_UNI_EVENT_HIF_CTRL:582mt7925_mcu_uni_hif_ctrl_event(dev, skb);583break;584case MCU_UNI_EVENT_FW_LOG_2_HOST:585mt7925_mcu_uni_debug_msg_event(dev, skb);586break;587case MCU_UNI_EVENT_ROC:588mt7925_mcu_uni_roc_event(dev, skb);589break;590case MCU_UNI_EVENT_SCAN_DONE:591mt7925_mcu_scan_event(dev, skb);592return;593case MCU_UNI_EVENT_TX_DONE:594mt7925_mcu_tx_done_event(dev, skb);595break;596case MCU_UNI_EVENT_BSS_BEACON_LOSS:597mt7925_mcu_connection_loss_event(dev, skb);598break;599case MCU_UNI_EVENT_RSSI_MONITOR:600mt7925_mcu_rssi_monitor_event(dev, skb);601break;602case MCU_UNI_EVENT_COREDUMP:603dev->fw_assert = true;604mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump);605return;606default:607break;608}609dev_kfree_skb(skb);610}611612void mt7925_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb)613{614struct mt7925_mcu_rxd *rxd = (struct mt7925_mcu_rxd *)skb->data;615616if (skb_linearize(skb))617return;618619if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) {620mt7925_mcu_uni_rx_unsolicited_event(dev, skb);621return;622}623624mt76_mcu_rx_event(&dev->mt76, skb);625}626627static int628mt7925_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,629struct ieee80211_ampdu_params *params,630bool enable, bool tx)631{632struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv;633struct sta_rec_ba_uni *ba;634struct sk_buff *skb;635struct tlv *tlv;636int len;637638len = sizeof(struct sta_req_hdr) + sizeof(*ba);639skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,640len);641if (IS_ERR(skb))642return PTR_ERR(skb);643644tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));645646ba = (struct sta_rec_ba_uni *)tlv;647ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT;648ba->winsize = cpu_to_le16(params->buf_size);649ba->ssn = cpu_to_le16(params->ssn);650ba->ba_en = enable << params->tid;651ba->amsdu = params->amsdu;652ba->tid = params->tid;653654return mt76_mcu_skb_send_msg(dev, skb,655MCU_UNI_CMD(STA_REC_UPDATE), true);656}657658/** starec & wtbl **/659int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev,660struct ieee80211_ampdu_params *params,661bool enable)662{663struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;664struct mt792x_vif *mvif = msta->vif;665666if (enable && !params->amsdu)667msta->deflink.wcid.amsdu = false;668669return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params,670enable, true);671}672673int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev,674struct ieee80211_ampdu_params *params,675bool enable)676{677struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;678struct mt792x_vif *mvif = msta->vif;679680return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params,681enable, false);682}683684static int mt7925_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)685{686struct {687u8 rsv[4];688689__le16 tag;690__le16 len;691692__le32 addr;693__le32 valid;694u8 data[MT7925_EEPROM_BLOCK_SIZE];695} __packed req = {696.tag = cpu_to_le16(1),697.len = cpu_to_le16(sizeof(req) - 4),698.addr = cpu_to_le32(round_down(offset,699MT7925_EEPROM_BLOCK_SIZE)),700};701struct evt {702u8 rsv[4];703704__le16 tag;705__le16 len;706707__le32 ver;708__le32 addr;709__le32 valid;710__le32 size;711__le32 magic_num;712__le32 type;713__le32 rsv1[4];714u8 data[32];715} __packed *res;716struct sk_buff *skb;717int ret;718719ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL),720&req, sizeof(req), true, &skb);721if (ret)722return ret;723724res = (struct evt *)skb->data;725*val = res->data[offset % MT7925_EEPROM_BLOCK_SIZE];726727dev_kfree_skb(skb);728729return 0;730}731732static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name)733{734const struct mt76_connac2_fw_trailer *hdr;735const struct mt76_connac2_fw_region *region;736const struct mt7925_clc *clc;737struct mt76_dev *mdev = &dev->mt76;738struct mt792x_phy *phy = &dev->phy;739const struct firmware *fw;740#if defined(__linux__)741u8 *clc_base = NULL, hw_encap = 0;742#elif defined(__FreeBSD__)743const u8 *clc_base = NULL;744u8 hw_encap = 0;745#endif746int ret, i, len, offset = 0;747748dev->phy.clc_chan_conf = 0xff;749dev->regd_user = false;750if (!mt7925_regd_clc_supported(dev))751return 0;752753if (mt76_is_mmio(&dev->mt76)) {754ret = mt7925_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap);755if (ret)756return ret;757hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP);758}759760ret = request_firmware(&fw, fw_name, mdev->dev);761if (ret)762return ret;763764if (!fw || !fw->data || fw->size < sizeof(*hdr)) {765dev_err(mdev->dev, "Invalid firmware\n");766ret = -EINVAL;767goto out;768}769770hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));771for (i = 0; i < hdr->n_region; i++) {772region = (const void *)((const u8 *)hdr -773(hdr->n_region - i) * sizeof(*region));774len = le32_to_cpu(region->len);775776/* check if we have valid buffer size */777if (offset + len > fw->size) {778dev_err(mdev->dev, "Invalid firmware region\n");779ret = -EINVAL;780goto out;781}782783if ((region->feature_set & FW_FEATURE_NON_DL) &&784region->type == FW_TYPE_CLC) {785#if defined(__linux__)786clc_base = (u8 *)(fw->data + offset);787#elif defined(__FreeBSD__)788clc_base = (const u8 *)(fw->data + offset);789#endif790break;791}792offset += len;793}794795if (!clc_base)796goto out;797798for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) {799clc = (const struct mt7925_clc *)(clc_base + offset);800801if (clc->idx >= ARRAY_SIZE(phy->clc))802break;803804/* do not init buf again if chip reset triggered */805if (phy->clc[clc->idx])806continue;807808/* header content sanity */809if ((clc->idx == MT792x_CLC_BE_CTRL &&810u8_get_bits(clc->t2.type, MT_EE_HW_TYPE_ENCAP) != hw_encap) ||811u8_get_bits(clc->t0.type, MT_EE_HW_TYPE_ENCAP) != hw_encap)812continue;813814phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc,815le32_to_cpu(clc->len),816GFP_KERNEL);817818if (!phy->clc[clc->idx]) {819ret = -ENOMEM;820goto out;821}822}823824ret = mt7925_regd_init(phy);825out:826release_firmware(fw);827828return ret;829}830831int mt7925_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl)832{833struct {834u8 _rsv[4];835836__le16 tag;837__le16 len;838u8 ctrl;839u8 interval;840u8 _rsv2[2];841} __packed req = {842.tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_LOG_CTRL),843.len = cpu_to_le16(sizeof(req) - 4),844.ctrl = ctrl,845};846int ret;847848ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(WSYS_CONFIG),849&req, sizeof(req), true, NULL);850return ret;851}852853int mt7925_mcu_get_temperature(struct mt792x_phy *phy)854{855struct {856u8 _rsv[4];857858__le16 tag;859__le16 len;860u8 _rsv2[4];861} __packed req = {862.tag = cpu_to_le16(0x0),863.len = cpu_to_le16(sizeof(req) - 4),864};865struct mt7925_thermal_evt {866u8 rsv[4];867__le32 temperature;868} __packed * evt;869struct mt792x_dev *dev = phy->dev;870int temperature, ret;871struct sk_buff *skb;872873ret = mt76_mcu_send_and_get_msg(&dev->mt76,874MCU_WM_UNI_CMD_QUERY(THERMAL),875&req, sizeof(req), true, &skb);876if (ret)877return ret;878879skb_pull(skb, 4 + sizeof(struct tlv));880evt = (struct mt7925_thermal_evt *)skb->data;881882temperature = le32_to_cpu(evt->temperature);883884dev_kfree_skb(skb);885886return temperature;887}888889static void890mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data)891{892struct mt76_phy *mphy = &dev->mt76.phy;893struct mt76_dev *mdev = mphy->dev;894struct mt7925_mcu_phy_cap {895u8 ht;896u8 vht;897u8 _5g;898u8 max_bw;899u8 nss;900u8 dbdc;901u8 tx_ldpc;902u8 rx_ldpc;903u8 tx_stbc;904u8 rx_stbc;905u8 hw_path;906u8 he;907u8 eht;908} __packed * cap;909enum {910WF0_24G,911WF0_5G912};913914cap = (struct mt7925_mcu_phy_cap *)data;915916mdev->phy.antenna_mask = BIT(cap->nss) - 1;917mdev->phy.chainmask = mdev->phy.antenna_mask;918mdev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G);919mdev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G);920}921922static void923mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data)924{925struct mt7925_mcu_eml_cap {926u8 rsv[4];927__le16 eml_cap;928u8 rsv2[6];929} __packed * cap;930931cap = (struct mt7925_mcu_eml_cap *)data;932933dev->phy.eml_cap = le16_to_cpu(cap->eml_cap);934}935936static int937mt7925_mcu_get_nic_capability(struct mt792x_dev *dev)938{939struct mt76_phy *mphy = &dev->mt76.phy;940struct {941u8 _rsv[4];942943__le16 tag;944__le16 len;945} __packed req = {946.tag = cpu_to_le16(UNI_CHIP_CONFIG_NIC_CAPA),947.len = cpu_to_le16(sizeof(req) - 4),948};949struct mt76_connac_cap_hdr {950__le16 n_element;951u8 rsv[2];952} __packed * hdr;953struct sk_buff *skb;954int ret, i;955956ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(CHIP_CONFIG),957&req, sizeof(req), true, &skb);958if (ret)959return ret;960961hdr = (struct mt76_connac_cap_hdr *)skb->data;962if (skb->len < sizeof(*hdr)) {963ret = -EINVAL;964goto out;965}966967skb_pull(skb, sizeof(*hdr));968969for (i = 0; i < le16_to_cpu(hdr->n_element); i++) {970struct tlv *tlv = (struct tlv *)skb->data;971int len;972973if (skb->len < sizeof(*tlv))974break;975976len = le16_to_cpu(tlv->len);977if (skb->len < len)978break;979980switch (le16_to_cpu(tlv->tag)) {981case MT_NIC_CAP_6G:982mphy->cap.has_6ghz = !!tlv->data[0];983break;984case MT_NIC_CAP_MAC_ADDR:985memcpy(mphy->macaddr, (void *)tlv->data, ETH_ALEN);986break;987case MT_NIC_CAP_PHY:988mt7925_mcu_parse_phy_cap(dev, tlv->data);989break;990case MT_NIC_CAP_CHIP_CAP:991dev->phy.chip_cap = le64_to_cpu(*(__le64 *)tlv->data);992break;993case MT_NIC_CAP_EML_CAP:994mt7925_mcu_parse_eml_cap(dev, tlv->data);995break;996default:997break;998}999skb_pull(skb, len);1000}1001out:1002dev_kfree_skb(skb);1003return ret;1004}10051006int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd)1007{1008u16 len = strlen(cmd) + 1;1009struct {1010u8 _rsv[4];1011__le16 tag;1012__le16 len;1013struct mt76_connac_config config;1014} __packed req = {1015.tag = cpu_to_le16(UNI_CHIP_CONFIG_CHIP_CFG),1016.len = cpu_to_le16(sizeof(req) - 4),1017.config = {1018.resp_type = 0,1019.type = 0,1020.data_size = cpu_to_le16(len),1021},1022};10231024memcpy(req.config.data, cmd, len);10251026return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(CHIP_CONFIG),1027&req, sizeof(req), false);1028}10291030int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable)1031{1032char cmd[16];10331034snprintf(cmd, sizeof(cmd), "KeepFullPwr %d", !enable);10351036return mt7925_mcu_chip_config(dev, cmd);1037}1038EXPORT_SYMBOL_GPL(mt7925_mcu_set_deep_sleep);10391040int mt7925_mcu_set_thermal_protect(struct mt792x_dev *dev)1041{1042char cmd[64];1043int ret = 0;10441045snprintf(cmd, sizeof(cmd), "ThermalProtGband %d %d %d %d %d %d %d %d %d %d",10460, 100, 90, 80, 30, 1, 1, 115, 105, 5);1047ret = mt7925_mcu_chip_config(dev, cmd);10481049snprintf(cmd, sizeof(cmd), "ThermalProtAband %d %d %d %d %d %d %d %d %d %d",10501, 100, 90, 80, 30, 1, 1, 115, 105, 5);1051ret |= mt7925_mcu_chip_config(dev, cmd);10521053return ret;1054}1055EXPORT_SYMBOL_GPL(mt7925_mcu_set_thermal_protect);10561057int mt7925_run_firmware(struct mt792x_dev *dev)1058{1059int err;10601061err = mt792x_load_firmware(dev);1062if (err)1063return err;10641065err = mt7925_mcu_get_nic_capability(dev);1066if (err)1067return err;10681069err = mt7925_load_clc(dev, mt792x_ram_name(dev));1070if (err)1071return err;1072set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);10731074return mt7925_mcu_fw_log_2_host(dev, 1);1075}1076EXPORT_SYMBOL_GPL(mt7925_run_firmware);10771078static void1079mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,1080struct ieee80211_vif *vif,1081struct ieee80211_link_sta *link_sta)1082{1083struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1084struct sta_rec_hdr_trans *hdr_trans;1085struct mt76_wcid *wcid;1086struct tlv *tlv;10871088tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans));1089hdr_trans = (struct sta_rec_hdr_trans *)tlv;1090hdr_trans->dis_rx_hdr_tran = true;10911092if (vif->type == NL80211_IFTYPE_STATION)1093hdr_trans->to_ds = true;1094else1095hdr_trans->from_ds = true;10961097if (link_sta) {1098struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv;1099struct mt792x_link_sta *mlink;11001101mlink = mt792x_sta_to_link(msta, link_sta->link_id);1102wcid = &mlink->wcid;1103} else {1104wcid = &mvif->sta.deflink.wcid;1105}11061107if (!wcid)1108return;11091110hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);1111if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {1112hdr_trans->to_ds = true;1113hdr_trans->from_ds = true;1114}1115}11161117int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,1118struct ieee80211_vif *vif,1119struct ieee80211_sta *sta,1120int link_id)1121{1122struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1123struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL;1124struct mt792x_link_sta *mlink;1125struct mt792x_bss_conf *mconf;1126struct mt792x_sta *msta;1127struct sk_buff *skb;11281129msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta;11301131mlink = mt792x_sta_to_link(msta, link_id);1132link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);1133mconf = mt792x_vif_to_link(mvif, link_id);11341135skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,1136&mlink->wcid,1137MT7925_STA_UPDATE_MAX_SIZE);1138if (IS_ERR(skb))1139return PTR_ERR(skb);11401141/* starec hdr trans */1142mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta);1143return mt76_mcu_skb_send_msg(&dev->mt76, skb,1144MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);1145}11461147int mt7925_mcu_set_tx(struct mt792x_dev *dev,1148struct ieee80211_bss_conf *bss_conf)1149{1150#define MCU_EDCA_AC_PARAM 01151#define WMM_AIFS_SET BIT(0)1152#define WMM_CW_MIN_SET BIT(1)1153#define WMM_CW_MAX_SET BIT(2)1154#define WMM_TXOP_SET BIT(3)1155#define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \1156WMM_CW_MAX_SET | WMM_TXOP_SET)1157struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(bss_conf);1158struct {1159u8 bss_idx;1160u8 __rsv[3];1161} __packed hdr = {1162.bss_idx = mconf->mt76.idx,1163};1164struct sk_buff *skb;1165int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca);1166int ac;11671168skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);1169if (!skb)1170return -ENOMEM;11711172skb_put_data(skb, &hdr, sizeof(hdr));11731174for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {1175struct ieee80211_tx_queue_params *q = &mconf->queue_params[ac];1176struct edca *e;1177struct tlv *tlv;11781179tlv = mt76_connac_mcu_add_tlv(skb, MCU_EDCA_AC_PARAM, sizeof(*e));11801181e = (struct edca *)tlv;1182e->set = WMM_PARAM_SET;1183e->queue = ac;1184e->aifs = q->aifs;1185e->txop = cpu_to_le16(q->txop);11861187if (q->cw_min)1188e->cw_min = fls(q->cw_min);1189else1190e->cw_min = 5;11911192if (q->cw_max)1193e->cw_max = fls(q->cw_max);1194else1195e->cw_max = 10;1196}11971198return mt76_mcu_skb_send_msg(&dev->mt76, skb,1199MCU_UNI_CMD(EDCA_UPDATE), true);1200}12011202static int1203mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid,1204struct mt76_connac_sta_key_conf *sta_key_conf,1205struct sk_buff *skb,1206struct ieee80211_key_conf *key,1207enum set_key_cmd cmd,1208struct mt792x_sta *msta)1209{1210struct mt792x_vif *mvif = msta->vif;1211struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id);1212struct sta_rec_sec_uni *sec;1213struct ieee80211_sta *sta;1214struct ieee80211_vif *vif;1215struct tlv *tlv;12161217sta = msta == &mvif->sta ?1218NULL :1219container_of((void *)msta, struct ieee80211_sta, drv_priv);1220vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);12211222tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec));1223sec = (struct sta_rec_sec_uni *)tlv;1224sec->bss_idx = mconf->mt76.idx;1225sec->is_authenticator = 0;1226sec->mgmt_prot = 1; /* only used in MLO mode */1227sec->wlan_idx = (u8)wcid->idx;12281229if (sta) {1230struct ieee80211_link_sta *link_sta;12311232sec->tx_key = 1;1233sec->key_type = 1;1234link_sta = mt792x_sta_to_link_sta(vif, sta, wcid->link_id);12351236if (link_sta)1237memcpy(sec->peer_addr, link_sta->addr, ETH_ALEN);1238} else {1239struct ieee80211_bss_conf *link_conf;12401241link_conf = mt792x_vif_to_bss_conf(vif, wcid->link_id);12421243if (link_conf)1244memcpy(sec->peer_addr, link_conf->bssid, ETH_ALEN);1245}12461247if (cmd == SET_KEY) {1248u8 cipher;12491250sec->add = 1;1251cipher = mt7925_mcu_get_cipher(key->cipher);1252if (cipher == CONNAC3_CIPHER_NONE)1253return -EOPNOTSUPP;12541255if (cipher == CONNAC3_CIPHER_BIP_CMAC_128) {1256sec->cipher_id = CONNAC3_CIPHER_BIP_CMAC_128;1257sec->key_id = sta_key_conf->keyidx;1258sec->key_len = 32;1259memcpy(sec->key, sta_key_conf->key, 16);1260memcpy(sec->key + 16, key->key, 16);1261} else {1262sec->cipher_id = cipher;1263sec->key_id = key->keyidx;1264sec->key_len = key->keylen;1265memcpy(sec->key, key->key, key->keylen);12661267if (cipher == CONNAC3_CIPHER_TKIP) {1268/* Rx/Tx MIC keys are swapped */1269memcpy(sec->key + 16, key->key + 24, 8);1270memcpy(sec->key + 24, key->key + 16, 8);1271}12721273/* store key_conf for BIP batch update */1274if (cipher == CONNAC3_CIPHER_AES_CCMP) {1275memcpy(sta_key_conf->key, key->key, key->keylen);1276sta_key_conf->keyidx = key->keyidx;1277}1278}1279} else {1280sec->add = 0;1281}12821283return 0;1284}12851286int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,1287struct mt76_connac_sta_key_conf *sta_key_conf,1288struct ieee80211_key_conf *key, int mcu_cmd,1289struct mt76_wcid *wcid, enum set_key_cmd cmd,1290struct mt792x_sta *msta)1291{1292struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1293struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id);1294struct sk_buff *skb;1295int ret;12961297skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, wcid,1298MT7925_STA_UPDATE_MAX_SIZE);1299if (IS_ERR(skb))1300return PTR_ERR(skb);13011302ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta);1303if (ret)1304return ret;13051306return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);1307}13081309int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,1310int duration, u8 token_id)1311{1312struct mt792x_vif *mvif = mconf->vif;1313struct ieee80211_vif *vif = container_of((void *)mvif,1314struct ieee80211_vif, drv_priv);1315struct ieee80211_bss_conf *link_conf;1316struct ieee80211_channel *chan;1317const u8 ch_band[] = {1318[NL80211_BAND_2GHZ] = 1,1319[NL80211_BAND_5GHZ] = 2,1320[NL80211_BAND_6GHZ] = 3,1321};1322enum mt7925_roc_req type;1323int center_ch, i = 0;1324bool is_AG_band = false;1325struct {1326u8 id;1327u8 bss_idx;1328u16 tag;1329struct mt792x_bss_conf *mconf;1330struct ieee80211_channel *chan;1331} links[2];13321333struct {1334struct {1335u8 rsv[4];1336} __packed hdr;1337struct roc_acquire_tlv roc[2];1338} __packed req = {1339.roc[0].tag = cpu_to_le16(UNI_ROC_NUM),1340.roc[0].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)),1341.roc[1].tag = cpu_to_le16(UNI_ROC_NUM),1342.roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv))1343};13441345if (!mconf || hweight16(vif->valid_links) < 2 ||1346hweight16(sel_links) != 2)1347return -EPERM;13481349for (i = 0; i < ARRAY_SIZE(links); i++) {1350links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) :1351mconf->link_id;1352link_conf = mt792x_vif_to_bss_conf(vif, links[i].id);1353if (WARN_ON_ONCE(!link_conf))1354return -EPERM;13551356links[i].chan = link_conf->chanreq.oper.chan;1357if (WARN_ON_ONCE(!links[i].chan))1358return -EPERM;13591360links[i].mconf = mt792x_vif_to_link(mvif, links[i].id);1361links[i].tag = links[i].id == mconf->link_id ?1362UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK;13631364is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ;1365}13661367if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)1368type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG :1369MT7925_ROC_REQ_MLSR_AA;1370else1371type = MT7925_ROC_REQ_JOIN;13721373for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) {1374if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan))1375continue;13761377chan = links[i].chan;1378center_ch = ieee80211_frequency_to_channel(chan->center_freq);1379req.roc[i].len = cpu_to_le16(sizeof(struct roc_acquire_tlv));1380req.roc[i].tag = cpu_to_le16(links[i].tag);1381req.roc[i].tokenid = token_id;1382req.roc[i].reqtype = type;1383req.roc[i].maxinterval = cpu_to_le32(duration);1384req.roc[i].bss_idx = links[i].mconf->mt76.idx;1385req.roc[i].control_channel = chan->hw_value;1386req.roc[i].bw = CMD_CBW_20MHZ;1387req.roc[i].bw_from_ap = CMD_CBW_20MHZ;1388req.roc[i].center_chan = center_ch;1389req.roc[i].center_chan_from_ap = center_ch;1390req.roc[i].center_chan2 = 0;1391req.roc[i].center_chan2_from_ap = 0;13921393/* STR : 0xfe indicates BAND_ALL with enabling DBDC1394* EMLSR : 0xff indicates (BAND_AUTO) without DBDC1395*/1396req.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ? 0xfe : 0xff;13971398if (chan->hw_value < center_ch)1399req.roc[i].sco = 1; /* SCA */1400else if (chan->hw_value > center_ch)1401req.roc[i].sco = 3; /* SCB */14021403req.roc[i].band = ch_band[chan->band];1404}14051406return mt76_mcu_send_msg(&mvif->phy->dev->mt76, MCU_UNI_CMD(ROC),1407&req, sizeof(req), true);1408}14091410int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,1411struct ieee80211_channel *chan, int duration,1412enum mt7925_roc_req type, u8 token_id)1413{1414int center_ch = ieee80211_frequency_to_channel(chan->center_freq);1415struct mt792x_dev *dev = phy->dev;1416struct {1417struct {1418u8 rsv[4];1419} __packed hdr;1420struct roc_acquire_tlv roc;1421} __packed req = {1422.roc = {1423.tag = cpu_to_le16(UNI_ROC_ACQUIRE),1424.len = cpu_to_le16(sizeof(struct roc_acquire_tlv)),1425.tokenid = token_id,1426.reqtype = type,1427.maxinterval = cpu_to_le32(duration),1428.bss_idx = mconf->mt76.idx,1429.control_channel = chan->hw_value,1430.bw = CMD_CBW_20MHZ,1431.bw_from_ap = CMD_CBW_20MHZ,1432.center_chan = center_ch,1433.center_chan_from_ap = center_ch,1434.dbdcband = 0xff, /* auto */1435},1436};14371438if (chan->hw_value < center_ch)1439req.roc.sco = 1; /* SCA */1440else if (chan->hw_value > center_ch)1441req.roc.sco = 3; /* SCB */14421443switch (chan->band) {1444case NL80211_BAND_6GHZ:1445req.roc.band = 3;1446break;1447case NL80211_BAND_5GHZ:1448req.roc.band = 2;1449break;1450default:1451req.roc.band = 1;1452break;1453}14541455return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),1456&req, sizeof(req), true);1457}14581459int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,1460u8 token_id)1461{1462struct mt792x_dev *dev = phy->dev;1463struct {1464struct {1465u8 rsv[4];1466} __packed hdr;1467struct roc_abort_tlv {1468__le16 tag;1469__le16 len;1470u8 bss_idx;1471u8 tokenid;1472u8 dbdcband;1473u8 rsv[5];1474} __packed abort;1475} __packed req = {1476.abort = {1477.tag = cpu_to_le16(UNI_ROC_ABORT),1478.len = cpu_to_le16(sizeof(struct roc_abort_tlv)),1479.tokenid = token_id,1480.bss_idx = mconf->mt76.idx,1481.dbdcband = 0xff, /* auto*/1482},1483};14841485return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),1486&req, sizeof(req), true);1487}14881489int mt7925_mcu_set_eeprom(struct mt792x_dev *dev)1490{1491struct {1492u8 _rsv[4];14931494__le16 tag;1495__le16 len;1496u8 buffer_mode;1497u8 format;1498__le16 buf_len;1499} __packed req = {1500.tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),1501.len = cpu_to_le16(sizeof(req) - 4),1502.buffer_mode = EE_MODE_EFUSE,1503.format = EE_FORMAT_WHOLE1504};15051506return mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(EFUSE_CTRL),1507&req, sizeof(req), true, NULL);1508}1509EXPORT_SYMBOL_GPL(mt7925_mcu_set_eeprom);15101511int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev,1512struct ieee80211_bss_conf *link_conf)1513{1514struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);1515struct {1516struct {1517u8 bss_idx;1518u8 pad[3];1519} __packed hdr;1520struct ps_tlv {1521__le16 tag;1522__le16 len;1523u8 ps_state; /* 0: device awake1524* 1: static power save1525* 2: dynamic power saving1526* 3: enter TWT power saving1527* 4: leave TWT power saving1528*/1529u8 pad[3];1530} __packed ps;1531} __packed ps_req = {1532.hdr = {1533.bss_idx = mconf->mt76.idx,1534},1535.ps = {1536.tag = cpu_to_le16(UNI_BSS_INFO_PS),1537.len = cpu_to_le16(sizeof(struct ps_tlv)),1538.ps_state = link_conf->vif->cfg.ps ? 2 : 0,1539},1540};15411542if (link_conf->vif->type != NL80211_IFTYPE_STATION)1543return -EOPNOTSUPP;15441545return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),1546&ps_req, sizeof(ps_req), true);1547}15481549int1550mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev,1551struct ieee80211_bss_conf *link_conf, bool enable)1552{1553struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);1554struct {1555struct {1556u8 bss_idx;1557u8 pad[3];1558} __packed hdr;1559struct bcnft_tlv {1560__le16 tag;1561__le16 len;1562__le16 bcn_interval;1563u8 dtim_period;1564u8 bmc_delivered_ac;1565u8 bmc_triggered_ac;1566u8 pad[3];1567} __packed bcnft;1568} __packed bcnft_req = {1569.hdr = {1570.bss_idx = mconf->mt76.idx,1571},1572.bcnft = {1573.tag = cpu_to_le16(UNI_BSS_INFO_BCNFT),1574.len = cpu_to_le16(sizeof(struct bcnft_tlv)),1575.bcn_interval = cpu_to_le16(link_conf->beacon_int),1576.dtim_period = link_conf->dtim_period,1577},1578};15791580if (link_conf->vif->type != NL80211_IFTYPE_STATION)1581return 0;15821583return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),1584&bcnft_req, sizeof(bcnft_req), true);1585}15861587int1588mt7925_mcu_set_bss_pm(struct mt792x_dev *dev,1589struct ieee80211_bss_conf *link_conf,1590bool enable)1591{1592struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);1593struct {1594struct {1595u8 bss_idx;1596u8 pad[3];1597} __packed hdr;1598struct bcnft_tlv {1599__le16 tag;1600__le16 len;1601__le16 bcn_interval;1602u8 dtim_period;1603u8 bmc_delivered_ac;1604u8 bmc_triggered_ac;1605u8 pad[3];1606} __packed enable;1607} req = {1608.hdr = {1609.bss_idx = mconf->mt76.idx,1610},1611.enable = {1612.tag = cpu_to_le16(UNI_BSS_INFO_BCNFT),1613.len = cpu_to_le16(sizeof(struct bcnft_tlv)),1614.dtim_period = link_conf->dtim_period,1615.bcn_interval = cpu_to_le16(link_conf->beacon_int),1616},1617};1618struct {1619struct {1620u8 bss_idx;1621u8 pad[3];1622} __packed hdr;1623struct pm_disable {1624__le16 tag;1625__le16 len;1626} __packed disable;1627} req1 = {1628.hdr = {1629.bss_idx = mconf->mt76.idx,1630},1631.disable = {1632.tag = cpu_to_le16(UNI_BSS_INFO_PM_DISABLE),1633.len = cpu_to_le16(sizeof(struct pm_disable))1634},1635};1636int err;16371638err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),1639&req1, sizeof(req1), true);1640if (err < 0 || !enable)1641return err;16421643return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),1644&req, sizeof(req), true);1645}16461647static void1648mt7925_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)1649{1650if (!link_sta->he_cap.has_he)1651return;16521653mt76_connac_mcu_sta_he_tlv_v2(skb, link_sta->sta);1654}16551656static void1657mt7925_mcu_sta_he_6g_tlv(struct sk_buff *skb,1658struct ieee80211_link_sta *link_sta)1659{1660struct sta_rec_he_6g_capa *he_6g;1661struct tlv *tlv;16621663if (!link_sta->he_6ghz_capa.capa)1664return;16651666tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g));16671668he_6g = (struct sta_rec_he_6g_capa *)tlv;1669he_6g->capa = link_sta->he_6ghz_capa.capa;1670}16711672static void1673mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)1674{1675struct ieee80211_eht_mcs_nss_supp *mcs_map;1676struct ieee80211_eht_cap_elem_fixed *elem;1677struct sta_rec_eht *eht;1678struct tlv *tlv;16791680if (!link_sta->eht_cap.has_eht)1681return;16821683mcs_map = &link_sta->eht_cap.eht_mcs_nss_supp;1684elem = &link_sta->eht_cap.eht_cap_elem;16851686tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht));16871688eht = (struct sta_rec_eht *)tlv;1689eht->tid_bitmap = 0xff;1690eht->mac_cap = cpu_to_le16(*(u16 *)elem->mac_cap_info);1691eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info);1692eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);16931694if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)1695memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20));1696memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80));1697memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160));1698}16991700static void1701mt7925_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)1702{1703struct sta_rec_ht *ht;1704struct tlv *tlv;17051706if (!link_sta->ht_cap.ht_supported)1707return;17081709tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));17101711ht = (struct sta_rec_ht *)tlv;1712ht->ht_cap = cpu_to_le16(link_sta->ht_cap.cap);1713}17141715static void1716mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)1717{1718struct sta_rec_vht *vht;1719struct tlv *tlv;17201721/* For 6G band, this tlv is necessary to let hw work normally */1722if (!link_sta->he_6ghz_capa.capa && !link_sta->vht_cap.vht_supported)1723return;17241725tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));17261727vht = (struct sta_rec_vht *)tlv;1728vht->vht_cap = cpu_to_le32(link_sta->vht_cap.cap);1729vht->vht_rx_mcs_map = link_sta->vht_cap.vht_mcs.rx_mcs_map;1730vht->vht_tx_mcs_map = link_sta->vht_cap.vht_mcs.tx_mcs_map;1731}17321733static void1734mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,1735struct ieee80211_vif *vif,1736struct ieee80211_link_sta *link_sta)1737{1738struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv;1739struct mt792x_link_sta *mlink;1740struct sta_rec_amsdu *amsdu;1741struct tlv *tlv;17421743if (vif->type != NL80211_IFTYPE_STATION &&1744vif->type != NL80211_IFTYPE_AP)1745return;17461747if (!link_sta->agg.max_amsdu_len)1748return;17491750tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));1751amsdu = (struct sta_rec_amsdu *)tlv;1752amsdu->max_amsdu_num = 8;1753amsdu->amsdu_en = true;17541755mlink = mt792x_sta_to_link(msta, link_sta->link_id);1756mlink->wcid.amsdu = true;17571758switch (link_sta->agg.max_amsdu_len) {1759case IEEE80211_MAX_MPDU_LEN_VHT_11454:1760amsdu->max_mpdu_size =1761IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;1762return;1763case IEEE80211_MAX_MPDU_LEN_HT_7935:1764case IEEE80211_MAX_MPDU_LEN_VHT_7991:1765amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;1766return;1767default:1768amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;1769return;1770}1771}17721773static void1774mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,1775struct ieee80211_vif *vif,1776struct ieee80211_link_sta *link_sta)1777{1778struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1779struct ieee80211_bss_conf *link_conf;1780struct cfg80211_chan_def *chandef;1781struct mt792x_bss_conf *mconf;1782struct sta_rec_phy *phy;1783struct tlv *tlv;1784u8 af = 0, mm = 0;17851786link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id);1787mconf = mt792x_vif_to_link(mvif, link_sta->link_id);1788chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def :1789&link_conf->chanreq.oper;17901791tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));1792phy = (struct sta_rec_phy *)tlv;1793phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,1794chandef->chan->band,1795link_sta);1796phy->basic_rate = cpu_to_le16((u16)link_conf->basic_rates);1797if (link_sta->ht_cap.ht_supported) {1798af = link_sta->ht_cap.ampdu_factor;1799mm = link_sta->ht_cap.ampdu_density;1800}18011802if (link_sta->vht_cap.vht_supported) {1803u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,1804link_sta->vht_cap.cap);18051806af = max_t(u8, af, vht_af);1807}18081809if (link_sta->he_6ghz_capa.capa) {1810af = le16_get_bits(link_sta->he_6ghz_capa.capa,1811IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);1812mm = le16_get_bits(link_sta->he_6ghz_capa.capa,1813IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);1814}18151816phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) |1817FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm);1818phy->max_ampdu_len = af;1819}18201821static void1822mt7925_mcu_sta_state_v2_tlv(struct mt76_phy *mphy, struct sk_buff *skb,1823struct ieee80211_link_sta *link_sta,1824struct ieee80211_vif *vif,1825u8 rcpi, u8 sta_state)1826{1827struct sta_rec_state_v2 {1828__le16 tag;1829__le16 len;1830u8 state;1831u8 rsv[3];1832__le32 flags;1833u8 vht_opmode;1834u8 action;1835u8 rsv2[2];1836} __packed * state;1837struct tlv *tlv;18381839tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));1840state = (struct sta_rec_state_v2 *)tlv;1841state->state = sta_state;18421843if (link_sta->vht_cap.vht_supported) {1844state->vht_opmode = link_sta->bandwidth;1845state->vht_opmode |= link_sta->rx_nss <<1846IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;1847}1848}18491850static void1851mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,1852struct ieee80211_vif *vif,1853struct ieee80211_link_sta *link_sta)1854{1855struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1856struct ieee80211_bss_conf *link_conf;1857struct cfg80211_chan_def *chandef;1858struct sta_rec_ra_info *ra_info;1859struct mt792x_bss_conf *mconf;1860enum nl80211_band band;1861struct tlv *tlv;1862u16 supp_rates;18631864link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id);1865mconf = mt792x_vif_to_link(mvif, link_sta->link_id);1866chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def :1867&link_conf->chanreq.oper;1868band = chandef->chan->band;18691870tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));1871ra_info = (struct sta_rec_ra_info *)tlv;18721873supp_rates = link_sta->supp_rates[band];1874if (band == NL80211_BAND_2GHZ)1875supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) |1876FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf);1877else1878supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates);18791880ra_info->legacy = cpu_to_le16(supp_rates);18811882if (link_sta->ht_cap.ht_supported)1883memcpy(ra_info->rx_mcs_bitmask,1884link_sta->ht_cap.mcs.rx_mask,1885HT_MCS_MASK_NUM);1886}18871888static void1889mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,1890struct ieee80211_vif *vif, struct ieee80211_sta *sta)1891{1892struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1893struct wiphy *wiphy = mvif->phy->mt76->hw->wiphy;1894const struct wiphy_iftype_ext_capab *ext_capa;1895struct sta_rec_eht_mld *eht_mld;1896struct tlv *tlv;1897u16 eml_cap;18981899if (!ieee80211_vif_is_mld(vif))1900return;19011902tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld));1903eht_mld = (struct sta_rec_eht_mld *)tlv;1904eht_mld->mld_type = 0xff;19051906ext_capa = cfg80211_get_iftype_ext_capa(wiphy,1907ieee80211_vif_type_p2p(vif));1908if (!ext_capa)1909return;19101911eml_cap = (vif->cfg.eml_cap & (IEEE80211_EML_CAP_EMLSR_SUPP |1912IEEE80211_EML_CAP_TRANSITION_TIMEOUT)) |1913(ext_capa->eml_capabilities & (IEEE80211_EML_CAP_EMLSR_PADDING_DELAY |1914IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY));19151916if (eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) {1917eht_mld->eml_cap[0] = u16_get_bits(eml_cap, GENMASK(7, 0));1918eht_mld->eml_cap[1] = u16_get_bits(eml_cap, GENMASK(15, 8));1919} else {1920eht_mld->str_cap[0] = BIT(1);1921}1922}19231924static void1925mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,1926struct ieee80211_vif *vif, struct ieee80211_sta *sta)1927{1928struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;1929struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;1930unsigned long valid = mvif->valid_links;1931struct mt792x_bss_conf *mconf;1932struct mt792x_link_sta *mlink;1933struct sta_rec_mld *mld;1934struct tlv *tlv;1935int i, cnt = 0;19361937tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld));1938mld = (struct sta_rec_mld *)tlv;1939memcpy(mld->mac_addr, sta->addr, ETH_ALEN);1940mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx);1941mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx);1942mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2);19431944for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {1945if (cnt == mld->link_num)1946break;19471948mconf = mt792x_vif_to_link(mvif, i);1949mlink = mt792x_sta_to_link(msta, i);1950mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);1951mld->link[cnt++].bss_idx = mconf->mt76.idx;19521953if (mlink != &msta->deflink)1954mld->secondary_id = cpu_to_le16(mlink->wcid.idx);1955}1956}19571958static void1959mt7925_mcu_sta_remove_tlv(struct sk_buff *skb)1960{1961struct sta_rec_remove *rem;1962struct tlv *tlv;19631964tlv = mt76_connac_mcu_add_tlv(skb, 0x25, sizeof(*rem));1965rem = (struct sta_rec_remove *)tlv;1966rem->action = 0;1967}19681969static int1970mt7925_mcu_sta_cmd(struct mt76_phy *phy,1971struct mt76_sta_cmd_info *info)1972{1973struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv;1974struct mt76_dev *dev = phy->dev;1975struct mt792x_bss_conf *mconf;1976struct sk_buff *skb;1977int conn_state;19781979mconf = mt792x_vif_to_link(mvif, info->wcid->link_id);19801981skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid,1982MT7925_STA_UPDATE_MAX_SIZE);1983if (IS_ERR(skb))1984return PTR_ERR(skb);19851986conn_state = info->enable ? CONN_STATE_PORT_SECURE :1987CONN_STATE_DISCONNECT;19881989if (info->enable && info->link_sta) {1990mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf,1991info->link_sta,1992conn_state, info->newly);1993mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta);1994mt7925_mcu_sta_ht_tlv(skb, info->link_sta);1995mt7925_mcu_sta_vht_tlv(skb, info->link_sta);1996mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta);1997mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta);1998mt7925_mcu_sta_he_tlv(skb, info->link_sta);1999mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta);2000mt7925_mcu_sta_eht_tlv(skb, info->link_sta);2001mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif,2002info->link_sta);2003mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta,2004info->vif, info->rcpi,2005info->state);20062007if (info->state != MT76_STA_INFO_STATE_NONE) {2008mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta);2009mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta);2010}2011}20122013if (!info->enable) {2014mt7925_mcu_sta_remove_tlv(skb);2015mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF,2016sizeof(struct tlv));2017} else {2018mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta);2019}20202021return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);2022}20232024int mt7925_mcu_sta_update(struct mt792x_dev *dev,2025struct ieee80211_link_sta *link_sta,2026struct ieee80211_vif *vif, bool enable,2027enum mt76_sta_info_state state)2028{2029struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;2030int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi);2031struct mt76_sta_cmd_info info = {2032.link_sta = link_sta,2033.vif = vif,2034.link_conf = &vif->bss_conf,2035.enable = enable,2036.cmd = MCU_UNI_CMD(STA_REC_UPDATE),2037.state = state,2038.offload_fw = true,2039.rcpi = to_rcpi(rssi),2040};2041struct mt792x_sta *msta;2042struct mt792x_link_sta *mlink;20432044if (link_sta) {2045msta = (struct mt792x_sta *)link_sta->sta->drv_priv;2046mlink = mt792x_sta_to_link(msta, link_sta->link_id);2047}2048info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid;2049info.newly = state != MT76_STA_INFO_STATE_ASSOC;20502051return mt7925_mcu_sta_cmd(&dev->mphy, &info);2052}20532054int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev,2055struct ieee80211_vif *vif,2056bool enable)2057{2058#define MT7925_FIF_BIT_CLR BIT(1)2059#define MT7925_FIF_BIT_SET BIT(0)2060int err = 0;20612062if (enable) {2063err = mt7925_mcu_uni_bss_bcnft(dev, &vif->bss_conf, true);2064if (err < 0)2065return err;20662067return mt7925_mcu_set_rxfilter(dev, 0,2068MT7925_FIF_BIT_SET,2069MT_WF_RFCR_DROP_OTHER_BEACON);2070}20712072err = mt7925_mcu_set_bss_pm(dev, &vif->bss_conf, false);2073if (err < 0)2074return err;20752076return mt7925_mcu_set_rxfilter(dev, 0,2077MT7925_FIF_BIT_CLR,2078MT_WF_RFCR_DROP_OTHER_BEACON);2079}20802081int mt7925_get_txpwr_info(struct mt792x_dev *dev, u8 band_idx, struct mt7925_txpwr *txpwr)2082{2083#define TX_POWER_SHOW_INFO 0x72084#define TXPOWER_ALL_RATE_POWER_INFO 0x22085struct mt7925_txpwr_event *event;2086struct mt7925_txpwr_req req = {2087.tag = cpu_to_le16(TX_POWER_SHOW_INFO),2088.len = cpu_to_le16(sizeof(req) - 4),2089.catg = TXPOWER_ALL_RATE_POWER_INFO,2090.band_idx = band_idx,2091};2092struct sk_buff *skb;2093int ret;20942095ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(TXPOWER),2096&req, sizeof(req), true, &skb);2097if (ret)2098return ret;20992100event = (struct mt7925_txpwr_event *)skb->data;2101memcpy(txpwr, &event->txpwr, sizeof(event->txpwr));21022103dev_kfree_skb(skb);21042105return 0;2106}21072108int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,2109bool enable)2110{2111struct {2112struct {2113u8 band_idx;2114u8 pad[3];2115} __packed hdr;2116struct sniffer_enable_tlv {2117__le16 tag;2118__le16 len;2119u8 enable;2120u8 pad[3];2121} __packed enable;2122} __packed req = {2123.hdr = {2124.band_idx = 0,2125},2126.enable = {2127.tag = cpu_to_le16(UNI_SNIFFER_ENABLE),2128.len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)),2129.enable = enable,2130},2131};21322133return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req),2134true);2135}21362137int mt7925_mcu_config_sniffer(struct mt792x_vif *vif,2138struct ieee80211_chanctx_conf *ctx)2139{2140struct mt76_phy *mphy = vif->phy->mt76;2141struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &mphy->chandef;2142int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;21432144static const u8 ch_band[] = {2145[NL80211_BAND_2GHZ] = 1,2146[NL80211_BAND_5GHZ] = 2,2147[NL80211_BAND_6GHZ] = 3,2148};2149static const u8 ch_width[] = {2150[NL80211_CHAN_WIDTH_20_NOHT] = 0,2151[NL80211_CHAN_WIDTH_20] = 0,2152[NL80211_CHAN_WIDTH_40] = 0,2153[NL80211_CHAN_WIDTH_80] = 1,2154[NL80211_CHAN_WIDTH_160] = 2,2155[NL80211_CHAN_WIDTH_80P80] = 3,2156[NL80211_CHAN_WIDTH_5] = 4,2157[NL80211_CHAN_WIDTH_10] = 5,2158[NL80211_CHAN_WIDTH_320] = 6,2159};21602161struct {2162struct {2163u8 band_idx;2164u8 pad[3];2165} __packed hdr;2166struct config_tlv {2167__le16 tag;2168__le16 len;2169u16 aid;2170u8 ch_band;2171u8 bw;2172u8 control_ch;2173u8 sco;2174u8 center_ch;2175u8 center_ch2;2176u8 drop_err;2177u8 pad[3];2178} __packed tlv;2179} __packed req = {2180.hdr = {2181.band_idx = 0,2182},2183.tlv = {2184.tag = cpu_to_le16(UNI_SNIFFER_CONFIG),2185.len = cpu_to_le16(sizeof(req.tlv)),2186.control_ch = chandef->chan->hw_value,2187.center_ch = ieee80211_frequency_to_channel(freq1),2188.drop_err = 1,2189},2190};21912192if (chandef->chan->band < ARRAY_SIZE(ch_band))2193req.tlv.ch_band = ch_band[chandef->chan->band];2194if (chandef->width < ARRAY_SIZE(ch_width))2195req.tlv.bw = ch_width[chandef->width];21962197if (freq2)2198req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2);21992200if (req.tlv.control_ch < req.tlv.center_ch)2201req.tlv.sco = 1; /* SCA */2202else if (req.tlv.control_ch > req.tlv.center_ch)2203req.tlv.sco = 3; /* SCB */22042205return mt76_mcu_send_msg(mphy->dev, MCU_UNI_CMD(SNIFFER),2206&req, sizeof(req), true);2207}22082209int2210mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,2211struct ieee80211_hw *hw,2212struct ieee80211_vif *vif,2213bool enable)2214{2215struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;2216struct ieee80211_mutable_offsets offs;2217struct {2218struct req_hdr {2219u8 bss_idx;2220u8 pad[3];2221} __packed hdr;2222struct bcn_content_tlv {2223__le16 tag;2224__le16 len;2225__le16 tim_ie_pos;2226__le16 csa_ie_pos;2227__le16 bcc_ie_pos;2228/* 0: disable beacon offload2229* 1: enable beacon offload2230* 2: update probe respond offload2231*/2232u8 enable;2233/* 0: legacy format (TXD + payload)2234* 1: only cap field IE2235*/2236u8 type;2237__le16 pkt_len;2238u8 pkt[512];2239} __packed beacon_tlv;2240} req = {2241.hdr = {2242.bss_idx = mvif->bss_conf.mt76.idx,2243},2244.beacon_tlv = {2245.tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),2246.len = cpu_to_le16(sizeof(struct bcn_content_tlv)),2247.enable = enable,2248.type = 1,2249},2250};2251struct sk_buff *skb;2252u8 cap_offs;22532254/* support enable/update process only2255* disable flow would be handled in bss stop handler automatically2256*/2257if (!enable)2258return -EOPNOTSUPP;22592260skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);2261if (!skb)2262return -EINVAL;22632264cap_offs = offsetof(struct ieee80211_mgmt, u.beacon.capab_info);2265if (!skb_pull(skb, cap_offs)) {2266dev_err(dev->mt76.dev, "beacon format err\n");2267dev_kfree_skb(skb);2268return -EINVAL;2269}22702271if (skb->len > 512) {2272dev_err(dev->mt76.dev, "beacon size limit exceed\n");2273dev_kfree_skb(skb);2274return -EINVAL;2275}22762277memcpy(req.beacon_tlv.pkt, skb->data, skb->len);2278req.beacon_tlv.pkt_len = cpu_to_le16(skb->len);2279offs.tim_offset -= cap_offs;2280req.beacon_tlv.tim_ie_pos = cpu_to_le16(offs.tim_offset);22812282if (offs.cntdwn_counter_offs[0]) {2283u16 csa_offs;22842285csa_offs = offs.cntdwn_counter_offs[0] - cap_offs - 4;2286req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);2287}2288dev_kfree_skb(skb);22892290return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),2291&req, sizeof(req), true);2292}22932294static2295void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy,2296struct ieee80211_bss_conf *link_conf,2297struct ieee80211_chanctx_conf *ctx)2298{2299struct cfg80211_chan_def *chandef = ctx ? &ctx->def :2300&link_conf->chanreq.oper;2301int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;2302enum nl80211_band band = chandef->chan->band;2303struct bss_rlm_tlv *req;2304struct tlv *tlv;23052306tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*req));2307req = (struct bss_rlm_tlv *)tlv;2308req->control_channel = chandef->chan->hw_value;2309req->center_chan = ieee80211_frequency_to_channel(freq1);2310req->center_chan2 = 0;2311req->tx_streams = hweight8(phy->antenna_mask);2312req->ht_op_info = 4; /* set HT 40M allowed */2313req->rx_streams = hweight8(phy->antenna_mask);2314req->center_chan2 = 0;2315req->sco = 0;2316req->band = 1;23172318switch (band) {2319case NL80211_BAND_2GHZ:2320req->band = 1;2321break;2322case NL80211_BAND_5GHZ:2323req->band = 2;2324break;2325case NL80211_BAND_6GHZ:2326req->band = 3;2327break;2328default:2329break;2330}23312332switch (chandef->width) {2333case NL80211_CHAN_WIDTH_40:2334req->bw = CMD_CBW_40MHZ;2335break;2336case NL80211_CHAN_WIDTH_80:2337req->bw = CMD_CBW_80MHZ;2338break;2339case NL80211_CHAN_WIDTH_80P80:2340req->bw = CMD_CBW_8080MHZ;2341req->center_chan2 = ieee80211_frequency_to_channel(freq2);2342break;2343case NL80211_CHAN_WIDTH_160:2344req->bw = CMD_CBW_160MHZ;2345break;2346case NL80211_CHAN_WIDTH_5:2347req->bw = CMD_CBW_5MHZ;2348break;2349case NL80211_CHAN_WIDTH_10:2350req->bw = CMD_CBW_10MHZ;2351break;2352case NL80211_CHAN_WIDTH_20_NOHT:2353case NL80211_CHAN_WIDTH_20:2354default:2355req->bw = CMD_CBW_20MHZ;2356req->ht_op_info = 0;2357break;2358}23592360if (req->control_channel < req->center_chan)2361req->sco = 1; /* SCA */2362else if (req->control_channel > req->center_chan)2363req->sco = 3; /* SCB */2364}23652366static struct sk_buff *2367__mt7925_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, int len)2368{2369struct bss_req_hdr hdr = {2370.bss_idx = mvif->idx,2371};2372struct sk_buff *skb;23732374skb = mt76_mcu_msg_alloc(dev, NULL, len);2375if (!skb)2376return ERR_PTR(-ENOMEM);23772378skb_put_data(skb, &hdr, sizeof(hdr));23792380return skb;2381}23822383static2384void mt7925_mcu_bss_eht_tlv(struct sk_buff *skb, struct mt76_phy *phy,2385struct ieee80211_bss_conf *link_conf,2386struct ieee80211_chanctx_conf *ctx)2387{2388struct cfg80211_chan_def *chandef = ctx ? &ctx->def :2389&link_conf->chanreq.oper;23902391struct bss_eht_tlv *req;2392struct tlv *tlv;23932394tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_EHT, sizeof(*req));2395req = (struct bss_eht_tlv *)tlv;2396req->is_eth_dscb_present = chandef->punctured ? 1 : 0;2397req->eht_dis_sub_chan_bitmap = cpu_to_le16(chandef->punctured);2398}23992400int mt7925_mcu_set_eht_pp(struct mt76_phy *phy, struct mt76_vif_link *mvif,2401struct ieee80211_bss_conf *link_conf,2402struct ieee80211_chanctx_conf *ctx)2403{2404struct sk_buff *skb;24052406skb = __mt7925_mcu_alloc_bss_req(phy->dev, mvif,2407MT7925_BSS_UPDATE_MAX_SIZE);2408if (IS_ERR(skb))2409return PTR_ERR(skb);24102411mt7925_mcu_bss_eht_tlv(skb, phy, link_conf, ctx);24122413return mt76_mcu_skb_send_msg(phy->dev, skb,2414MCU_UNI_CMD(BSS_INFO_UPDATE), true);2415}24162417int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif,2418struct ieee80211_bss_conf *link_conf,2419struct ieee80211_chanctx_conf *ctx)2420{2421struct sk_buff *skb;24222423skb = __mt7925_mcu_alloc_bss_req(phy->dev, mvif,2424MT7925_BSS_UPDATE_MAX_SIZE);2425if (IS_ERR(skb))2426return PTR_ERR(skb);24272428mt7925_mcu_bss_rlm_tlv(skb, phy, link_conf, ctx);24292430return mt76_mcu_skb_send_msg(phy->dev, skb,2431MCU_UNI_CMD(BSS_INFO_UPDATE), true);2432}24332434static u82435mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,2436enum nl80211_band band,2437struct ieee80211_link_sta *link_sta)2438{2439struct ieee80211_he_6ghz_capa *he_6ghz_capa;2440const struct ieee80211_sta_eht_cap *eht_cap;2441__le16 capa = 0;2442u8 mode = 0;24432444if (link_sta) {2445he_6ghz_capa = &link_sta->he_6ghz_capa;2446eht_cap = &link_sta->eht_cap;2447} else {2448struct ieee80211_supported_band *sband;24492450sband = phy->hw->wiphy->bands[band];2451capa = ieee80211_get_he_6ghz_capa(sband, vif->type);2452he_6ghz_capa = (struct ieee80211_he_6ghz_capa *)&capa;24532454eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type);2455}24562457switch (band) {2458case NL80211_BAND_2GHZ:2459if (eht_cap && eht_cap->has_eht)2460mode |= PHY_MODE_BE_24G;2461break;2462case NL80211_BAND_5GHZ:2463if (eht_cap && eht_cap->has_eht)2464mode |= PHY_MODE_BE_5G;2465break;2466case NL80211_BAND_6GHZ:2467if (he_6ghz_capa && he_6ghz_capa->capa)2468mode |= PHY_MODE_AX_6G;24692470if (eht_cap && eht_cap->has_eht)2471mode |= PHY_MODE_BE_6G;2472break;2473default:2474break;2475}24762477return mode;2478}24792480static void2481mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,2482struct ieee80211_bss_conf *link_conf,2483struct ieee80211_link_sta *link_sta,2484struct ieee80211_chanctx_conf *ctx,2485struct mt76_phy *phy, u16 wlan_idx,2486bool enable)2487{2488struct ieee80211_vif *vif = link_conf->vif;2489struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);2490struct cfg80211_chan_def *chandef = ctx ? &ctx->def :2491&link_conf->chanreq.oper;2492enum nl80211_band band = chandef->chan->band;2493struct mt76_connac_bss_basic_tlv *basic_req;2494struct mt792x_link_sta *mlink;2495struct tlv *tlv;2496int conn_type;2497u8 idx;24982499tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req));2500basic_req = (struct mt76_connac_bss_basic_tlv *)tlv;25012502idx = mconf->mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 :2503mconf->mt76.omac_idx;2504basic_req->hw_bss_idx = idx;25052506basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band,2507link_sta);25082509if (band == NL80211_BAND_2GHZ)2510basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX);2511else2512basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX);25132514memcpy(basic_req->bssid, link_conf->bssid, ETH_ALEN);2515basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta);2516basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int);2517basic_req->dtim_period = link_conf->dtim_period;2518basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);2519basic_req->link_idx = mconf->mt76.idx;25202521if (link_sta) {2522struct mt792x_sta *msta;25232524msta = (struct mt792x_sta *)link_sta->sta->drv_priv;2525mlink = mt792x_sta_to_link(msta, link_sta->link_id);25262527} else {2528mlink = &mconf->vif->sta.deflink;2529}25302531basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx);2532basic_req->omac_idx = mconf->mt76.omac_idx;2533basic_req->band_idx = mconf->mt76.band_idx;2534basic_req->wmm_idx = mconf->mt76.wmm_idx;2535basic_req->conn_state = !enable;25362537switch (vif->type) {2538case NL80211_IFTYPE_MESH_POINT:2539case NL80211_IFTYPE_AP:2540if (vif->p2p)2541conn_type = CONNECTION_P2P_GO;2542else2543conn_type = CONNECTION_INFRA_AP;2544basic_req->conn_type = cpu_to_le32(conn_type);2545basic_req->active = enable;2546break;2547case NL80211_IFTYPE_STATION:2548if (vif->p2p)2549conn_type = CONNECTION_P2P_GC;2550else2551conn_type = CONNECTION_INFRA_STA;2552basic_req->conn_type = cpu_to_le32(conn_type);2553basic_req->active = true;2554break;2555case NL80211_IFTYPE_ADHOC:2556basic_req->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);2557basic_req->active = true;2558break;2559default:2560WARN_ON(1);2561break;2562}2563}25642565static void2566mt7925_mcu_bss_sec_tlv(struct sk_buff *skb,2567struct ieee80211_bss_conf *link_conf)2568{2569struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);2570struct mt76_vif_link *mvif = &mconf->mt76;2571struct bss_sec_tlv {2572__le16 tag;2573__le16 len;2574u8 mode;2575u8 status;2576u8 cipher;2577u8 __rsv;2578} __packed * sec;2579struct tlv *tlv;25802581tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec));2582sec = (struct bss_sec_tlv *)tlv;25832584switch (mvif->cipher) {2585case CONNAC3_CIPHER_GCMP_256:2586case CONNAC3_CIPHER_GCMP:2587sec->mode = MODE_WPA3_SAE;2588sec->status = 8;2589break;2590case CONNAC3_CIPHER_AES_CCMP:2591sec->mode = MODE_WPA2_PSK;2592sec->status = 6;2593break;2594case CONNAC3_CIPHER_TKIP:2595sec->mode = MODE_WPA2_PSK;2596sec->status = 4;2597break;2598case CONNAC3_CIPHER_WEP104:2599case CONNAC3_CIPHER_WEP40:2600sec->mode = MODE_SHARED;2601sec->status = 0;2602break;2603default:2604sec->mode = MODE_OPEN;2605sec->status = 1;2606break;2607}26082609sec->cipher = mvif->cipher;2610}26112612static void2613mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy,2614struct ieee80211_chanctx_conf *ctx,2615struct ieee80211_bss_conf *link_conf)2616{2617struct cfg80211_chan_def *chandef = ctx ? &ctx->def :2618&link_conf->chanreq.oper;2619struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);2620enum nl80211_band band = chandef->chan->band;2621struct mt76_vif_link *mvif = &mconf->mt76;2622struct bss_rate_tlv *bmc;2623struct tlv *tlv;2624u8 idx = mvif->mcast_rates_idx ?2625mvif->mcast_rates_idx : mvif->basic_rates_idx;26262627tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc));26282629bmc = (struct bss_rate_tlv *)tlv;26302631if (band == NL80211_BAND_2GHZ)2632bmc->basic_rate = cpu_to_le16(HR_DSSS_ERP_BASIC_RATE);2633else2634bmc->basic_rate = cpu_to_le16(OFDM_BASIC_RATE);26352636bmc->short_preamble = (band == NL80211_BAND_2GHZ);2637bmc->bc_fixed_rate = idx;2638bmc->mc_fixed_rate = idx;2639}26402641static void2642mt7925_mcu_bss_mld_tlv(struct sk_buff *skb,2643struct ieee80211_bss_conf *link_conf)2644{2645struct ieee80211_vif *vif = link_conf->vif;2646struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);2647struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;2648struct mt792x_phy *phy = mvif->phy;2649struct bss_mld_tlv *mld;2650struct tlv *tlv;2651bool is_mld;26522653is_mld = ieee80211_vif_is_mld(link_conf->vif) ||2654(hweight16(mvif->valid_links) > 1);26552656tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld));2657mld = (struct bss_mld_tlv *)tlv;26582659mld->link_id = is_mld ? link_conf->link_id : 0xff;2660/* apply the index of the primary link */2661mld->group_mld_id = is_mld ? mvif->bss_conf.mt76.idx : 0xff;2662mld->own_mld_id = mconf->mt76.idx + 32;2663mld->remap_idx = 0xff;26642665if (phy->chip_cap & MT792x_CHIP_CAP_MLO_EML_EN) {2666mld->eml_enable = !!(link_conf->vif->cfg.eml_cap &2667IEEE80211_EML_CAP_EMLSR_SUPP);2668} else {2669mld->eml_enable = 0;2670}26712672memcpy(mld->mac_addr, vif->addr, ETH_ALEN);2673}26742675static void2676mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf)2677{2678struct mt76_connac_bss_qos_tlv *qos;2679struct tlv *tlv;26802681tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_QBSS, sizeof(*qos));2682qos = (struct mt76_connac_bss_qos_tlv *)tlv;2683qos->qos = link_conf->qos;2684}26852686static void2687mt7925_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,2688bool enable)2689{2690struct bss_info_uni_mbssid *mbssid;2691struct tlv *tlv;26922693if (!enable && !link_conf->bssid_indicator)2694return;26952696tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_11V_MBSSID,2697sizeof(*mbssid));26982699mbssid = (struct bss_info_uni_mbssid *)tlv;2700mbssid->max_indicator = link_conf->bssid_indicator;2701mbssid->mbss_idx = link_conf->bssid_index;2702mbssid->tx_bss_omac_idx = 0;2703}27042705static void2706mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,2707struct mt792x_phy *phy)2708{2709#define DEFAULT_HE_PE_DURATION 42710#define DEFAULT_HE_DURATION_RTS_THRES 10232711const struct ieee80211_sta_he_cap *cap;2712struct bss_info_uni_he *he;2713struct tlv *tlv;27142715cap = mt76_connac_get_he_phy_cap(phy->mt76, link_conf->vif);27162717tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));27182719he = (struct bss_info_uni_he *)tlv;2720he->he_pe_duration = link_conf->htc_trig_based_pkt_ext;2721if (!he->he_pe_duration)2722he->he_pe_duration = DEFAULT_HE_PE_DURATION;27232724he->he_rts_thres = cpu_to_le16(link_conf->frame_time_rts_th);2725if (!he->he_rts_thres)2726he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);27272728he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;2729he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;2730he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;2731}27322733static void2734mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,2735bool enable)2736{2737struct bss_info_uni_bss_color *color;2738struct tlv *tlv;27392740tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BSS_COLOR, sizeof(*color));2741color = (struct bss_info_uni_bss_color *)tlv;27422743color->enable = enable ?2744link_conf->he_bss_color.enabled : 0;2745color->bss_color = enable ?2746link_conf->he_bss_color.color : 0;2747}27482749static void2750mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb,2751struct ieee80211_bss_conf *link_conf)2752{2753struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;2754struct mt792x_phy *phy = mvif->phy;2755struct bss_ifs_time_tlv *ifs_time;2756struct tlv *tlv;27572758tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time));2759ifs_time = (struct bss_ifs_time_tlv *)tlv;2760ifs_time->slot_valid = true;2761ifs_time->slot_time = cpu_to_le16(phy->slottime);2762}27632764int mt7925_mcu_set_timing(struct mt792x_phy *phy,2765struct ieee80211_bss_conf *link_conf)2766{2767struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);2768struct mt792x_dev *dev = phy->dev;2769struct sk_buff *skb;27702771skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,2772MT7925_BSS_UPDATE_MAX_SIZE);2773if (IS_ERR(skb))2774return PTR_ERR(skb);27752776mt7925_mcu_bss_ifs_tlv(skb, link_conf);27772778return mt76_mcu_skb_send_msg(&dev->mt76, skb,2779MCU_UNI_CMD(BSS_INFO_UPDATE), true);2780}27812782void mt7925_mcu_del_dev(struct mt76_dev *mdev,2783struct ieee80211_vif *vif)2784{2785struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2786struct {2787struct {2788u8 omac_idx;2789u8 band_idx;2790__le16 pad;2791} __packed hdr;2792struct req_tlv {2793__le16 tag;2794__le16 len;2795u8 active;2796u8 link_idx; /* hw link idx */2797u8 omac_addr[ETH_ALEN];2798} __packed tlv;2799} dev_req = {2800.tlv = {2801.tag = cpu_to_le16(DEV_INFO_ACTIVE),2802.len = cpu_to_le16(sizeof(struct req_tlv)),2803.active = true,2804},2805};2806struct {2807struct {2808u8 bss_idx;2809u8 pad[3];2810} __packed hdr;2811struct mt76_connac_bss_basic_tlv basic;2812} basic_req = {2813.basic = {2814.tag = cpu_to_le16(UNI_BSS_INFO_BASIC),2815.len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)),2816.active = true,2817.conn_state = 1,2818},2819};28202821dev_req.hdr.omac_idx = mvif->omac_idx;2822dev_req.hdr.band_idx = mvif->band_idx;28232824basic_req.hdr.bss_idx = mvif->idx;2825basic_req.basic.omac_idx = mvif->omac_idx;2826basic_req.basic.band_idx = mvif->band_idx;2827basic_req.basic.link_idx = mvif->link_idx;28282829mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE),2830&basic_req, sizeof(basic_req), true);28312832/* recovery omac address for the legacy interface */2833memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN);2834mt76_mcu_send_msg(mdev, MCU_UNI_CMD(DEV_INFO_UPDATE),2835&dev_req, sizeof(dev_req), true);2836}28372838int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,2839struct ieee80211_chanctx_conf *ctx,2840struct ieee80211_bss_conf *link_conf,2841struct ieee80211_link_sta *link_sta,2842int enable)2843{2844struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv;2845struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);2846struct mt792x_dev *dev = phy->dev;2847struct mt792x_link_sta *mlink_bc;2848struct sk_buff *skb;28492850skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,2851MT7925_BSS_UPDATE_MAX_SIZE);2852if (IS_ERR(skb))2853return PTR_ERR(skb);28542855mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id);28562857/* bss_basic must be first */2858mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76,2859mlink_bc->wcid.idx, enable);2860mt7925_mcu_bss_sec_tlv(skb, link_conf);2861mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf);2862mt7925_mcu_bss_qos_tlv(skb, link_conf);2863mt7925_mcu_bss_mld_tlv(skb, link_conf);2864mt7925_mcu_bss_ifs_tlv(skb, link_conf);28652866if (link_conf->he_support) {2867mt7925_mcu_bss_he_tlv(skb, link_conf, phy);2868mt7925_mcu_bss_color_tlv(skb, link_conf, enable);2869}28702871if (enable) {2872mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx);2873mt7925_mcu_bss_mbssid_tlv(skb, link_conf, enable);2874}28752876return mt76_mcu_skb_send_msg(&dev->mt76, skb,2877MCU_UNI_CMD(BSS_INFO_UPDATE), true);2878}28792880int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)2881{2882struct mt76_dev *mdev = phy->dev;28832884struct mbmc_conf_tlv *conf;2885struct mbmc_set_req *hdr;2886struct sk_buff *skb;2887struct tlv *tlv;2888int max_len, err;28892890max_len = sizeof(*hdr) + sizeof(*conf);2891skb = mt76_mcu_msg_alloc(mdev, NULL, max_len);2892if (!skb)2893return -ENOMEM;28942895hdr = (struct mbmc_set_req *)skb_put(skb, sizeof(*hdr));28962897tlv = mt76_connac_mcu_add_tlv(skb, UNI_MBMC_SETTING, sizeof(*conf));2898conf = (struct mbmc_conf_tlv *)tlv;28992900conf->mbmc_en = enable;2901conf->band = 0; /* unused */29022903err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SET_DBDC_PARMS),2904true);29052906return err;2907}29082909static void2910mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev,2911struct sk_buff *skb,2912struct ieee80211_scan_ies *scan_ies)2913{2914u32 max_len = sizeof(struct scan_ie_tlv) + MT76_CONNAC_SCAN_IE_LEN;2915struct scan_ie_tlv *ie;2916enum nl80211_band i;2917struct tlv *tlv;2918const u8 *ies;2919u16 ies_len;29202921for (i = 0; i <= NL80211_BAND_6GHZ; i++) {2922if (i == NL80211_BAND_60GHZ)2923continue;29242925ies = scan_ies->ies[i];2926ies_len = scan_ies->len[i];29272928if (!ies || !ies_len)2929continue;29302931if (ies_len > max_len)2932return;29332934tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE,2935sizeof(*ie) + ies_len);2936ie = (struct scan_ie_tlv *)tlv;29372938memcpy(ie->ies, ies, ies_len);2939ie->ies_len = cpu_to_le16(ies_len);29402941switch (i) {2942case NL80211_BAND_2GHZ:2943ie->band = 1;2944break;2945case NL80211_BAND_6GHZ:2946ie->band = 3;2947break;2948default:2949ie->band = 2;2950break;2951}29522953max_len -= (sizeof(*ie) + ies_len);2954}2955}29562957int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,2958struct ieee80211_scan_request *scan_req)2959{2960struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2961struct cfg80211_scan_request *sreq = &scan_req->req;2962int n_ssids = 0, err, i;2963struct ieee80211_channel **scan_list = sreq->channels;2964struct mt76_dev *mdev = phy->dev;2965struct mt76_connac_mcu_scan_channel *chan;2966struct sk_buff *skb;2967struct scan_hdr_tlv *hdr;2968struct scan_req_tlv *req;2969struct scan_ssid_tlv *ssid;2970struct scan_bssid_tlv *bssid;2971struct scan_chan_info_tlv *chan_info;2972struct scan_ie_tlv *ie;2973struct scan_misc_tlv *misc;2974struct tlv *tlv;2975int max_len;29762977if (test_bit(MT76_HW_SCANNING, &phy->state))2978return -EBUSY;29792980max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) +2981sizeof(*bssid) * MT7925_RNR_SCAN_MAX_BSSIDS +2982sizeof(*chan_info) + sizeof(*misc) + sizeof(*ie) +2983MT76_CONNAC_SCAN_IE_LEN;29842985skb = mt76_mcu_msg_alloc(mdev, NULL, max_len);2986if (!skb)2987return -ENOMEM;29882989set_bit(MT76_HW_SCANNING, &phy->state);2990mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;29912992hdr = (struct scan_hdr_tlv *)skb_put(skb, sizeof(*hdr));2993hdr->seq_num = mvif->scan_seq_num | mvif->band_idx << 7;2994hdr->bss_idx = mvif->idx;29952996tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_REQ, sizeof(*req));2997req = (struct scan_req_tlv *)tlv;2998req->scan_type = sreq->n_ssids ? 1 : 0;2999req->probe_req_num = sreq->n_ssids ? 2 : 0;30003001tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID, sizeof(*ssid));3002ssid = (struct scan_ssid_tlv *)tlv;3003for (i = 0; i < sreq->n_ssids; i++) {3004if (!sreq->ssids[i].ssid_len)3005continue;3006if (i >= MT7925_RNR_SCAN_MAX_BSSIDS)3007break;30083009ssid->ssids[n_ssids].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);3010memcpy(ssid->ssids[n_ssids].ssid, sreq->ssids[i].ssid,3011sreq->ssids[i].ssid_len);3012n_ssids++;3013}3014ssid->ssid_type = n_ssids ? BIT(2) : BIT(0);3015ssid->ssids_num = n_ssids;30163017if (sreq->n_6ghz_params) {3018u8 j;30193020mt76_connac_mcu_build_rnr_scan_param(mdev, sreq);30213022for (j = 0; j < mdev->rnr.bssid_num; j++) {3023if (j >= MT7925_RNR_SCAN_MAX_BSSIDS)3024break;30253026tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID,3027sizeof(*bssid));3028bssid = (struct scan_bssid_tlv *)tlv;30293030ether_addr_copy(bssid->bssid, mdev->rnr.bssid[j]);3031bssid->match_ch = mdev->rnr.channel[j];3032bssid->match_ssid_ind = MT7925_RNR_SCAN_MAX_BSSIDS;3033bssid->match_short_ssid_ind = MT7925_RNR_SCAN_MAX_BSSIDS;3034}3035req->scan_func |= SCAN_FUNC_RNR_SCAN;3036} else {3037tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, sizeof(*bssid));3038bssid = (struct scan_bssid_tlv *)tlv;30393040ether_addr_copy(bssid->bssid, sreq->bssid);3041}30423043tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info));3044chan_info = (struct scan_chan_info_tlv *)tlv;3045chan_info->channels_num = min_t(u8, sreq->n_channels,3046ARRAY_SIZE(chan_info->channels));3047for (i = 0; i < chan_info->channels_num; i++) {3048chan = &chan_info->channels[i];30493050switch (scan_list[i]->band) {3051case NL80211_BAND_2GHZ:3052chan->band = 1;3053break;3054case NL80211_BAND_6GHZ:3055chan->band = 3;3056break;3057default:3058chan->band = 2;3059break;3060}3061chan->channel_num = scan_list[i]->hw_value;3062}3063chan_info->channel_type = sreq->n_channels ? 4 : 0;30643065req->scan_func |= SCAN_FUNC_SPLIT_SCAN;30663067tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_MISC, sizeof(*misc));3068misc = (struct scan_misc_tlv *)tlv;3069if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {3070get_random_mask_addr(misc->random_mac, sreq->mac_addr,3071sreq->mac_addr_mask);3072req->scan_func |= SCAN_FUNC_RANDOM_MAC;3073}30743075/* Append scan probe IEs as the last tlv */3076mt7925_mcu_build_scan_ie_tlv(mdev, skb, &scan_req->ies);30773078err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ),3079true);3080if (err < 0)3081clear_bit(MT76_HW_SCANNING, &phy->state);30823083return err;3084}3085EXPORT_SYMBOL_GPL(mt7925_mcu_hw_scan);30863087int mt7925_mcu_sched_scan_req(struct mt76_phy *phy,3088struct ieee80211_vif *vif,3089struct cfg80211_sched_scan_request *sreq,3090struct ieee80211_scan_ies *ies)3091{3092struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;3093struct ieee80211_channel **scan_list = sreq->channels;3094struct mt76_connac_mcu_scan_channel *chan;3095struct mt76_dev *mdev = phy->dev;3096struct cfg80211_match_set *cfg_match;3097struct cfg80211_ssid *cfg_ssid;30983099struct scan_hdr_tlv *hdr;3100struct scan_sched_req *req;3101struct scan_ssid_tlv *ssid;3102struct scan_chan_info_tlv *chan_info;3103struct scan_ie_tlv *ie;3104struct scan_sched_ssid_match_sets *match;3105struct sk_buff *skb;3106struct tlv *tlv;3107int i, max_len;31083109max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) +3110sizeof(*chan_info) + sizeof(*ie) +3111sizeof(*match);31123113skb = mt76_mcu_msg_alloc(mdev, NULL, max_len);3114if (!skb)3115return -ENOMEM;31163117mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;31183119hdr = (struct scan_hdr_tlv *)skb_put(skb, sizeof(*hdr));3120hdr->seq_num = mvif->scan_seq_num | mvif->band_idx << 7;3121hdr->bss_idx = mvif->idx;31223123tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SCHED_REQ, sizeof(*req));3124req = (struct scan_sched_req *)tlv;3125req->version = 1;31263127if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)3128req->scan_func |= SCAN_FUNC_RANDOM_MAC;31293130req->intervals_num = sreq->n_scan_plans;3131for (i = 0; i < req->intervals_num; i++)3132req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval);31333134tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID, sizeof(*ssid));3135ssid = (struct scan_ssid_tlv *)tlv;31363137ssid->ssids_num = sreq->n_ssids;3138ssid->ssid_type = BIT(2);3139for (i = 0; i < ssid->ssids_num; i++) {3140cfg_ssid = &sreq->ssids[i];3141memcpy(ssid->ssids[i].ssid, cfg_ssid->ssid, cfg_ssid->ssid_len);3142ssid->ssids[i].ssid_len = cpu_to_le32(cfg_ssid->ssid_len);3143}31443145tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID_MATCH_SETS, sizeof(*match));3146match = (struct scan_sched_ssid_match_sets *)tlv;3147match->match_num = sreq->n_match_sets;3148for (i = 0; i < match->match_num; i++) {3149cfg_match = &sreq->match_sets[i];3150memcpy(match->match[i].ssid, cfg_match->ssid.ssid,3151cfg_match->ssid.ssid_len);3152match->match[i].rssi_th = cpu_to_le32(cfg_match->rssi_thold);3153match->match[i].ssid_len = cfg_match->ssid.ssid_len;3154}31553156tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info));3157chan_info = (struct scan_chan_info_tlv *)tlv;3158chan_info->channels_num = min_t(u8, sreq->n_channels,3159ARRAY_SIZE(chan_info->channels));3160for (i = 0; i < chan_info->channels_num; i++) {3161chan = &chan_info->channels[i];31623163switch (scan_list[i]->band) {3164case NL80211_BAND_2GHZ:3165chan->band = 1;3166break;3167case NL80211_BAND_6GHZ:3168chan->band = 3;3169break;3170default:3171chan->band = 2;3172break;3173}3174chan->channel_num = scan_list[i]->hw_value;3175}3176chan_info->channel_type = sreq->n_channels ? 4 : 0;31773178/* Append scan probe IEs as the last tlv */3179mt7925_mcu_build_scan_ie_tlv(mdev, skb, ies);31803181return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ),3182true);3183}3184EXPORT_SYMBOL_GPL(mt7925_mcu_sched_scan_req);31853186int3187mt7925_mcu_sched_scan_enable(struct mt76_phy *phy,3188struct ieee80211_vif *vif,3189bool enable)3190{3191struct mt76_dev *mdev = phy->dev;3192struct scan_sched_enable *req;3193struct scan_hdr_tlv *hdr;3194struct sk_buff *skb;3195struct tlv *tlv;3196int max_len;31973198max_len = sizeof(*hdr) + sizeof(*req);31993200skb = mt76_mcu_msg_alloc(mdev, NULL, max_len);3201if (!skb)3202return -ENOMEM;32033204hdr = (struct scan_hdr_tlv *)skb_put(skb, sizeof(*hdr));3205hdr->seq_num = 0;3206hdr->bss_idx = 0;32073208tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SCHED_ENABLE, sizeof(*req));3209req = (struct scan_sched_enable *)tlv;3210req->active = !enable;32113212if (enable)3213set_bit(MT76_HW_SCHED_SCANNING, &phy->state);3214else3215clear_bit(MT76_HW_SCHED_SCANNING, &phy->state);32163217return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ),3218true);3219}32203221int mt7925_mcu_cancel_hw_scan(struct mt76_phy *phy,3222struct ieee80211_vif *vif)3223{3224struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;3225struct {3226struct scan_hdr {3227u8 seq_num;3228u8 bss_idx;3229u8 pad[2];3230} __packed hdr;3231struct scan_cancel_tlv {3232__le16 tag;3233__le16 len;3234u8 is_ext_channel;3235u8 rsv[3];3236} __packed cancel;3237} req = {3238.hdr = {3239.seq_num = mvif->scan_seq_num,3240.bss_idx = mvif->idx,3241},3242.cancel = {3243.tag = cpu_to_le16(UNI_SCAN_CANCEL),3244.len = cpu_to_le16(sizeof(struct scan_cancel_tlv)),3245},3246};32473248if (test_and_clear_bit(MT76_HW_SCANNING, &phy->state)) {3249struct cfg80211_scan_info info = {3250.aborted = true,3251};32523253ieee80211_scan_completed(phy->hw, &info);3254}32553256return mt76_mcu_send_msg(phy->dev, MCU_UNI_CMD(SCAN_REQ),3257&req, sizeof(req), true);3258}3259EXPORT_SYMBOL_GPL(mt7925_mcu_cancel_hw_scan);32603261int mt7925_mcu_set_channel_domain(struct mt76_phy *phy)3262{3263int len, i, n_max_channels, n_2ch = 0, n_5ch = 0, n_6ch = 0;3264struct {3265struct {3266u8 alpha2[4]; /* regulatory_request.alpha2 */3267u8 bw_2g; /* BW_20_40M 03268* BW_20M 13269* BW_20_40_80M 23270* BW_20_40_80_160M 33271* BW_20_40_80_8080M 43272*/3273u8 bw_5g;3274u8 bw_6g;3275u8 pad;3276} __packed hdr;3277struct n_chan {3278__le16 tag;3279__le16 len;3280u8 n_2ch;3281u8 n_5ch;3282u8 n_6ch;3283u8 pad;3284} __packed n_ch;3285} req = {3286.hdr = {3287.bw_2g = 0,3288.bw_5g = 3, /* BW_20_40_80_160M */3289.bw_6g = 3,3290},3291.n_ch = {3292.tag = cpu_to_le16(2),3293},3294};3295struct mt76_connac_mcu_chan {3296__le16 hw_value;3297__le16 pad;3298__le32 flags;3299} __packed channel;3300struct mt76_dev *dev = phy->dev;3301struct ieee80211_channel *chan;3302struct sk_buff *skb;33033304n_max_channels = phy->sband_2g.sband.n_channels +3305phy->sband_5g.sband.n_channels +3306phy->sband_6g.sband.n_channels;3307len = sizeof(req) + n_max_channels * sizeof(channel);33083309skb = mt76_mcu_msg_alloc(dev, NULL, len);3310if (!skb)3311return -ENOMEM;33123313skb_reserve(skb, sizeof(req));33143315for (i = 0; i < phy->sband_2g.sband.n_channels; i++) {3316chan = &phy->sband_2g.sband.channels[i];3317if (chan->flags & IEEE80211_CHAN_DISABLED)3318continue;33193320channel.hw_value = cpu_to_le16(chan->hw_value);3321channel.flags = cpu_to_le32(chan->flags);3322channel.pad = 0;33233324skb_put_data(skb, &channel, sizeof(channel));3325n_2ch++;3326}3327for (i = 0; i < phy->sband_5g.sband.n_channels; i++) {3328chan = &phy->sband_5g.sband.channels[i];3329if (chan->flags & IEEE80211_CHAN_DISABLED)3330continue;33313332channel.hw_value = cpu_to_le16(chan->hw_value);3333channel.flags = cpu_to_le32(chan->flags);3334channel.pad = 0;33353336skb_put_data(skb, &channel, sizeof(channel));3337n_5ch++;3338}3339for (i = 0; i < phy->sband_6g.sband.n_channels; i++) {3340chan = &phy->sband_6g.sband.channels[i];3341if (chan->flags & IEEE80211_CHAN_DISABLED)3342continue;33433344channel.hw_value = cpu_to_le16(chan->hw_value);3345channel.flags = cpu_to_le32(chan->flags);3346channel.pad = 0;33473348skb_put_data(skb, &channel, sizeof(channel));3349n_6ch++;3350}33513352BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(req.hdr.alpha2));3353memcpy(req.hdr.alpha2, dev->alpha2, sizeof(dev->alpha2));3354req.n_ch.n_2ch = n_2ch;3355req.n_ch.n_5ch = n_5ch;3356req.n_ch.n_6ch = n_6ch;3357len = sizeof(struct n_chan) + (n_2ch + n_5ch + n_6ch) * sizeof(channel);3358req.n_ch.len = cpu_to_le16(len);3359memcpy(__skb_push(skb, sizeof(req)), &req, sizeof(req));33603361return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SET_DOMAIN_INFO),3362true);3363}3364EXPORT_SYMBOL_GPL(mt7925_mcu_set_channel_domain);33653366static int3367__mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,3368enum environment_cap env_cap,3369struct mt7925_clc *clc, u8 idx)3370{3371struct mt7925_clc_segment *seg;3372struct sk_buff *skb;3373struct {3374u8 rsv[4];3375__le16 tag;3376__le16 len;33773378u8 ver;3379u8 pad0;3380__le16 size;3381u8 idx;3382u8 env;3383u8 acpi_conf;3384u8 pad1;3385u8 alpha2[2];3386u8 type[2];3387u8 rsvd[64];3388} __packed req = {3389.tag = cpu_to_le16(0x3),3390.len = cpu_to_le16(sizeof(req) - 4),33913392.idx = idx,3393.env = env_cap,3394};3395int ret, valid_cnt = 0;3396u8 *pos, *last_pos;33973398if (!clc)3399return 0;34003401req.ver = clc->ver;3402pos = clc->data + sizeof(*seg) * clc->t0.nr_seg;3403last_pos = clc->data + le32_to_cpu(*(__le32 *)(clc->data + 4));3404while (pos < last_pos) {3405struct mt7925_clc_rule *rule = (struct mt7925_clc_rule *)pos;34063407pos += sizeof(*rule);3408if (rule->alpha2[0] != alpha2[0] ||3409rule->alpha2[1] != alpha2[1])3410continue;34113412seg = (struct mt7925_clc_segment *)clc->data3413+ rule->seg_idx - 1;34143415memcpy(req.alpha2, rule->alpha2, 2);3416memcpy(req.type, rule->type, 2);34173418req.size = cpu_to_le16(seg->len);3419dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag;3420skb = __mt76_mcu_msg_alloc(&dev->mt76, &req,3421le16_to_cpu(req.size) + sizeof(req),3422sizeof(req), GFP_KERNEL);3423if (!skb)3424return -ENOMEM;3425skb_put_data(skb, clc->data + seg->offset, seg->len);34263427ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,3428MCU_UNI_CMD(SET_POWER_LIMIT),3429true);3430if (ret < 0)3431return ret;3432valid_cnt++;3433}34343435if (!valid_cnt) {3436dev->phy.clc_chan_conf = 0xff;3437return -ENOENT;3438}34393440return 0;3441}34423443int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,3444enum environment_cap env_cap)3445{3446struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy;3447int i, ret;34483449if (!ARRAY_SIZE(phy->clc))3450return -ESRCH;34513452/* submit all clc config */3453for (i = 0; i < ARRAY_SIZE(phy->clc); i++) {3454if (i == MT792x_CLC_BE_CTRL)3455continue;34563457ret = __mt7925_mcu_set_clc(dev, alpha2, env_cap,3458phy->clc[i], i);34593460/* If no country found, set "00" as default */3461if (ret == -ENOENT)3462ret = __mt7925_mcu_set_clc(dev, "00",3463ENVIRON_INDOOR,3464phy->clc[i], i);3465if (ret < 0)3466return ret;3467}3468return 0;3469}34703471int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb,3472int cmd, int *wait_seq)3473{3474int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);3475struct mt76_connac2_mcu_uni_txd *uni_txd;3476struct mt76_connac2_mcu_txd *mcu_txd;3477__le32 *txd;3478u32 val;3479u8 seq;34803481/* TODO: make dynamic based on msg type */3482mdev->mcu.timeout = 20 * HZ;34833484seq = ++mdev->mcu.msg_seq & 0xf;3485if (!seq)3486seq = ++mdev->mcu.msg_seq & 0xf;34873488if (cmd == MCU_CMD(FW_SCATTER))3489goto exit;34903491txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);3492txd = (__le32 *)skb_push(skb, txd_len);34933494val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |3495FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) |3496FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0);3497txd[0] = cpu_to_le32(val);34983499val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD);3500txd[1] = cpu_to_le32(val);35013502if (cmd & __MCU_CMD_FIELD_UNI) {3503uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd;3504uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));3505uni_txd->cid = cpu_to_le16(mcu_cmd);3506uni_txd->s2d_index = MCU_S2D_H2N;3507uni_txd->pkt_type = MCU_PKT_ID;3508uni_txd->seq = seq;35093510if (cmd & __MCU_CMD_FIELD_QUERY)3511uni_txd->option = MCU_CMD_UNI_QUERY_ACK;3512else3513uni_txd->option = MCU_CMD_UNI_EXT_ACK;35143515if (cmd == MCU_UNI_CMD(HIF_CTRL) ||3516cmd == MCU_UNI_CMD(CHIP_CONFIG))3517uni_txd->option &= ~MCU_CMD_ACK;35183519if (mcu_cmd == MCU_UNI_CMD_TESTMODE_CTRL ||3520mcu_cmd == MCU_UNI_CMD_TESTMODE_RX_STAT) {3521if (cmd & __MCU_CMD_FIELD_QUERY)3522uni_txd->option = 0x2;3523else3524uni_txd->option = 0x6;3525}35263527goto exit;3528}35293530mcu_txd = (struct mt76_connac2_mcu_txd *)txd;3531mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));3532mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU,3533MT_TX_MCU_PORT_RX_Q0));3534mcu_txd->pkt_type = MCU_PKT_ID;3535mcu_txd->seq = seq;3536mcu_txd->cid = mcu_cmd;3537mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);35383539if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {3540if (cmd & __MCU_CMD_FIELD_QUERY)3541mcu_txd->set_query = MCU_Q_QUERY;3542else3543mcu_txd->set_query = MCU_Q_SET;3544mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;3545} else {3546mcu_txd->set_query = MCU_Q_NA;3547}35483549if (cmd & __MCU_CMD_FIELD_WA)3550mcu_txd->s2d_index = MCU_S2D_H2C;3551else3552mcu_txd->s2d_index = MCU_S2D_H2N;35533554exit:3555if (wait_seq)3556*wait_seq = seq;35573558return 0;3559}3560EXPORT_SYMBOL_GPL(mt7925_mcu_fill_message);35613562int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val)3563{3564struct {3565u8 band_idx;3566u8 _rsv[3];35673568__le16 tag;3569__le16 len;3570__le32 len_thresh;3571__le32 pkt_thresh;3572} __packed req = {3573.band_idx = phy->mt76->band_idx,3574.tag = cpu_to_le16(UNI_BAND_CONFIG_RTS_THRESHOLD),3575.len = cpu_to_le16(sizeof(req) - 4),3576.len_thresh = cpu_to_le32(val),3577.pkt_thresh = cpu_to_le32(0x2),3578};35793580return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG),3581&req, sizeof(req), true);3582}35833584int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable)3585{3586struct {3587u8 band_idx;3588u8 _rsv[3];35893590__le16 tag;3591__le16 len;3592u8 enable;3593u8 _rsv2[3];3594} __packed req = {3595.band_idx = phy->mt76->band_idx,3596.tag = cpu_to_le16(UNI_BAND_CONFIG_RADIO_ENABLE),3597.len = cpu_to_le16(sizeof(req) - 4),3598.enable = enable,3599};36003601return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG),3602&req, sizeof(req), true);3603}36043605static void3606mt7925_mcu_build_sku(struct mt76_dev *dev, s8 *sku,3607struct mt76_power_limits *limits,3608enum nl80211_band band)3609{3610int i, offset = sizeof(limits->cck);36113612memset(sku, 127, MT_CONNAC3_SKU_POWER_LIMIT);36133614if (band == NL80211_BAND_2GHZ) {3615/* cck */3616memcpy(sku, limits->cck, sizeof(limits->cck));3617}36183619/* ofdm */3620memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm));3621offset += (sizeof(limits->ofdm) * 5);36223623/* ht */3624for (i = 0; i < 2; i++) {3625memcpy(&sku[offset], limits->mcs[i], 8);3626offset += 8;3627}3628sku[offset++] = limits->mcs[0][0];36293630/* vht */3631for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) {3632memcpy(&sku[offset], limits->mcs[i],3633ARRAY_SIZE(limits->mcs[i]));3634offset += 12;3635}36363637/* he */3638for (i = 0; i < ARRAY_SIZE(limits->ru); i++) {3639memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i]));3640offset += ARRAY_SIZE(limits->ru[i]);3641}36423643/* eht */3644for (i = 0; i < ARRAY_SIZE(limits->eht); i++) {3645memcpy(&sku[offset], limits->eht[i], ARRAY_SIZE(limits->eht[i]));3646offset += ARRAY_SIZE(limits->eht[i]);3647}3648}36493650static int3651mt7925_mcu_rate_txpower_band(struct mt76_phy *phy,3652enum nl80211_band band)3653{3654int tx_power, n_chan, last_ch, err = 0, idx = 0;3655int i, sku_len, batch_size, batch_len = 3;3656struct mt76_dev *dev = phy->dev;3657static const u8 chan_list_2ghz[] = {36581, 2, 3, 4, 5, 6, 7,36598, 9, 10, 11, 12, 13, 143660};3661static const u8 chan_list_5ghz[] = {366236, 38, 40, 42, 44, 46, 48,366350, 52, 54, 56, 58, 60, 62,366464, 100, 102, 104, 106, 108, 110,3665112, 114, 116, 118, 120, 122, 124,3666126, 128, 132, 134, 136, 138, 140,3667142, 144, 149, 151, 153, 155, 157,3668159, 161, 165, 1673669};3670static const u8 chan_list_6ghz[] = {36711, 3, 5, 7, 9, 11, 13,367215, 17, 19, 21, 23, 25, 27,367329, 33, 35, 37, 39, 41, 43,367445, 47, 49, 51, 53, 55, 57,367559, 61, 65, 67, 69, 71, 73,367675, 77, 79, 81, 83, 85, 87,367789, 91, 93, 97, 99, 101, 103,3678105, 107, 109, 111, 113, 115, 117,3679119, 121, 123, 125, 129, 131, 133,3680135, 137, 139, 141, 143, 145, 147,3681149, 151, 153, 155, 157, 161, 163,3682165, 167, 169, 171, 173, 175, 177,3683179, 181, 183, 185, 187, 189, 193,3684195, 197, 199, 201, 203, 205, 207,3685209, 211, 213, 215, 217, 219, 221,3686225, 227, 229, 2333687};3688struct mt76_power_limits *limits;3689struct mt7925_sku_tlv *sku_tlbv;3690const u8 *ch_list;36913692sku_len = sizeof(*sku_tlbv);3693tx_power = 2 * phy->hw->conf.power_level;3694if (!tx_power)3695tx_power = 127;36963697if (band == NL80211_BAND_2GHZ) {3698n_chan = ARRAY_SIZE(chan_list_2ghz);3699ch_list = chan_list_2ghz;3700last_ch = chan_list_2ghz[ARRAY_SIZE(chan_list_2ghz) - 1];3701} else if (band == NL80211_BAND_6GHZ) {3702n_chan = ARRAY_SIZE(chan_list_6ghz);3703ch_list = chan_list_6ghz;3704last_ch = chan_list_6ghz[ARRAY_SIZE(chan_list_6ghz) - 1];3705} else {3706n_chan = ARRAY_SIZE(chan_list_5ghz);3707ch_list = chan_list_5ghz;3708last_ch = chan_list_5ghz[ARRAY_SIZE(chan_list_5ghz) - 1];3709}3710batch_size = DIV_ROUND_UP(n_chan, batch_len);37113712limits = devm_kmalloc(dev->dev, sizeof(*limits), GFP_KERNEL);3713if (!limits)3714return -ENOMEM;37153716sku_tlbv = devm_kmalloc(dev->dev, sku_len, GFP_KERNEL);3717if (!sku_tlbv) {3718devm_kfree(dev->dev, limits);3719return -ENOMEM;3720}37213722for (i = 0; i < batch_size; i++) {3723struct mt7925_tx_power_limit_tlv *tx_power_tlv;3724int j, msg_len, num_ch;3725struct sk_buff *skb;37263727num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len;3728msg_len = sizeof(*tx_power_tlv) + num_ch * sku_len;3729skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);3730if (!skb) {3731err = -ENOMEM;3732goto out;3733}37343735tx_power_tlv = (struct mt7925_tx_power_limit_tlv *)3736skb_put(skb, sizeof(*tx_power_tlv));37373738BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv->alpha2));3739memcpy(tx_power_tlv->alpha2, dev->alpha2, sizeof(dev->alpha2));3740tx_power_tlv->n_chan = num_ch;3741tx_power_tlv->tag = cpu_to_le16(0x1);3742tx_power_tlv->len = cpu_to_le16(sizeof(*tx_power_tlv));37433744switch (band) {3745case NL80211_BAND_2GHZ:3746tx_power_tlv->band = 1;3747break;3748case NL80211_BAND_6GHZ:3749tx_power_tlv->band = 3;3750break;3751default:3752tx_power_tlv->band = 2;3753break;3754}37553756for (j = 0; j < num_ch; j++, idx++) {3757struct ieee80211_channel chan = {3758.hw_value = ch_list[idx],3759.band = band,3760};3761s8 reg_power, sar_power;37623763reg_power = mt76_connac_get_ch_power(phy, &chan,3764tx_power);3765sar_power = mt76_get_sar_power(phy, &chan, reg_power);37663767mt76_get_rate_power_limits(phy, &chan, limits,3768sar_power);37693770tx_power_tlv->last_msg = ch_list[idx] == last_ch;3771sku_tlbv->channel = ch_list[idx];37723773mt7925_mcu_build_sku(dev, sku_tlbv->pwr_limit,3774limits, band);3775skb_put_data(skb, sku_tlbv, sku_len);3776}3777err = mt76_mcu_skb_send_msg(dev, skb,3778MCU_UNI_CMD(SET_POWER_LIMIT),3779true);3780if (err < 0)3781goto out;3782}37833784out:3785devm_kfree(dev->dev, sku_tlbv);3786devm_kfree(dev->dev, limits);3787return err;3788}37893790int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy)3791{3792struct mt76_dev *mdev = phy->dev;3793struct mt792x_dev *dev = mt792x_hw_dev(mdev->hw);3794int err;37953796if (phy->cap.has_2ghz) {3797err = mt7925_mcu_rate_txpower_band(phy,3798NL80211_BAND_2GHZ);3799if (err < 0)3800return err;3801}38023803if (phy->cap.has_5ghz) {3804err = mt7925_mcu_rate_txpower_band(phy,3805NL80211_BAND_5GHZ);3806if (err < 0)3807return err;3808}38093810if (phy->cap.has_6ghz && dev->phy.clc_chan_conf) {3811err = mt7925_mcu_rate_txpower_band(phy,3812NL80211_BAND_6GHZ);3813if (err < 0)3814return err;3815}38163817return 0;3818}38193820int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy)3821{3822#define UNI_CMD_RADIO_STATUS_GET 03823struct mt792x_dev *dev = phy->dev;3824struct sk_buff *skb;3825int ret;3826struct {3827__le16 tag;3828__le16 len;3829u8 rsv[4];3830} __packed req = {3831.tag = UNI_CMD_RADIO_STATUS_GET,3832.len = cpu_to_le16(sizeof(req)),3833};3834struct mt7925_radio_status_event {3835__le16 tag;3836__le16 len;38373838u8 data;3839u8 rsv[3];3840} __packed *status;38413842ret = mt76_mcu_send_and_get_msg(&dev->mt76,3843MCU_UNI_CMD(RADIO_STATUS),3844&req, sizeof(req), true, &skb);3845if (ret)3846return ret;38473848skb_pull(skb, sizeof(struct tlv));3849status = (struct mt7925_radio_status_event *)skb->data;3850ret = status->data;38513852dev_kfree_skb(skb);38533854return ret;3855}38563857int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,3858u8 bit_op, u32 bit_map)3859{3860struct mt792x_phy *phy = &dev->phy;3861struct {3862u8 band_idx;3863u8 rsv1[3];38643865__le16 tag;3866__le16 len;3867u8 mode;3868u8 rsv2[3];3869__le32 fif;3870__le32 bit_map; /* bit_* for bitmap update */3871u8 bit_op;3872u8 pad[51];3873} __packed req = {3874.band_idx = phy->mt76->band_idx,3875.tag = cpu_to_le16(UNI_BAND_CONFIG_SET_MAC80211_RX_FILTER),3876.len = cpu_to_le16(sizeof(req) - 4),38773878.mode = fif ? 0 : 1,3879.fif = cpu_to_le32(fif),3880.bit_map = cpu_to_le32(bit_map),3881.bit_op = bit_op,3882};38833884return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG),3885&req, sizeof(req), true);3886}38873888int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif)3889{3890struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(&vif->bss_conf);3891struct {3892struct {3893u8 bss_idx;3894u8 pad[3];3895} __packed hdr;3896__le16 tag;3897__le16 len;3898u8 enable;3899s8 cqm_rssi_high;3900s8 cqm_rssi_low;3901u8 rsv;3902} req = {3903.hdr = {3904.bss_idx = mconf->mt76.idx,3905},3906.tag = cpu_to_le16(UNI_CMD_RSSI_MONITOR_SET),3907.len = cpu_to_le16(sizeof(req) - 4),3908.enable = vif->cfg.assoc,3909.cqm_rssi_high = (s8)(vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst),3910.cqm_rssi_low = (s8)(vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst),3911};39123913return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RSSI_MONITOR), &req,3914sizeof(req), false);3915}391639173918