Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c
109069 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/* Copyright (C) 2020 MediaTek Inc. */23#include <linux/firmware.h>4#include "mt76_connac2_mac.h"5#include "mt76_connac_mcu.h"67int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option)8{9struct {10__le32 option;11__le32 addr;12} req = {13.option = cpu_to_le32(option),14.addr = cpu_to_le32(addr),15};1617return mt76_mcu_send_msg(dev, MCU_CMD(FW_START_REQ), &req,18sizeof(req), true);19}20EXPORT_SYMBOL_GPL(mt76_connac_mcu_start_firmware);2122int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get)23{24u32 op = get ? PATCH_SEM_GET : PATCH_SEM_RELEASE;25struct {26__le32 op;27} req = {28.op = cpu_to_le32(op),29};3031return mt76_mcu_send_msg(dev, MCU_CMD(PATCH_SEM_CONTROL),32&req, sizeof(req), true);33}34EXPORT_SYMBOL_GPL(mt76_connac_mcu_patch_sem_ctrl);3536int mt76_connac_mcu_start_patch(struct mt76_dev *dev)37{38struct {39u8 check_crc;40u8 reserved[3];41} req = {42.check_crc = 0,43};4445return mt76_mcu_send_msg(dev, MCU_CMD(PATCH_FINISH_REQ),46&req, sizeof(req), true);47}48EXPORT_SYMBOL_GPL(mt76_connac_mcu_start_patch);4950#define MCU_PATCH_ADDRESS 0x2000005152int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len,53u32 mode)54{55struct {56__le32 addr;57__le32 len;58__le32 mode;59} req = {60.addr = cpu_to_le32(addr),61.len = cpu_to_le32(len),62.mode = cpu_to_le32(mode),63};64int cmd;6566if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) ||67(is_mt7921(dev) && addr == 0x900000) ||68(is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) ||69(is_mt799x(dev) && addr == 0x900000))70cmd = MCU_CMD(PATCH_START_REQ);71else72cmd = MCU_CMD(TARGET_ADDRESS_LEN_REQ);7374return mt76_mcu_send_msg(dev, cmd, &req, sizeof(req), true);75}76EXPORT_SYMBOL_GPL(mt76_connac_mcu_init_download);7778int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy)79{80int len, i, n_max_channels, n_2ch = 0, n_5ch = 0, n_6ch = 0;81struct mt76_connac_mcu_channel_domain {82u8 alpha2[4]; /* regulatory_request.alpha2 */83u8 bw_2g; /* BW_20_40M 084* BW_20M 185* BW_20_40_80M 286* BW_20_40_80_160M 387* BW_20_40_80_8080M 488*/89u8 bw_5g;90u8 bw_6g;91u8 pad;92u8 n_2ch;93u8 n_5ch;94u8 n_6ch;95u8 pad2;96} __packed hdr = {97.bw_2g = 0,98.bw_5g = 3, /* BW_20_40_80_160M */99.bw_6g = 3,100};101struct mt76_connac_mcu_chan {102__le16 hw_value;103__le16 pad;104__le32 flags;105} __packed channel;106struct mt76_dev *dev = phy->dev;107struct ieee80211_channel *chan;108struct sk_buff *skb;109110n_max_channels = phy->sband_2g.sband.n_channels +111phy->sband_5g.sband.n_channels +112phy->sband_6g.sband.n_channels;113len = sizeof(hdr) + n_max_channels * sizeof(channel);114115skb = mt76_mcu_msg_alloc(dev, NULL, len);116if (!skb)117return -ENOMEM;118119skb_reserve(skb, sizeof(hdr));120121for (i = 0; i < phy->sband_2g.sband.n_channels; i++) {122chan = &phy->sband_2g.sband.channels[i];123if (chan->flags & IEEE80211_CHAN_DISABLED)124continue;125126channel.hw_value = cpu_to_le16(chan->hw_value);127channel.flags = cpu_to_le32(chan->flags);128channel.pad = 0;129130skb_put_data(skb, &channel, sizeof(channel));131n_2ch++;132}133for (i = 0; i < phy->sband_5g.sband.n_channels; i++) {134chan = &phy->sband_5g.sband.channels[i];135if (chan->flags & IEEE80211_CHAN_DISABLED)136continue;137138channel.hw_value = cpu_to_le16(chan->hw_value);139channel.flags = cpu_to_le32(chan->flags);140channel.pad = 0;141142skb_put_data(skb, &channel, sizeof(channel));143n_5ch++;144}145for (i = 0; i < phy->sband_6g.sband.n_channels; i++) {146chan = &phy->sband_6g.sband.channels[i];147if (chan->flags & IEEE80211_CHAN_DISABLED)148continue;149150channel.hw_value = cpu_to_le16(chan->hw_value);151channel.flags = cpu_to_le32(chan->flags);152channel.pad = 0;153154skb_put_data(skb, &channel, sizeof(channel));155n_6ch++;156}157158BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(hdr.alpha2));159memcpy(hdr.alpha2, dev->alpha2, sizeof(dev->alpha2));160hdr.n_2ch = n_2ch;161hdr.n_5ch = n_5ch;162hdr.n_6ch = n_6ch;163164memcpy(__skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));165166return mt76_mcu_skb_send_msg(dev, skb, MCU_CE_CMD(SET_CHAN_DOMAIN),167false);168}169EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_channel_domain);170171int mt76_connac_mcu_set_mac_enable(struct mt76_dev *dev, int band, bool enable,172bool hdr_trans)173{174struct {175u8 enable;176u8 band;177u8 rsv[2];178} __packed req_mac = {179.enable = enable,180.band = band,181};182183return mt76_mcu_send_msg(dev, MCU_EXT_CMD(MAC_INIT_CTRL), &req_mac,184sizeof(req_mac), true);185}186EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_mac_enable);187188int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif)189{190struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;191struct {192u8 bss_idx;193u8 ps_state; /* 0: device awake194* 1: static power save195* 2: dynamic power saving196*/197} req = {198.bss_idx = mvif->idx,199.ps_state = vif->cfg.ps ? 2 : 0,200};201202if (vif->type != NL80211_IFTYPE_STATION)203return -EOPNOTSUPP;204205return mt76_mcu_send_msg(dev, MCU_CE_CMD(SET_PS_PROFILE),206&req, sizeof(req), false);207}208EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_vif_ps);209210int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band)211{212struct {213u8 prot_idx;214u8 band;215u8 rsv[2];216__le32 len_thresh;217__le32 pkt_thresh;218} __packed req = {219.prot_idx = 1,220.band = band,221.len_thresh = cpu_to_le32(val),222.pkt_thresh = cpu_to_le32(0x2),223};224225return mt76_mcu_send_msg(dev, MCU_EXT_CMD(PROTECT_CTRL), &req,226sizeof(req), true);227}228EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rts_thresh);229230void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac,231struct ieee80211_vif *vif)232{233struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;234struct mt76_connac_beacon_loss_event *event = priv;235236if (mvif->idx != event->bss_idx)237return;238239if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))240return;241242ieee80211_beacon_loss(vif);243}244EXPORT_SYMBOL_GPL(mt76_connac_mcu_beacon_loss_iter);245246struct tlv *247mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len,248void *sta_ntlv, void *sta_wtbl)249{250struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv;251struct tlv *sta_hdr = sta_wtbl;252struct tlv *ptlv, tlv = {253.tag = cpu_to_le16(tag),254.len = cpu_to_le16(len),255};256u16 ntlv;257258ptlv = skb_put_zero(skb, len);259memcpy(ptlv, &tlv, sizeof(tlv));260261ntlv = le16_to_cpu(ntlv_hdr->tlv_num);262ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1);263264if (sta_hdr) {265len += le16_to_cpu(sta_hdr->len);266sta_hdr->len = cpu_to_le16(len);267}268269return ptlv;270}271EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_nested_tlv);272273struct sk_buff *274__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif,275struct mt76_wcid *wcid, int len)276{277struct sta_req_hdr hdr = {278.bss_idx = mvif->idx,279.muar_idx = wcid ? mvif->omac_idx : 0,280.is_tlv_append = 1,281};282struct sk_buff *skb;283284if (wcid && !wcid->sta && !wcid->sta_disabled)285hdr.muar_idx = 0xe;286287mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo,288&hdr.wlan_idx_hi);289skb = __mt76_mcu_msg_alloc(dev, NULL, len, len, GFP_ATOMIC);290if (!skb)291return ERR_PTR(-ENOMEM);292293skb_put_data(skb, &hdr, sizeof(hdr));294295return skb;296}297EXPORT_SYMBOL_GPL(__mt76_connac_mcu_alloc_sta_req);298299struct wtbl_req_hdr *300mt76_connac_mcu_alloc_wtbl_req(struct mt76_dev *dev, struct mt76_wcid *wcid,301int cmd, void *sta_wtbl, struct sk_buff **skb)302{303struct tlv *sta_hdr = sta_wtbl;304struct wtbl_req_hdr hdr = {305.operation = cmd,306};307struct sk_buff *nskb = *skb;308309mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo,310&hdr.wlan_idx_hi);311if (!nskb) {312nskb = mt76_mcu_msg_alloc(dev, NULL,313MT76_CONNAC_WTBL_UPDATE_MAX_SIZE);314if (!nskb)315return ERR_PTR(-ENOMEM);316317*skb = nskb;318}319320if (sta_hdr)321le16_add_cpu(&sta_hdr->len, sizeof(hdr));322323return skb_put_data(nskb, &hdr, sizeof(hdr));324}325EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req);326327void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb,328struct ieee80211_vif *vif)329{330struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;331u8 omac_idx = mvif->omac_idx;332struct bss_info_omac *omac;333struct tlv *tlv;334u32 type = 0;335336switch (vif->type) {337case NL80211_IFTYPE_MONITOR:338case NL80211_IFTYPE_MESH_POINT:339case NL80211_IFTYPE_AP:340if (vif->p2p)341type = CONNECTION_P2P_GO;342else343type = CONNECTION_INFRA_AP;344break;345case NL80211_IFTYPE_STATION:346if (vif->p2p)347type = CONNECTION_P2P_GC;348else349type = CONNECTION_INFRA_STA;350break;351case NL80211_IFTYPE_ADHOC:352type = CONNECTION_IBSS_ADHOC;353break;354default:355WARN_ON(1);356break;357}358359tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac));360361omac = (struct bss_info_omac *)tlv;362omac->conn_type = cpu_to_le32(type);363omac->omac_idx = mvif->omac_idx;364omac->band_idx = mvif->band_idx;365omac->hw_bss_idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx;366}367EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv);368369void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,370struct ieee80211_bss_conf *link_conf,371struct ieee80211_link_sta *link_sta,372int conn_state, bool newly)373{374struct ieee80211_vif *vif = link_conf->vif;375struct sta_rec_basic *basic;376struct tlv *tlv;377int conn_type;378379tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic));380381basic = (struct sta_rec_basic *)tlv;382basic->extra_info = cpu_to_le16(EXTRA_INFO_VER);383384if (newly && conn_state != CONN_STATE_DISCONNECT)385basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);386basic->conn_state = conn_state;387388if (!link_sta) {389basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC);390391if (vif->type == NL80211_IFTYPE_STATION &&392!is_zero_ether_addr(link_conf->bssid)) {393memcpy(basic->peer_addr, link_conf->bssid, ETH_ALEN);394basic->aid = cpu_to_le16(vif->cfg.aid);395} else {396eth_broadcast_addr(basic->peer_addr);397}398return;399}400401switch (vif->type) {402case NL80211_IFTYPE_MESH_POINT:403case NL80211_IFTYPE_AP:404if (vif->p2p && !is_mt7921(dev))405conn_type = CONNECTION_P2P_GC;406else407conn_type = CONNECTION_INFRA_STA;408basic->conn_type = cpu_to_le32(conn_type);409basic->aid = cpu_to_le16(link_sta->sta->aid);410break;411case NL80211_IFTYPE_STATION:412if (vif->p2p && !is_mt7921(dev))413conn_type = CONNECTION_P2P_GO;414else415conn_type = CONNECTION_INFRA_AP;416basic->conn_type = cpu_to_le32(conn_type);417basic->aid = cpu_to_le16(vif->cfg.aid);418break;419case NL80211_IFTYPE_ADHOC:420basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);421basic->aid = cpu_to_le16(link_sta->sta->aid);422break;423default:424WARN_ON(1);425break;426}427428memcpy(basic->peer_addr, link_sta->addr, ETH_ALEN);429basic->qos = link_sta->sta->wme;430}431EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_basic_tlv);432433void mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif,434struct ieee80211_sta *sta)435{436struct sta_rec_uapsd *uapsd;437struct tlv *tlv;438439if (vif->type != NL80211_IFTYPE_AP || !sta->wme)440return;441442tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd));443uapsd = (struct sta_rec_uapsd *)tlv;444445if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) {446uapsd->dac_map |= BIT(3);447uapsd->tac_map |= BIT(3);448}449if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) {450uapsd->dac_map |= BIT(2);451uapsd->tac_map |= BIT(2);452}453if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) {454uapsd->dac_map |= BIT(1);455uapsd->tac_map |= BIT(1);456}457if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) {458uapsd->dac_map |= BIT(0);459uapsd->tac_map |= BIT(0);460}461uapsd->max_sp = sta->max_sp;462}463EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_uapsd);464465void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,466struct ieee80211_vif *vif,467struct mt76_wcid *wcid,468void *sta_wtbl, void *wtbl_tlv)469{470struct wtbl_hdr_trans *htr;471struct tlv *tlv;472473tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HDR_TRANS,474sizeof(*htr),475wtbl_tlv, sta_wtbl);476htr = (struct wtbl_hdr_trans *)tlv;477htr->no_rx_trans = true;478479if (vif->type == NL80211_IFTYPE_STATION)480htr->to_ds = true;481else482htr->from_ds = true;483484if (!wcid)485return;486487htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);488if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {489htr->to_ds = true;490htr->from_ds = true;491}492}493EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv);494495int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev,496struct ieee80211_vif *vif,497struct mt76_wcid *wcid, int cmd)498{499struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;500struct wtbl_req_hdr *wtbl_hdr;501struct tlv *sta_wtbl;502struct sk_buff *skb;503504skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);505if (IS_ERR(skb))506return PTR_ERR(skb);507508sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,509sizeof(struct tlv));510511wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET,512sta_wtbl, &skb);513if (IS_ERR(wtbl_hdr))514return PTR_ERR(wtbl_hdr);515516mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, sta_wtbl, wtbl_hdr);517518return mt76_mcu_skb_send_msg(dev, skb, cmd, true);519}520EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_update_hdr_trans);521522int mt76_connac_mcu_wtbl_update_hdr_trans(struct mt76_dev *dev,523struct ieee80211_vif *vif,524struct ieee80211_sta *sta)525{526struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;527struct wtbl_req_hdr *wtbl_hdr;528struct sk_buff *skb = NULL;529530wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET, NULL,531&skb);532if (IS_ERR(wtbl_hdr))533return PTR_ERR(wtbl_hdr);534535mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, NULL, wtbl_hdr);536537return mt76_mcu_skb_send_msg(dev, skb, MCU_EXT_CMD(WTBL_UPDATE), true);538}539EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_update_hdr_trans);540541void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev,542struct sk_buff *skb,543struct ieee80211_vif *vif,544struct ieee80211_sta *sta,545void *sta_wtbl, void *wtbl_tlv)546{547struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;548struct wtbl_generic *generic;549struct wtbl_rx *rx;550struct wtbl_spe *spe;551struct tlv *tlv;552553tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_GENERIC,554sizeof(*generic),555wtbl_tlv, sta_wtbl);556557generic = (struct wtbl_generic *)tlv;558559if (sta) {560if (vif->type == NL80211_IFTYPE_STATION)561generic->partial_aid = cpu_to_le16(vif->cfg.aid);562else563generic->partial_aid = cpu_to_le16(sta->aid);564memcpy(generic->peer_addr, sta->addr, ETH_ALEN);565generic->muar_idx = mvif->omac_idx;566generic->qos = sta->wme;567} else {568if (!is_connac_v1(dev) && vif->type == NL80211_IFTYPE_STATION)569memcpy(generic->peer_addr, vif->bss_conf.bssid,570ETH_ALEN);571else572eth_broadcast_addr(generic->peer_addr);573574generic->muar_idx = 0xe;575}576577tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx),578wtbl_tlv, sta_wtbl);579580rx = (struct wtbl_rx *)tlv;581rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1;582rx->rca2 = 1;583rx->rv = 1;584585if (!is_connac_v1(dev))586return;587588tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe),589wtbl_tlv, sta_wtbl);590spe = (struct wtbl_spe *)tlv;591spe->spe_idx = 24;592}593EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_generic_tlv);594595static void596mt76_connac_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,597struct ieee80211_vif *vif)598{599struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;600struct sta_rec_amsdu *amsdu;601struct tlv *tlv;602603if (vif->type != NL80211_IFTYPE_AP &&604vif->type != NL80211_IFTYPE_STATION)605return;606607if (!sta->deflink.agg.max_amsdu_len)608return;609610tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));611amsdu = (struct sta_rec_amsdu *)tlv;612amsdu->max_amsdu_num = 8;613amsdu->amsdu_en = true;614amsdu->max_mpdu_size = sta->deflink.agg.max_amsdu_len >=615IEEE80211_MAX_MPDU_LEN_VHT_7991;616617wcid->amsdu = true;618}619620#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p)621#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m)622static void623mt76_connac_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)624{625struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;626struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;627struct sta_rec_he *he;628struct tlv *tlv;629u32 cap = 0;630631tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));632633he = (struct sta_rec_he *)tlv;634635if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)636cap |= STA_REC_HE_CAP_HTC;637638if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)639cap |= STA_REC_HE_CAP_BSR;640641if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)642cap |= STA_REC_HE_CAP_OM;643644if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU)645cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU;646647if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)648cap |= STA_REC_HE_CAP_BQR;649650if (elem->phy_cap_info[0] &651(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G |652IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))653cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;654655if (elem->phy_cap_info[1] &656IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)657cap |= STA_REC_HE_CAP_LDPC;658659if (elem->phy_cap_info[1] &660IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US)661cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI;662663if (elem->phy_cap_info[2] &664IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US)665cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI;666667if (elem->phy_cap_info[2] &668IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ)669cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC;670671if (elem->phy_cap_info[2] &672IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)673cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;674675if (elem->phy_cap_info[6] &676IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)677cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;678679if (elem->phy_cap_info[7] &680IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI)681cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI;682683if (elem->phy_cap_info[7] &684IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ)685cap |= STA_REC_HE_CAP_GT_80M_TX_STBC;686687if (elem->phy_cap_info[7] &688IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)689cap |= STA_REC_HE_CAP_GT_80M_RX_STBC;690691if (elem->phy_cap_info[8] &692IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI)693cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI;694695if (elem->phy_cap_info[8] &696IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI)697cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;698699if (elem->phy_cap_info[9] &700IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK)701cap |= STA_REC_HE_CAP_TRIG_CQI_FK;702703if (elem->phy_cap_info[9] &704IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)705cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;706707if (elem->phy_cap_info[9] &708IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU)709cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242;710711he->he_cap = cpu_to_le32(cap);712713switch (sta->deflink.bandwidth) {714case IEEE80211_STA_RX_BW_160:715if (elem->phy_cap_info[0] &716IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)717he->max_nss_mcs[CMD_HE_MCS_BW8080] =718he_cap->he_mcs_nss_supp.rx_mcs_80p80;719720he->max_nss_mcs[CMD_HE_MCS_BW160] =721he_cap->he_mcs_nss_supp.rx_mcs_160;722fallthrough;723default:724he->max_nss_mcs[CMD_HE_MCS_BW80] =725he_cap->he_mcs_nss_supp.rx_mcs_80;726break;727}728729he->t_frame_dur =730HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);731he->max_ampdu_exp =732HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]);733734he->bw_set =735HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]);736he->device_class =737HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]);738he->punc_pream_rx =739HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);740741he->dcm_tx_mode =742HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]);743he->dcm_tx_max_nss =744HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]);745he->dcm_rx_mode =746HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]);747he->dcm_rx_max_nss =748HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]);749he->dcm_rx_max_nss =750HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]);751752he->pkt_ext = 2;753}754755void756mt76_connac_mcu_sta_he_tlv_v2(struct sk_buff *skb, struct ieee80211_sta *sta)757{758struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;759struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;760struct sta_rec_he_v2 *he;761struct tlv *tlv;762763tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he));764765he = (struct sta_rec_he_v2 *)tlv;766memcpy(he->he_phy_cap, elem->phy_cap_info, sizeof(he->he_phy_cap));767memcpy(he->he_mac_cap, elem->mac_cap_info, sizeof(he->he_mac_cap));768769switch (sta->deflink.bandwidth) {770case IEEE80211_STA_RX_BW_160:771if (elem->phy_cap_info[0] &772IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)773he->max_nss_mcs[CMD_HE_MCS_BW8080] =774he_cap->he_mcs_nss_supp.rx_mcs_80p80;775776he->max_nss_mcs[CMD_HE_MCS_BW160] =777he_cap->he_mcs_nss_supp.rx_mcs_160;778fallthrough;779default:780he->max_nss_mcs[CMD_HE_MCS_BW80] =781he_cap->he_mcs_nss_supp.rx_mcs_80;782break;783}784785he->pkt_ext = IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US;786}787EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_he_tlv_v2);788789u8790mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,791enum nl80211_band band,792struct ieee80211_link_sta *link_sta)793{794struct ieee80211_sta_ht_cap *ht_cap;795struct ieee80211_sta_vht_cap *vht_cap;796const struct ieee80211_sta_he_cap *he_cap;797const struct ieee80211_sta_eht_cap *eht_cap;798u8 mode = 0;799800if (link_sta) {801ht_cap = &link_sta->ht_cap;802vht_cap = &link_sta->vht_cap;803he_cap = &link_sta->he_cap;804eht_cap = &link_sta->eht_cap;805} else {806struct ieee80211_supported_band *sband;807808sband = mphy->hw->wiphy->bands[band];809ht_cap = &sband->ht_cap;810vht_cap = &sband->vht_cap;811he_cap = ieee80211_get_he_iftype_cap(sband, vif->type);812eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type);813}814815if (band == NL80211_BAND_2GHZ) {816mode |= PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP;817818if (ht_cap->ht_supported)819mode |= PHY_TYPE_BIT_HT;820821if (he_cap && he_cap->has_he)822mode |= PHY_TYPE_BIT_HE;823824if (eht_cap && eht_cap->has_eht)825mode |= PHY_TYPE_BIT_BE;826} else if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {827mode |= PHY_TYPE_BIT_OFDM;828829if (ht_cap->ht_supported)830mode |= PHY_TYPE_BIT_HT;831832if (vht_cap->vht_supported)833mode |= PHY_TYPE_BIT_VHT;834835if (he_cap && he_cap->has_he)836mode |= PHY_TYPE_BIT_HE;837838if (eht_cap && eht_cap->has_eht)839mode |= PHY_TYPE_BIT_BE;840}841842return mode;843}844EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode_v2);845846void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,847struct ieee80211_sta *sta,848struct ieee80211_vif *vif,849u8 rcpi, u8 sta_state)850{851struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;852struct cfg80211_chan_def *chandef = mvif->ctx ?853&mvif->ctx->def : &mphy->chandef;854enum nl80211_band band = chandef->chan->band;855struct mt76_dev *dev = mphy->dev;856struct sta_rec_ra_info *ra_info;857struct sta_rec_state *state;858struct sta_rec_phy *phy;859struct tlv *tlv;860u16 supp_rates;861862/* starec ht */863if (sta->deflink.ht_cap.ht_supported) {864struct sta_rec_ht *ht;865866tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));867ht = (struct sta_rec_ht *)tlv;868ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);869}870871/* starec vht */872if (sta->deflink.vht_cap.vht_supported) {873struct sta_rec_vht *vht;874int len;875876len = is_mt7921(dev) ? sizeof(*vht) : sizeof(*vht) - 4;877tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len);878vht = (struct sta_rec_vht *)tlv;879vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);880vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;881vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;882}883884/* starec uapsd */885mt76_connac_mcu_sta_uapsd(skb, vif, sta);886887if (!is_mt7921(dev))888return;889890if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)891mt76_connac_mcu_sta_amsdu_tlv(skb, sta, vif);892893/* starec he */894if (sta->deflink.he_cap.has_he) {895mt76_connac_mcu_sta_he_tlv(skb, sta);896mt76_connac_mcu_sta_he_tlv_v2(skb, sta);897if (band == NL80211_BAND_6GHZ &&898sta_state == MT76_STA_INFO_STATE_ASSOC) {899struct sta_rec_he_6g_capa *he_6g_capa;900901tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G,902sizeof(*he_6g_capa));903he_6g_capa = (struct sta_rec_he_6g_capa *)tlv;904he_6g_capa->capa = sta->deflink.he_6ghz_capa.capa;905}906}907908tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));909phy = (struct sta_rec_phy *)tlv;910phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band,911&sta->deflink);912phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates);913phy->rcpi = rcpi;914phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR,915sta->deflink.ht_cap.ampdu_factor) |916FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY,917sta->deflink.ht_cap.ampdu_density);918919tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));920ra_info = (struct sta_rec_ra_info *)tlv;921922supp_rates = sta->deflink.supp_rates[band];923if (band == NL80211_BAND_2GHZ)924supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) |925FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf);926else927supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates);928929ra_info->legacy = cpu_to_le16(supp_rates);930931if (sta->deflink.ht_cap.ht_supported)932memcpy(ra_info->rx_mcs_bitmask,933sta->deflink.ht_cap.mcs.rx_mask,934HT_MCS_MASK_NUM);935936tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));937state = (struct sta_rec_state *)tlv;938state->state = sta_state;939940if (sta->deflink.vht_cap.vht_supported) {941state->vht_opmode = sta->deflink.bandwidth;942state->vht_opmode |= (sta->deflink.rx_nss - 1) <<943IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;944}945}946EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_tlv);947948void mt76_connac_mcu_wtbl_smps_tlv(struct sk_buff *skb,949struct ieee80211_sta *sta,950void *sta_wtbl, void *wtbl_tlv)951{952struct wtbl_smps *smps;953struct tlv *tlv;954955tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps),956wtbl_tlv, sta_wtbl);957smps = (struct wtbl_smps *)tlv;958smps->smps = (sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC);959}960EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_smps_tlv);961962void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb,963struct ieee80211_sta *sta, void *sta_wtbl,964void *wtbl_tlv, bool ht_ldpc, bool vht_ldpc)965{966struct wtbl_ht *ht = NULL;967struct tlv *tlv;968u32 flags = 0;969970if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_6ghz_capa.capa) {971tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),972wtbl_tlv, sta_wtbl);973ht = (struct wtbl_ht *)tlv;974ht->ldpc = ht_ldpc &&975!!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);976977if (sta->deflink.ht_cap.ht_supported) {978ht->af = sta->deflink.ht_cap.ampdu_factor;979ht->mm = sta->deflink.ht_cap.ampdu_density;980} else {981ht->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,982IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);983ht->mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa,984IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);985}986987ht->ht = true;988}989990if (sta->deflink.vht_cap.vht_supported || sta->deflink.he_6ghz_capa.capa) {991struct wtbl_vht *vht;992u8 af;993994tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_VHT,995sizeof(*vht), wtbl_tlv,996sta_wtbl);997vht = (struct wtbl_vht *)tlv;998vht->ldpc = vht_ldpc &&999!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);1000vht->vht = true;10011002af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,1003sta->deflink.vht_cap.cap);1004if (ht)1005ht->af = max(ht->af, af);1006}10071008mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv);10091010if (is_connac_v1(dev) && sta->deflink.ht_cap.ht_supported) {1011/* sgi */1012u32 msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 |1013MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160;1014struct wtbl_raw *raw;10151016tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RAW_DATA,1017sizeof(*raw), wtbl_tlv,1018sta_wtbl);10191020if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)1021flags |= MT_WTBL_W5_SHORT_GI_20;1022if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)1023flags |= MT_WTBL_W5_SHORT_GI_40;10241025if (sta->deflink.vht_cap.vht_supported) {1026if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)1027flags |= MT_WTBL_W5_SHORT_GI_80;1028if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)1029flags |= MT_WTBL_W5_SHORT_GI_160;1030}1031raw = (struct wtbl_raw *)tlv;1032raw->val = cpu_to_le32(flags);1033raw->msk = cpu_to_le32(~msk);1034raw->wtbl_idx = 1;1035raw->dw = 5;1036}1037}1038EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv);10391040int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,1041struct mt76_sta_cmd_info *info)1042{1043struct mt76_vif_link *mvif = (struct mt76_vif_link *)info->vif->drv_priv;1044struct ieee80211_link_sta *link_sta;1045struct mt76_dev *dev = phy->dev;1046struct wtbl_req_hdr *wtbl_hdr;1047struct tlv *sta_wtbl;1048struct sk_buff *skb;1049int conn_state;10501051if (!info->link_conf)1052info->link_conf = &info->vif->bss_conf;10531054skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, info->wcid);1055if (IS_ERR(skb))1056return PTR_ERR(skb);10571058conn_state = info->enable ? CONN_STATE_PORT_SECURE :1059CONN_STATE_DISCONNECT;1060link_sta = info->sta ? &info->sta->deflink : NULL;1061if (info->sta || !info->offload_fw)1062mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf,1063link_sta, conn_state,1064info->newly);1065if (info->sta && info->enable)1066mt76_connac_mcu_sta_tlv(phy, skb, info->sta,1067info->vif, info->rcpi,1068info->state);10691070sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,1071sizeof(struct tlv));10721073wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, info->wcid,1074WTBL_RESET_AND_SET,1075sta_wtbl, &skb);1076if (IS_ERR(wtbl_hdr))1077return PTR_ERR(wtbl_hdr);10781079if (info->enable) {1080mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif,1081info->sta, sta_wtbl,1082wtbl_hdr);1083mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid,1084sta_wtbl, wtbl_hdr);1085if (info->sta)1086mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta,1087sta_wtbl, wtbl_hdr,1088true, true);1089}10901091return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);1092}1093EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_cmd);10941095void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb,1096struct ieee80211_ampdu_params *params,1097bool enable, bool tx, void *sta_wtbl,1098void *wtbl_tlv)1099{1100struct wtbl_ba *ba;1101struct tlv *tlv;11021103tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba),1104wtbl_tlv, sta_wtbl);11051106ba = (struct wtbl_ba *)tlv;1107ba->tid = params->tid;11081109if (tx) {1110ba->ba_type = MT_BA_TYPE_ORIGINATOR;1111ba->sn = enable ? cpu_to_le16(params->ssn) : 0;1112ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0;1113ba->ba_en = enable;1114} else {1115memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN);1116ba->ba_type = MT_BA_TYPE_RECIPIENT;1117ba->rst_ba_tid = params->tid;1118ba->rst_ba_sel = RST_BA_MAC_TID_MATCH;1119ba->rst_ba_sb = 1;1120}11211122if (!is_connac_v1(dev)) {1123ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0;1124return;1125}11261127if (enable && tx) {1128static const u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 };1129int i;11301131for (i = 7; i > 0; i--) {1132if (params->buf_size >= ba_range[i])1133break;1134}1135ba->ba_winsize_idx = i;1136}1137}1138EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ba_tlv);11391140int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,1141struct ieee80211_bss_conf *bss_conf,1142struct mt76_vif_link *mvif,1143struct mt76_wcid *wcid,1144bool enable)1145{1146struct mt76_dev *dev = phy->dev;1147struct {1148struct {1149u8 omac_idx;1150u8 band_idx;1151__le16 pad;1152} __packed hdr;1153struct req_tlv {1154__le16 tag;1155__le16 len;1156u8 active;1157u8 link_idx; /* not link_id */1158u8 omac_addr[ETH_ALEN];1159} __packed tlv;1160} dev_req = {1161.hdr = {1162.omac_idx = mvif->omac_idx,1163.band_idx = mvif->band_idx,1164},1165.tlv = {1166.tag = cpu_to_le16(DEV_INFO_ACTIVE),1167.len = cpu_to_le16(sizeof(struct req_tlv)),1168.active = enable,1169.link_idx = mvif->link_idx,1170},1171};1172struct {1173struct {1174u8 bss_idx;1175u8 pad[3];1176} __packed hdr;1177struct mt76_connac_bss_basic_tlv basic;1178} basic_req = {1179.hdr = {1180.bss_idx = mvif->idx,1181},1182.basic = {1183.tag = cpu_to_le16(UNI_BSS_INFO_BASIC),1184.len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)),1185.omac_idx = mvif->omac_idx,1186.band_idx = mvif->band_idx,1187.wmm_idx = mvif->wmm_idx,1188.active = enable,1189.bmc_tx_wlan_idx = cpu_to_le16(wcid->idx),1190.sta_idx = cpu_to_le16(wcid->idx),1191.conn_state = 1,1192.link_idx = mvif->link_idx,1193},1194};1195int err, idx, cmd, len;1196void *data;11971198switch (bss_conf->vif->type) {1199case NL80211_IFTYPE_MESH_POINT:1200case NL80211_IFTYPE_MONITOR:1201case NL80211_IFTYPE_AP:1202basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);1203break;1204case NL80211_IFTYPE_STATION:1205basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA);1206break;1207case NL80211_IFTYPE_P2P_DEVICE:1208basic_req.basic.conn_type = cpu_to_le32(CONNECTION_P2P_GO);1209break;1210case NL80211_IFTYPE_ADHOC:1211basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);1212break;1213default:1214WARN_ON(1);1215break;1216}12171218idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;1219basic_req.basic.hw_bss_idx = idx;12201221memcpy(dev_req.tlv.omac_addr, bss_conf->addr, ETH_ALEN);12221223cmd = enable ? MCU_UNI_CMD(DEV_INFO_UPDATE) : MCU_UNI_CMD(BSS_INFO_UPDATE);1224data = enable ? (void *)&dev_req : (void *)&basic_req;1225len = enable ? sizeof(dev_req) : sizeof(basic_req);12261227err = mt76_mcu_send_msg(dev, cmd, data, len, true);1228if (err < 0)1229return err;12301231cmd = enable ? MCU_UNI_CMD(BSS_INFO_UPDATE) : MCU_UNI_CMD(DEV_INFO_UPDATE);1232data = enable ? (void *)&basic_req : (void *)&dev_req;1233len = enable ? sizeof(basic_req) : sizeof(dev_req);12341235return mt76_mcu_send_msg(dev, cmd, data, len, true);1236}1237EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_dev);12381239void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb,1240struct ieee80211_ampdu_params *params,1241bool enable, bool tx)1242{1243struct sta_rec_ba *ba;1244struct tlv *tlv;12451246tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));12471248ba = (struct sta_rec_ba *)tlv;1249ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT;1250ba->winsize = cpu_to_le16(params->buf_size);1251ba->ssn = cpu_to_le16(params->ssn);1252ba->ba_en = enable << params->tid;1253ba->amsdu = params->amsdu;1254ba->tid = params->tid;1255}1256EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba_tlv);12571258int mt76_connac_mcu_sta_wed_update(struct mt76_dev *dev, struct sk_buff *skb)1259{1260if (!mt76_is_mmio(dev))1261return 0;12621263if (!mtk_wed_device_active(&dev->mmio.wed))1264return 0;12651266return mtk_wed_device_update_msg(&dev->mmio.wed, WED_WO_STA_REC,1267skb->data, skb->len);1268}1269EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_wed_update);12701271int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,1272struct ieee80211_ampdu_params *params,1273int cmd, bool enable, bool tx)1274{1275struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv;1276struct wtbl_req_hdr *wtbl_hdr;1277struct tlv *sta_wtbl;1278struct sk_buff *skb;1279int ret;12801281skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);1282if (IS_ERR(skb))1283return PTR_ERR(skb);12841285sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,1286sizeof(struct tlv));12871288wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET,1289sta_wtbl, &skb);1290if (IS_ERR(wtbl_hdr))1291return PTR_ERR(wtbl_hdr);12921293mt76_connac_mcu_wtbl_ba_tlv(dev, skb, params, enable, tx, sta_wtbl,1294wtbl_hdr);12951296ret = mt76_connac_mcu_sta_wed_update(dev, skb);1297if (ret)1298return ret;12991300ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true);1301if (ret)1302return ret;13031304skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);1305if (IS_ERR(skb))1306return PTR_ERR(skb);13071308mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx);13091310ret = mt76_connac_mcu_sta_wed_update(dev, skb);1311if (ret)1312return ret;13131314return mt76_mcu_skb_send_msg(dev, skb, cmd, true);1315}1316EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba);13171318u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,1319enum nl80211_band band,1320struct ieee80211_link_sta *link_sta)1321{1322struct mt76_dev *dev = phy->dev;1323const struct ieee80211_sta_he_cap *he_cap;1324struct ieee80211_sta_vht_cap *vht_cap;1325struct ieee80211_sta_ht_cap *ht_cap;1326u8 mode = 0;13271328if (is_connac_v1(dev))1329return 0x38;13301331if (link_sta) {1332ht_cap = &link_sta->ht_cap;1333vht_cap = &link_sta->vht_cap;1334he_cap = &link_sta->he_cap;1335} else {1336struct ieee80211_supported_band *sband;13371338sband = phy->hw->wiphy->bands[band];1339ht_cap = &sband->ht_cap;1340vht_cap = &sband->vht_cap;1341he_cap = ieee80211_get_he_iftype_cap(sband, vif->type);1342}13431344if (band == NL80211_BAND_2GHZ) {1345mode |= PHY_MODE_B | PHY_MODE_G;13461347if (ht_cap->ht_supported)1348mode |= PHY_MODE_GN;13491350if (he_cap && he_cap->has_he)1351mode |= PHY_MODE_AX_24G;1352} else if (band == NL80211_BAND_5GHZ) {1353mode |= PHY_MODE_A;13541355if (ht_cap->ht_supported)1356mode |= PHY_MODE_AN;13571358if (vht_cap->vht_supported)1359mode |= PHY_MODE_AC;13601361if (he_cap && he_cap->has_he)1362mode |= PHY_MODE_AX_5G;1363} else if (band == NL80211_BAND_6GHZ) {1364mode |= PHY_MODE_A | PHY_MODE_AN |1365PHY_MODE_AC | PHY_MODE_AX_5G;1366}13671368return mode;1369}1370EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode);13711372u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf,1373enum nl80211_band band)1374{1375const struct ieee80211_sta_eht_cap *eht_cap;1376struct ieee80211_supported_band *sband;1377u8 mode = 0;13781379if (band == NL80211_BAND_6GHZ)1380mode |= PHY_MODE_AX_6G;13811382sband = phy->hw->wiphy->bands[band];1383eht_cap = ieee80211_get_eht_iftype_cap(sband, conf->vif->type);13841385if (!eht_cap || !eht_cap->has_eht || !conf->eht_support)1386return mode;13871388switch (band) {1389case NL80211_BAND_6GHZ:1390mode |= PHY_MODE_BE_6G;1391break;1392case NL80211_BAND_5GHZ:1393mode |= PHY_MODE_BE_5G;1394break;1395case NL80211_BAND_2GHZ:1396mode |= PHY_MODE_BE_24G;1397break;1398default:1399break;1400}14011402return mode;1403}1404EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode_ext);14051406const struct ieee80211_sta_he_cap *1407mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif)1408{1409struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1410struct cfg80211_chan_def *chandef = mvif->ctx ?1411&mvif->ctx->def : &phy->chandef;1412enum nl80211_band band = chandef->chan->band;1413struct ieee80211_supported_band *sband;14141415sband = phy->hw->wiphy->bands[band];14161417return ieee80211_get_he_iftype_cap(sband, vif->type);1418}1419EXPORT_SYMBOL_GPL(mt76_connac_get_he_phy_cap);14201421const struct ieee80211_sta_eht_cap *1422mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif)1423{1424enum nl80211_band band = phy->chandef.chan->band;1425struct ieee80211_supported_band *sband;14261427sband = phy->hw->wiphy->bands[band];14281429return ieee80211_get_eht_iftype_cap(sband, vif->type);1430}1431EXPORT_SYMBOL_GPL(mt76_connac_get_eht_phy_cap);14321433#define DEFAULT_HE_PE_DURATION 41434#define DEFAULT_HE_DURATION_RTS_THRES 10231435static void1436mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif,1437struct tlv *tlv)1438{1439const struct ieee80211_sta_he_cap *cap;1440struct bss_info_uni_he *he;14411442cap = mt76_connac_get_he_phy_cap(phy, vif);14431444he = (struct bss_info_uni_he *)tlv;1445he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;1446if (!he->he_pe_duration)1447he->he_pe_duration = DEFAULT_HE_PE_DURATION;14481449he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);1450if (!he->he_rts_thres)1451he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);14521453he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;1454he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;1455he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;1456}14571458int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif,1459struct ieee80211_chanctx_conf *ctx)1460{1461struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef;1462int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;1463enum nl80211_band band = chandef->chan->band;1464struct mt76_dev *mdev = phy->dev;1465struct {1466struct {1467u8 bss_idx;1468u8 pad[3];1469} __packed hdr;1470struct rlm_tlv {1471__le16 tag;1472__le16 len;1473u8 control_channel;1474u8 center_chan;1475u8 center_chan2;1476u8 bw;1477u8 tx_streams;1478u8 rx_streams;1479u8 short_st;1480u8 ht_op_info;1481u8 sco;1482u8 band;1483u8 pad[2];1484} __packed rlm;1485} __packed rlm_req = {1486.hdr = {1487.bss_idx = mvif->idx,1488},1489.rlm = {1490.tag = cpu_to_le16(UNI_BSS_INFO_RLM),1491.len = cpu_to_le16(sizeof(struct rlm_tlv)),1492.control_channel = chandef->chan->hw_value,1493.center_chan = ieee80211_frequency_to_channel(freq1),1494.center_chan2 = ieee80211_frequency_to_channel(freq2),1495.tx_streams = hweight8(phy->antenna_mask),1496.ht_op_info = 4, /* set HT 40M allowed */1497.rx_streams = phy->chainmask,1498.short_st = true,1499.band = band,1500},1501};15021503switch (chandef->width) {1504case NL80211_CHAN_WIDTH_40:1505rlm_req.rlm.bw = CMD_CBW_40MHZ;1506break;1507case NL80211_CHAN_WIDTH_80:1508rlm_req.rlm.bw = CMD_CBW_80MHZ;1509break;1510case NL80211_CHAN_WIDTH_80P80:1511rlm_req.rlm.bw = CMD_CBW_8080MHZ;1512break;1513case NL80211_CHAN_WIDTH_160:1514rlm_req.rlm.bw = CMD_CBW_160MHZ;1515break;1516case NL80211_CHAN_WIDTH_5:1517rlm_req.rlm.bw = CMD_CBW_5MHZ;1518break;1519case NL80211_CHAN_WIDTH_10:1520rlm_req.rlm.bw = CMD_CBW_10MHZ;1521break;1522case NL80211_CHAN_WIDTH_20_NOHT:1523case NL80211_CHAN_WIDTH_20:1524default:1525rlm_req.rlm.bw = CMD_CBW_20MHZ;1526rlm_req.rlm.ht_op_info = 0;1527break;1528}15291530if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan)1531rlm_req.rlm.sco = 1; /* SCA */1532else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan)1533rlm_req.rlm.sco = 3; /* SCB */15341535return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &rlm_req,1536sizeof(rlm_req), true);1537}1538EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_set_chctx);15391540int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,1541struct ieee80211_vif *vif,1542struct mt76_wcid *wcid,1543bool enable,1544struct ieee80211_chanctx_conf *ctx)1545{1546struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1547struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef;1548enum nl80211_band band = chandef->chan->band;1549struct mt76_dev *mdev = phy->dev;1550struct {1551struct {1552u8 bss_idx;1553u8 pad[3];1554} __packed hdr;1555struct mt76_connac_bss_basic_tlv basic;1556struct mt76_connac_bss_qos_tlv qos;1557} basic_req = {1558.hdr = {1559.bss_idx = mvif->idx,1560},1561.basic = {1562.tag = cpu_to_le16(UNI_BSS_INFO_BASIC),1563.len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)),1564.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),1565.dtim_period = vif->bss_conf.dtim_period,1566.omac_idx = mvif->omac_idx,1567.band_idx = mvif->band_idx,1568.wmm_idx = mvif->wmm_idx,1569.active = true, /* keep bss deactivated */1570.phymode = mt76_connac_get_phy_mode(phy, vif, band, NULL),1571},1572.qos = {1573.tag = cpu_to_le16(UNI_BSS_INFO_QBSS),1574.len = cpu_to_le16(sizeof(struct mt76_connac_bss_qos_tlv)),1575.qos = vif->bss_conf.qos,1576},1577};1578int err, conn_type;1579u8 idx, basic_phy;15801581idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;1582basic_req.basic.hw_bss_idx = idx;1583if (band == NL80211_BAND_6GHZ)1584basic_req.basic.phymode_ext = PHY_MODE_AX_6G;15851586basic_phy = mt76_connac_get_phy_mode_v2(phy, vif, band, NULL);1587basic_req.basic.nonht_basic_phy = cpu_to_le16(basic_phy);15881589switch (vif->type) {1590case NL80211_IFTYPE_MESH_POINT:1591case NL80211_IFTYPE_AP:1592if (vif->p2p)1593conn_type = CONNECTION_P2P_GO;1594else1595conn_type = CONNECTION_INFRA_AP;1596basic_req.basic.conn_type = cpu_to_le32(conn_type);1597/* Fully active/deactivate BSS network in AP mode only */1598basic_req.basic.active = enable;1599break;1600case NL80211_IFTYPE_STATION:1601if (vif->p2p)1602conn_type = CONNECTION_P2P_GC;1603else1604conn_type = CONNECTION_INFRA_STA;1605basic_req.basic.conn_type = cpu_to_le32(conn_type);1606break;1607case NL80211_IFTYPE_ADHOC:1608basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);1609break;1610default:1611WARN_ON(1);1612break;1613}16141615memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN);1616basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(wcid->idx);1617basic_req.basic.sta_idx = cpu_to_le16(wcid->idx);1618basic_req.basic.conn_state = !enable;16191620err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &basic_req,1621sizeof(basic_req), true);1622if (err < 0)1623return err;16241625if (vif->bss_conf.he_support) {1626struct {1627struct {1628u8 bss_idx;1629u8 pad[3];1630} __packed hdr;1631struct bss_info_uni_he he;1632struct bss_info_uni_bss_color bss_color;1633} he_req = {1634.hdr = {1635.bss_idx = mvif->idx,1636},1637.he = {1638.tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC),1639.len = cpu_to_le16(sizeof(struct bss_info_uni_he)),1640},1641.bss_color = {1642.tag = cpu_to_le16(UNI_BSS_INFO_BSS_COLOR),1643.len = cpu_to_le16(sizeof(struct bss_info_uni_bss_color)),1644.enable = 0,1645.bss_color = 0,1646},1647};16481649if (enable) {1650he_req.bss_color.enable =1651vif->bss_conf.he_bss_color.enabled;1652he_req.bss_color.bss_color =1653vif->bss_conf.he_bss_color.color;1654}16551656mt76_connac_mcu_uni_bss_he_tlv(phy, vif,1657(struct tlv *)&he_req.he);1658err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE),1659&he_req, sizeof(he_req), true);1660if (err < 0)1661return err;1662}16631664if (enable && vif->bss_conf.bssid_indicator) {1665struct {1666struct {1667u8 bss_idx;1668u8 pad[3];1669} __packed hdr;1670struct bss_info_uni_mbssid mbssid;1671} mbssid_req = {1672.hdr = {1673.bss_idx = mvif->idx,1674},1675.mbssid = {1676.tag = cpu_to_le16(UNI_BSS_INFO_11V_MBSSID),1677.len = cpu_to_le16(sizeof(struct bss_info_uni_mbssid)),1678.max_indicator = vif->bss_conf.bssid_indicator,1679.mbss_idx = vif->bss_conf.bssid_index,1680},1681};16821683err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE),1684&mbssid_req, sizeof(mbssid_req), true);1685if (err < 0)1686return err;1687}16881689return mt76_connac_mcu_uni_set_chctx(phy, mvif, ctx);1690}1691EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss);16921693void mt76_connac_mcu_build_rnr_scan_param(struct mt76_dev *mdev,1694struct cfg80211_scan_request *sreq)1695{1696struct ieee80211_channel **scan_list = sreq->channels;1697int i, bssid_index = 0;16981699/* clear 6G active Scan BSSID table */1700memset(&mdev->rnr, 0, sizeof(mdev->rnr));17011702for (i = 0; i < sreq->n_6ghz_params; i++) {1703u8 ch_idx = sreq->scan_6ghz_params[i].channel_idx;1704int k = 0;17051706/* Remove the duplicated BSSID */1707for (k = 0; k < bssid_index; k++) {1708if (!memcmp(&mdev->rnr.bssid[k],1709sreq->scan_6ghz_params[i].bssid,1710ETH_ALEN))1711break;1712}17131714if (k == bssid_index &&1715bssid_index < MT76_RNR_SCAN_MAX_BSSIDS) {1716memcpy(&mdev->rnr.bssid[bssid_index++],1717sreq->scan_6ghz_params[i].bssid, ETH_ALEN);1718mdev->rnr.channel[k] = scan_list[ch_idx]->hw_value;1719}1720}17211722mdev->rnr.bssid_num = bssid_index;17231724if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {1725memcpy(mdev->rnr.random_mac, sreq->mac_addr, ETH_ALEN);1726mdev->rnr.sreq_flag = sreq->flags;1727}1728}1729EXPORT_SYMBOL_GPL(mt76_connac_mcu_build_rnr_scan_param);17301731#define MT76_CONNAC_SCAN_CHANNEL_TIME 601732int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,1733struct ieee80211_scan_request *scan_req)1734{1735struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1736struct cfg80211_scan_request *sreq = &scan_req->req;1737int n_ssids = 0, err, i, duration;1738int ext_channels_num = max_t(int, sreq->n_channels - 32, 0);1739struct ieee80211_channel **scan_list = sreq->channels;1740struct mt76_dev *mdev = phy->dev;1741struct mt76_connac_mcu_scan_channel *chan;1742struct mt76_connac_hw_scan_req *req;1743struct sk_buff *skb;17441745if (test_bit(MT76_HW_SCANNING, &phy->state))1746return -EBUSY;17471748skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req));1749if (!skb)1750return -ENOMEM;17511752set_bit(MT76_HW_SCANNING, &phy->state);1753mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;17541755req = (struct mt76_connac_hw_scan_req *)skb_put_zero(skb, sizeof(*req));17561757req->seq_num = mvif->scan_seq_num | mvif->band_idx << 7;1758req->bss_idx = mvif->idx;1759req->scan_type = sreq->n_ssids ? 1 : 0;1760req->probe_req_num = sreq->n_ssids ? 2 : 0;1761req->version = 1;17621763for (i = 0; i < sreq->n_ssids; i++) {1764if (!sreq->ssids[i].ssid_len)1765continue;17661767req->ssids[n_ssids].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);1768memcpy(req->ssids[n_ssids].ssid, sreq->ssids[i].ssid,1769sreq->ssids[i].ssid_len);1770n_ssids++;1771}1772req->ssid_type = n_ssids ? BIT(2) : BIT(0);1773req->ssid_type_ext = n_ssids ? BIT(0) : 0;1774req->ssids_num = n_ssids;17751776duration = is_mt7921(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME;1777/* increase channel time for passive scan */1778if (!sreq->n_ssids)1779duration *= 2;1780req->timeout_value = cpu_to_le16(sreq->n_channels * duration);1781req->channel_min_dwell_time = cpu_to_le16(duration);1782req->channel_dwell_time = cpu_to_le16(duration);17831784if (sreq->n_channels == 0 || sreq->n_channels > 64) {1785req->channel_type = 0;1786req->channels_num = 0;1787req->ext_channels_num = 0;1788} else {1789req->channel_type = 4;1790req->channels_num = min_t(u8, sreq->n_channels, 32);1791req->ext_channels_num = min_t(u8, ext_channels_num, 32);1792}17931794for (i = 0; i < req->channels_num + req->ext_channels_num; i++) {1795if (i >= 32)1796chan = &req->ext_channels[i - 32];1797else1798chan = &req->channels[i];17991800switch (scan_list[i]->band) {1801case NL80211_BAND_2GHZ:1802chan->band = 1;1803break;1804case NL80211_BAND_6GHZ:1805chan->band = 3;1806break;1807default:1808chan->band = 2;1809break;1810}1811chan->channel_num = scan_list[i]->hw_value;1812}18131814if (sreq->ie_len > 0) {1815memcpy(req->ies, sreq->ie, sreq->ie_len);1816req->ies_len = cpu_to_le16(sreq->ie_len);1817}18181819if (is_mt7921(phy->dev))1820req->scan_func |= SCAN_FUNC_SPLIT_SCAN;18211822memcpy(req->bssid, sreq->bssid, ETH_ALEN);1823if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {1824get_random_mask_addr(req->random_mac, sreq->mac_addr,1825sreq->mac_addr_mask);1826req->scan_func |= SCAN_FUNC_RANDOM_MAC;1827}18281829err = mt76_mcu_skb_send_msg(mdev, skb, MCU_CE_CMD(START_HW_SCAN),1830false);1831if (err < 0)1832clear_bit(MT76_HW_SCANNING, &phy->state);18331834return err;1835}1836EXPORT_SYMBOL_GPL(mt76_connac_mcu_hw_scan);18371838int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy,1839struct ieee80211_vif *vif)1840{1841struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1842struct {1843u8 seq_num;1844u8 is_ext_channel;1845u8 rsv[2];1846} __packed req = {1847.seq_num = mvif->scan_seq_num,1848};18491850if (test_and_clear_bit(MT76_HW_SCANNING, &phy->state)) {1851struct cfg80211_scan_info info = {1852.aborted = true,1853};18541855ieee80211_scan_completed(phy->hw, &info);1856}18571858return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(CANCEL_HW_SCAN),1859&req, sizeof(req), false);1860}1861EXPORT_SYMBOL_GPL(mt76_connac_mcu_cancel_hw_scan);18621863int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,1864struct ieee80211_vif *vif,1865struct cfg80211_sched_scan_request *sreq)1866{1867struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1868struct ieee80211_channel **scan_list = sreq->channels;1869struct mt76_connac_mcu_scan_channel *chan;1870struct mt76_connac_sched_scan_req *req;1871struct mt76_dev *mdev = phy->dev;1872struct cfg80211_match_set *match;1873struct cfg80211_ssid *ssid;1874struct sk_buff *skb;1875int i;18761877skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req) + sreq->ie_len);1878if (!skb)1879return -ENOMEM;18801881mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;18821883req = (struct mt76_connac_sched_scan_req *)skb_put_zero(skb, sizeof(*req));1884req->version = 1;1885req->seq_num = mvif->scan_seq_num | mvif->band_idx << 7;18861887if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {1888u8 *addr = is_mt7663(phy->dev) ? req->mt7663.random_mac1889: req->mt7921.random_mac;18901891req->scan_func = 1;1892get_random_mask_addr(addr, sreq->mac_addr,1893sreq->mac_addr_mask);1894}1895if (is_mt7921(phy->dev)) {1896req->mt7921.bss_idx = mvif->idx;1897req->mt7921.delay = cpu_to_le32(sreq->delay);1898}18991900req->ssids_num = sreq->n_ssids;1901for (i = 0; i < req->ssids_num; i++) {1902ssid = &sreq->ssids[i];1903memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len);1904req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len);1905}19061907req->match_num = sreq->n_match_sets;1908for (i = 0; i < req->match_num; i++) {1909match = &sreq->match_sets[i];1910memcpy(req->match[i].ssid, match->ssid.ssid,1911match->ssid.ssid_len);1912req->match[i].rssi_th = cpu_to_le32(match->rssi_thold);1913req->match[i].ssid_len = match->ssid.ssid_len;1914}19151916req->channel_type = sreq->n_channels ? 4 : 0;1917req->channels_num = min_t(u8, sreq->n_channels, 64);1918for (i = 0; i < req->channels_num; i++) {1919chan = &req->channels[i];19201921switch (scan_list[i]->band) {1922case NL80211_BAND_2GHZ:1923chan->band = 1;1924break;1925case NL80211_BAND_6GHZ:1926chan->band = 3;1927break;1928default:1929chan->band = 2;1930break;1931}1932chan->channel_num = scan_list[i]->hw_value;1933}19341935req->intervals_num = sreq->n_scan_plans;1936for (i = 0; i < req->intervals_num; i++)1937req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval);19381939if (sreq->ie_len > 0) {1940req->ie_len = cpu_to_le16(sreq->ie_len);1941memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len);1942}19431944return mt76_mcu_skb_send_msg(mdev, skb, MCU_CE_CMD(SCHED_SCAN_REQ),1945false);1946}1947EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_req);19481949int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy,1950struct ieee80211_vif *vif,1951bool enable)1952{1953struct {1954u8 active; /* 0: enabled 1: disabled */1955u8 rsv[3];1956} __packed req = {1957.active = !enable,1958};19591960if (enable)1961set_bit(MT76_HW_SCHED_SCANNING, &phy->state);1962else1963clear_bit(MT76_HW_SCHED_SCANNING, &phy->state);19641965return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(SCHED_SCAN_ENABLE),1966&req, sizeof(req), false);1967}1968EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable);19691970int mt76_connac_mcu_chip_config(struct mt76_dev *dev)1971{1972struct mt76_connac_config req = {1973.resp_type = 0,1974};19751976#if defined(__linux__)1977strscpy(req.data, "assert");1978#elif defined(__FreeBSD__)1979strscpy(req.data, "assert", sizeof(req.data));1980#endif19811982return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG),1983&req, sizeof(req), false);1984}1985EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config);19861987int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable)1988{1989struct mt76_connac_config req = {1990.resp_type = 0,1991};19921993snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !enable);19941995return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG),1996&req, sizeof(req), false);1997}1998EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep);19992000int mt76_connac_sta_state_dp(struct mt76_dev *dev,2001enum ieee80211_sta_state old_state,2002enum ieee80211_sta_state new_state)2003{2004if ((old_state == IEEE80211_STA_ASSOC &&2005new_state == IEEE80211_STA_AUTHORIZED) ||2006(old_state == IEEE80211_STA_NONE &&2007new_state == IEEE80211_STA_NOTEXIST))2008mt76_connac_mcu_set_deep_sleep(dev, true);20092010if ((old_state == IEEE80211_STA_NOTEXIST &&2011new_state == IEEE80211_STA_NONE) ||2012(old_state == IEEE80211_STA_AUTHORIZED &&2013new_state == IEEE80211_STA_ASSOC))2014mt76_connac_mcu_set_deep_sleep(dev, false);20152016return 0;2017}2018EXPORT_SYMBOL_GPL(mt76_connac_sta_state_dp);20192020void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,2021struct mt76_connac_coredump *coredump)2022{2023spin_lock_bh(&dev->lock);2024__skb_queue_tail(&coredump->msg_list, skb);2025spin_unlock_bh(&dev->lock);20262027coredump->last_activity = jiffies;20282029queue_delayed_work(dev->wq, &coredump->work,2030MT76_CONNAC_COREDUMP_TIMEOUT);2031}2032EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);20332034static void2035mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,2036struct mt76_power_limits *limits,2037enum nl80211_band band)2038{2039int max_power = is_mt7921(dev) ? 127 : 63;2040int i, offset = sizeof(limits->cck);20412042memset(sku, max_power, MT_SKU_POWER_LIMIT);20432044if (band == NL80211_BAND_2GHZ) {2045/* cck */2046memcpy(sku, limits->cck, sizeof(limits->cck));2047}20482049/* ofdm */2050memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm));2051offset += sizeof(limits->ofdm);20522053/* ht */2054for (i = 0; i < 2; i++) {2055memcpy(&sku[offset], limits->mcs[i], 8);2056offset += 8;2057}2058sku[offset++] = limits->mcs[0][0];20592060/* vht */2061for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) {2062memcpy(&sku[offset], limits->mcs[i],2063ARRAY_SIZE(limits->mcs[i]));2064offset += 12;2065}20662067if (!is_mt7921(dev))2068return;20692070/* he */2071for (i = 0; i < ARRAY_SIZE(limits->ru); i++) {2072memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i]));2073offset += ARRAY_SIZE(limits->ru[i]);2074}2075}20762077s8 mt76_connac_get_ch_power(struct mt76_phy *phy,2078struct ieee80211_channel *chan,2079s8 target_power)2080{2081struct mt76_dev *dev = phy->dev;2082struct ieee80211_supported_band *sband;2083int i;20842085switch (chan->band) {2086case NL80211_BAND_2GHZ:2087sband = &phy->sband_2g.sband;2088break;2089case NL80211_BAND_5GHZ:2090sband = &phy->sband_5g.sband;2091break;2092case NL80211_BAND_6GHZ:2093sband = &phy->sband_6g.sband;2094break;2095default:2096return target_power;2097}20982099for (i = 0; i < sband->n_channels; i++) {2100struct ieee80211_channel *ch = &sband->channels[i];21012102if (ch->hw_value == chan->hw_value) {2103if (!(ch->flags & IEEE80211_CHAN_DISABLED)) {2104int power = 2 * ch->max_reg_power;21052106if (is_mt7663(dev) && (power > 63 || power < -64))2107power = 63;2108target_power = min_t(s8, power, target_power);2109}2110break;2111}2112}21132114return target_power;2115}2116EXPORT_SYMBOL_GPL(mt76_connac_get_ch_power);21172118static int2119mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,2120enum nl80211_band band)2121{2122struct mt76_dev *dev = phy->dev;2123int sku_len, batch_len = is_mt7921(dev) ? 8 : 16;2124static const u8 chan_list_2ghz[] = {21251, 2, 3, 4, 5, 6, 7,21268, 9, 10, 11, 12, 13, 142127};2128static const u8 chan_list_5ghz[] = {212936, 38, 40, 42, 44, 46, 48,213050, 52, 54, 56, 58, 60, 62,213164, 100, 102, 104, 106, 108, 110,2132112, 114, 116, 118, 120, 122, 124,2133126, 128, 132, 134, 136, 138, 140,2134142, 144, 149, 151, 153, 155, 157,2135159, 161, 165, 169, 173, 1772136};2137static const u8 chan_list_6ghz[] = {21381, 3, 5, 7, 9, 11, 13,213915, 17, 19, 21, 23, 25, 27,214029, 33, 35, 37, 39, 41, 43,214145, 47, 49, 51, 53, 55, 57,214259, 61, 65, 67, 69, 71, 73,214375, 77, 79, 81, 83, 85, 87,214489, 91, 93, 97, 99, 101, 103,2145105, 107, 109, 111, 113, 115, 117,2146119, 121, 123, 125, 129, 131, 133,2147135, 137, 139, 141, 143, 145, 147,2148149, 151, 153, 155, 157, 161, 163,2149165, 167, 169, 171, 173, 175, 177,2150179, 181, 183, 185, 187, 189, 193,2151195, 197, 199, 201, 203, 205, 207,2152209, 211, 213, 215, 217, 219, 221,2153225, 227, 229, 2332154};2155int i, n_chan, batch_size, idx = 0, tx_power, last_ch, err = 0;2156struct mt76_connac_sku_tlv sku_tlbv;2157struct mt76_power_limits *limits;2158const u8 *ch_list;21592160limits = devm_kmalloc(dev->dev, sizeof(*limits), GFP_KERNEL);2161if (!limits)2162return -ENOMEM;21632164sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;2165tx_power = 2 * phy->hw->conf.power_level;2166if (!tx_power)2167tx_power = 127;21682169if (band == NL80211_BAND_2GHZ) {2170n_chan = ARRAY_SIZE(chan_list_2ghz);2171ch_list = chan_list_2ghz;2172} else if (band == NL80211_BAND_6GHZ) {2173n_chan = ARRAY_SIZE(chan_list_6ghz);2174ch_list = chan_list_6ghz;2175} else {2176n_chan = ARRAY_SIZE(chan_list_5ghz);2177ch_list = chan_list_5ghz;2178}2179batch_size = DIV_ROUND_UP(n_chan, batch_len);21802181if (phy->cap.has_6ghz)2182last_ch = chan_list_6ghz[ARRAY_SIZE(chan_list_6ghz) - 1];2183else if (phy->cap.has_5ghz)2184last_ch = chan_list_5ghz[ARRAY_SIZE(chan_list_5ghz) - 1];2185else2186last_ch = chan_list_2ghz[ARRAY_SIZE(chan_list_2ghz) - 1];21872188for (i = 0; i < batch_size; i++) {2189struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {};2190int j, msg_len, num_ch;2191struct sk_buff *skb;21922193num_ch = i == batch_size - 1 ? n_chan - i * batch_len : batch_len;2194msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);2195skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);2196if (!skb) {2197err = -ENOMEM;2198goto out;2199}22002201skb_reserve(skb, sizeof(tx_power_tlv));22022203BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));2204memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));2205tx_power_tlv.n_chan = num_ch;22062207switch (band) {2208case NL80211_BAND_2GHZ:2209tx_power_tlv.band = 1;2210break;2211case NL80211_BAND_6GHZ:2212tx_power_tlv.band = 3;2213break;2214default:2215tx_power_tlv.band = 2;2216break;2217}22182219for (j = 0; j < num_ch; j++, idx++) {2220struct ieee80211_channel chan = {2221.hw_value = ch_list[idx],2222.band = band,2223};2224s8 reg_power, sar_power;22252226reg_power = mt76_connac_get_ch_power(phy, &chan,2227tx_power);2228sar_power = mt76_get_sar_power(phy, &chan, reg_power);22292230mt76_get_rate_power_limits(phy, &chan, limits,2231sar_power);22322233tx_power_tlv.last_msg = ch_list[idx] == last_ch;2234sku_tlbv.channel = ch_list[idx];22352236mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,2237limits, band);2238skb_put_data(skb, &sku_tlbv, sku_len);2239}2240__skb_push(skb, sizeof(tx_power_tlv));2241memcpy(skb->data, &tx_power_tlv, sizeof(tx_power_tlv));22422243err = mt76_mcu_skb_send_msg(dev, skb,2244MCU_CE_CMD(SET_RATE_TX_POWER),2245false);2246if (err < 0)2247goto out;2248}22492250out:2251devm_kfree(dev->dev, limits);2252return err;2253}22542255int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)2256{2257int err;22582259if (phy->cap.has_2ghz) {2260err = mt76_connac_mcu_rate_txpower_band(phy,2261NL80211_BAND_2GHZ);2262if (err < 0)2263return err;2264}2265if (phy->cap.has_5ghz) {2266err = mt76_connac_mcu_rate_txpower_band(phy,2267NL80211_BAND_5GHZ);2268if (err < 0)2269return err;2270}2271if (phy->cap.has_6ghz) {2272err = mt76_connac_mcu_rate_txpower_band(phy,2273NL80211_BAND_6GHZ);2274if (err < 0)2275return err;2276}22772278return 0;2279}2280EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);22812282int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev,2283struct mt76_vif_link *vif,2284struct ieee80211_bss_conf *info)2285{2286struct ieee80211_vif *mvif = container_of(info, struct ieee80211_vif,2287bss_conf);2288struct sk_buff *skb;2289int i, len = min_t(int, mvif->cfg.arp_addr_cnt,2290IEEE80211_BSS_ARP_ADDR_LIST_LEN);2291struct {2292struct {2293u8 bss_idx;2294u8 pad[3];2295} __packed hdr;2296struct mt76_connac_arpns_tlv arp;2297} req_hdr = {2298.hdr = {2299.bss_idx = vif->idx,2300},2301.arp = {2302.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),2303.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),2304.ips_num = len,2305.mode = 2, /* update */2306.option = 1,2307},2308};23092310skb = mt76_mcu_msg_alloc(dev, NULL,2311sizeof(req_hdr) + len * sizeof(__be32));2312if (!skb)2313return -ENOMEM;23142315skb_put_data(skb, &req_hdr, sizeof(req_hdr));2316for (i = 0; i < len; i++)2317skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32));23182319return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true);2320}2321EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_arp_filter);23222323int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw,2324struct ieee80211_vif *vif)2325{2326struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2327int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow;2328struct mt76_phy *phy = hw->priv;2329struct {2330__le32 ct_win;2331u8 bss_idx;2332u8 rsv[3];2333} __packed req = {2334.ct_win = cpu_to_le32(ct_window),2335.bss_idx = mvif->idx,2336};23372338return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(SET_P2P_OPPPS),2339&req, sizeof(req), false);2340}2341EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_p2p_oppps);23422343#ifdef CONFIG_PM23442345const struct wiphy_wowlan_support mt76_connac_wowlan_support = {2346.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |2347WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT,2348.n_patterns = 1,2349.pattern_min_len = 1,2350.pattern_max_len = MT76_CONNAC_WOW_PATTEN_MAX_LEN,2351.max_nd_match_sets = 10,2352};2353EXPORT_SYMBOL_GPL(mt76_connac_wowlan_support);23542355static void2356mt76_connac_mcu_key_iter(struct ieee80211_hw *hw,2357struct ieee80211_vif *vif,2358struct ieee80211_sta *sta,2359struct ieee80211_key_conf *key,2360void *data)2361{2362struct mt76_connac_gtk_rekey_tlv *gtk_tlv = data;2363u32 cipher;23642365if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&2366key->cipher != WLAN_CIPHER_SUITE_CCMP &&2367key->cipher != WLAN_CIPHER_SUITE_TKIP)2368return;23692370if (key->cipher == WLAN_CIPHER_SUITE_TKIP)2371cipher = BIT(3);2372else2373cipher = BIT(4);23742375/* we are assuming here to have a single pairwise key */2376if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {2377if (key->cipher == WLAN_CIPHER_SUITE_TKIP)2378gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1);2379else2380gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2);23812382gtk_tlv->pairwise_cipher = cpu_to_le32(cipher);2383gtk_tlv->keyid = key->keyidx;2384} else {2385gtk_tlv->group_cipher = cpu_to_le32(cipher);2386}2387}23882389int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,2390struct ieee80211_vif *vif,2391struct cfg80211_gtk_rekey_data *key)2392{2393struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2394struct mt76_connac_gtk_rekey_tlv *gtk_tlv;2395struct mt76_phy *phy = hw->priv;2396struct sk_buff *skb;2397struct {2398u8 bss_idx;2399u8 pad[3];2400} __packed hdr = {2401.bss_idx = mvif->idx,2402};24032404skb = mt76_mcu_msg_alloc(phy->dev, NULL,2405sizeof(hdr) + sizeof(*gtk_tlv));2406if (!skb)2407return -ENOMEM;24082409skb_put_data(skb, &hdr, sizeof(hdr));2410gtk_tlv = (struct mt76_connac_gtk_rekey_tlv *)skb_put_zero(skb,2411sizeof(*gtk_tlv));2412gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY);2413gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv));2414gtk_tlv->rekey_mode = 2;2415gtk_tlv->option = 1;24162417rcu_read_lock();2418ieee80211_iter_keys_rcu(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv);2419rcu_read_unlock();24202421memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN);2422memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN);2423memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN);24242425return mt76_mcu_skb_send_msg(phy->dev, skb,2426MCU_UNI_CMD(OFFLOAD), true);2427}2428EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_gtk_rekey);24292430static int2431mt76_connac_mcu_set_arp_filter(struct mt76_dev *dev, struct ieee80211_vif *vif,2432bool suspend)2433{2434struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2435struct {2436struct {2437u8 bss_idx;2438u8 pad[3];2439} __packed hdr;2440struct mt76_connac_arpns_tlv arpns;2441} req = {2442.hdr = {2443.bss_idx = mvif->idx,2444},2445.arpns = {2446.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),2447.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),2448.mode = suspend,2449},2450};24512452return mt76_mcu_send_msg(dev, MCU_UNI_CMD(OFFLOAD), &req,2453sizeof(req), true);2454}24552456int2457mt76_connac_mcu_set_gtk_rekey(struct mt76_dev *dev, struct ieee80211_vif *vif,2458bool suspend)2459{2460struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2461struct {2462struct {2463u8 bss_idx;2464u8 pad[3];2465} __packed hdr;2466struct mt76_connac_gtk_rekey_tlv gtk_tlv;2467} __packed req = {2468.hdr = {2469.bss_idx = mvif->idx,2470},2471.gtk_tlv = {2472.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY),2473.len = cpu_to_le16(sizeof(struct mt76_connac_gtk_rekey_tlv)),2474.rekey_mode = !suspend,2475},2476};24772478return mt76_mcu_send_msg(dev, MCU_UNI_CMD(OFFLOAD), &req,2479sizeof(req), true);2480}2481EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_gtk_rekey);24822483int2484mt76_connac_mcu_set_suspend_mode(struct mt76_dev *dev,2485struct ieee80211_vif *vif,2486bool enable, u8 mdtim,2487bool wow_suspend)2488{2489struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2490struct {2491struct {2492u8 bss_idx;2493u8 pad[3];2494} __packed hdr;2495struct mt76_connac_suspend_tlv suspend_tlv;2496} req = {2497.hdr = {2498.bss_idx = mvif->idx,2499},2500.suspend_tlv = {2501.tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING),2502.len = cpu_to_le16(sizeof(struct mt76_connac_suspend_tlv)),2503.enable = enable,2504.mdtim = mdtim,2505.wow_suspend = wow_suspend,2506},2507};25082509return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req,2510sizeof(req), true);2511}2512EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_mode);25132514static int2515mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev,2516struct ieee80211_vif *vif,2517u8 index, bool enable,2518struct cfg80211_pkt_pattern *pattern)2519{2520struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2521struct mt76_connac_wow_pattern_tlv *ptlv;2522struct sk_buff *skb;2523struct req_hdr {2524u8 bss_idx;2525u8 pad[3];2526} __packed hdr = {2527.bss_idx = mvif->idx,2528};25292530skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*ptlv));2531if (!skb)2532return -ENOMEM;25332534skb_put_data(skb, &hdr, sizeof(hdr));2535ptlv = (struct mt76_connac_wow_pattern_tlv *)skb_put_zero(skb, sizeof(*ptlv));2536ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN);2537ptlv->len = cpu_to_le16(sizeof(*ptlv));2538ptlv->data_len = pattern->pattern_len;2539ptlv->enable = enable;2540ptlv->index = index;25412542memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len);2543memcpy(ptlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8));25442545return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SUSPEND), true);2546}25472548int2549mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,2550bool suspend, struct cfg80211_wowlan *wowlan)2551{2552struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2553struct mt76_dev *dev = phy->dev;2554struct {2555struct {2556u8 bss_idx;2557u8 pad[3];2558} __packed hdr;2559struct mt76_connac_wow_ctrl_tlv wow_ctrl_tlv;2560struct mt76_connac_wow_gpio_param_tlv gpio_tlv;2561} req = {2562.hdr = {2563.bss_idx = mvif->idx,2564},2565.wow_ctrl_tlv = {2566.tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL),2567.len = cpu_to_le16(sizeof(struct mt76_connac_wow_ctrl_tlv)),2568.cmd = suspend ? 1 : 2,2569},2570.gpio_tlv = {2571.tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM),2572.len = cpu_to_le16(sizeof(struct mt76_connac_wow_gpio_param_tlv)),2573.gpio_pin = 0xff, /* follow fw about GPIO pin */2574},2575};25762577if (wowlan->magic_pkt)2578req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC;2579if (wowlan->disconnect)2580req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT |2581UNI_WOW_DETECT_TYPE_BCN_LOST);2582if (wowlan->nd_config) {2583mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config);2584req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT;2585mt76_connac_mcu_sched_scan_enable(phy, vif, suspend);2586}2587if (wowlan->n_patterns)2588req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP;25892590if (mt76_is_mmio(dev))2591req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE;2592else if (mt76_is_usb(dev))2593req.wow_ctrl_tlv.wakeup_hif = WOW_USB;2594else if (mt76_is_sdio(dev))2595req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO;25962597return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req,2598sizeof(req), true);2599}2600EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_wow_ctrl);26012602int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend, bool wait_resp)2603{2604struct {2605struct {2606u8 hif_type; /* 0x0: HIF_SDIO2607* 0x1: HIF_USB2608* 0x2: HIF_PCIE2609*/2610u8 pad[3];2611} __packed hdr;2612struct hif_suspend_tlv {2613__le16 tag;2614__le16 len;2615u8 suspend;2616u8 pad[7];2617} __packed hif_suspend;2618} req = {2619.hif_suspend = {2620.tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */2621.len = cpu_to_le16(sizeof(struct hif_suspend_tlv)),2622.suspend = suspend,2623},2624};26252626if (mt76_is_mmio(dev))2627req.hdr.hif_type = 2;2628else if (mt76_is_usb(dev))2629req.hdr.hif_type = 1;2630else if (mt76_is_sdio(dev))2631req.hdr.hif_type = 0;26322633return mt76_mcu_send_msg(dev, MCU_UNI_CMD(HIF_CTRL), &req,2634sizeof(req), wait_resp);2635}2636EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_hif_suspend);26372638void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,2639struct ieee80211_vif *vif)2640{2641struct mt76_phy *phy = priv;2642bool suspend = !test_bit(MT76_STATE_RUNNING, &phy->state);2643struct ieee80211_hw *hw = phy->hw;2644struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config;2645int i;26462647mt76_connac_mcu_set_gtk_rekey(phy->dev, vif, suspend);2648mt76_connac_mcu_set_arp_filter(phy->dev, vif, suspend);26492650mt76_connac_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true);26512652for (i = 0; i < wowlan->n_patterns; i++)2653mt76_connac_mcu_set_wow_pattern(phy->dev, vif, i, suspend,2654&wowlan->patterns[i]);2655mt76_connac_mcu_set_wow_ctrl(phy, vif, suspend, wowlan);2656}2657EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter);2658#endif /* CONFIG_PM */26592660u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset)2661{2662struct {2663__le32 addr;2664__le32 val;2665} __packed req = {2666.addr = cpu_to_le32(offset),2667};26682669return mt76_mcu_send_msg(dev, MCU_CE_QUERY(REG_READ), &req,2670sizeof(req), true);2671}2672EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_rr);26732674void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val)2675{2676struct {2677__le32 addr;2678__le32 val;2679} __packed req = {2680.addr = cpu_to_le32(offset),2681.val = cpu_to_le32(val),2682};26832684mt76_mcu_send_msg(dev, MCU_CE_CMD(REG_WRITE), &req,2685sizeof(req), false);2686}2687EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_wr);26882689static int2690mt76_connac_mcu_sta_key_tlv(struct mt76_connac_sta_key_conf *sta_key_conf,2691struct sk_buff *skb,2692struct ieee80211_key_conf *key,2693enum set_key_cmd cmd)2694{2695struct sta_rec_sec *sec;2696u32 len = sizeof(*sec);2697struct tlv *tlv;26982699tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));2700sec = (struct sta_rec_sec *)tlv;2701sec->add = cmd;27022703if (cmd == SET_KEY) {2704struct sec_key *sec_key;2705u8 cipher;27062707cipher = mt76_connac_mcu_get_cipher(key->cipher);2708if (cipher == MCU_CIPHER_NONE)2709return -EOPNOTSUPP;27102711sec_key = &sec->key[0];2712sec_key->cipher_len = sizeof(*sec_key);27132714if (cipher == MCU_CIPHER_BIP_CMAC_128) {2715sec_key->cipher_id = MCU_CIPHER_AES_CCMP;2716sec_key->key_id = sta_key_conf->keyidx;2717sec_key->key_len = 16;2718memcpy(sec_key->key, sta_key_conf->key, 16);27192720sec_key = &sec->key[1];2721sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128;2722sec_key->cipher_len = sizeof(*sec_key);2723sec_key->key_len = 16;2724memcpy(sec_key->key, key->key, 16);2725sec->n_cipher = 2;2726} else {2727sec_key->cipher_id = cipher;2728sec_key->key_id = key->keyidx;2729sec_key->key_len = key->keylen;2730memcpy(sec_key->key, key->key, key->keylen);27312732if (cipher == MCU_CIPHER_TKIP) {2733/* Rx/Tx MIC keys are swapped */2734memcpy(sec_key->key + 16, key->key + 24, 8);2735memcpy(sec_key->key + 24, key->key + 16, 8);2736}27372738/* store key_conf for BIP batch update */2739if (cipher == MCU_CIPHER_AES_CCMP) {2740memcpy(sta_key_conf->key, key->key, key->keylen);2741sta_key_conf->keyidx = key->keyidx;2742}27432744len -= sizeof(*sec_key);2745sec->n_cipher = 1;2746}2747} else {2748len -= sizeof(sec->key);2749sec->n_cipher = 0;2750}2751sec->len = cpu_to_le16(len);27522753return 0;2754}27552756int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,2757struct mt76_connac_sta_key_conf *sta_key_conf,2758struct ieee80211_key_conf *key, int mcu_cmd,2759struct mt76_wcid *wcid, enum set_key_cmd cmd)2760{2761struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2762struct sk_buff *skb;2763int ret;27642765skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);2766if (IS_ERR(skb))2767return PTR_ERR(skb);27682769ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd);2770if (ret)2771return ret;27722773ret = mt76_connac_mcu_sta_wed_update(dev, skb);2774if (ret)2775return ret;27762777return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);2778}2779EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_key);27802781/* SIFS 20us + 512 byte beacon transmitted by 1Mbps (3906us) */2782#define BCN_TX_ESTIMATE_TIME (4096 + 20)2783void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif_link *mvif)2784{2785struct bss_info_ext_bss *ext;2786int ext_bss_idx, tsf_offset;2787struct tlv *tlv;27882789ext_bss_idx = mvif->omac_idx - EXT_BSSID_START;2790if (ext_bss_idx < 0)2791return;27922793tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext));27942795ext = (struct bss_info_ext_bss *)tlv;2796tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;2797ext->mbss_tsf_offset = cpu_to_le32(tsf_offset);2798}2799EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_ext_tlv);28002801int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb,2802struct ieee80211_vif *vif,2803struct ieee80211_sta *sta,2804struct mt76_phy *phy, u16 wlan_idx,2805bool enable)2806{2807struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2808u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA;2809struct bss_info_basic *bss;2810struct tlv *tlv;28112812tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss));2813bss = (struct bss_info_basic *)tlv;28142815switch (vif->type) {2816case NL80211_IFTYPE_MESH_POINT:2817case NL80211_IFTYPE_MONITOR:2818break;2819case NL80211_IFTYPE_AP:2820if (ieee80211_hw_check(phy->hw, SUPPORTS_MULTI_BSSID)) {2821u8 bssid_id = vif->bss_conf.bssid_indicator;2822struct wiphy *wiphy = phy->hw->wiphy;28232824if (bssid_id > ilog2(wiphy->mbssid_max_interfaces))2825return -EINVAL;28262827bss->non_tx_bssid = vif->bss_conf.bssid_index;2828bss->max_bssid = bssid_id;2829}2830break;2831case NL80211_IFTYPE_STATION:2832if (enable) {2833rcu_read_lock();2834if (!sta)2835sta = ieee80211_find_sta(vif,2836vif->bss_conf.bssid);2837/* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */2838if (sta) {2839struct mt76_wcid *wcid;28402841wcid = (struct mt76_wcid *)sta->drv_priv;2842wlan_idx = wcid->idx;2843}2844rcu_read_unlock();2845}2846break;2847case NL80211_IFTYPE_ADHOC:2848type = NETWORK_IBSS;2849break;2850default:2851WARN_ON(1);2852break;2853}28542855bss->network_type = cpu_to_le32(type);2856bss->bmc_wcid_lo = to_wcid_lo(wlan_idx);2857bss->bmc_wcid_hi = to_wcid_hi(wlan_idx);2858bss->wmm_idx = mvif->wmm_idx;2859bss->active = enable;2860bss->cipher = mvif->cipher;28612862if (vif->type != NL80211_IFTYPE_MONITOR) {2863struct cfg80211_chan_def *chandef = &phy->chandef;28642865memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);2866bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);2867bss->dtim_period = vif->bss_conf.dtim_period;2868bss->phy_mode = mt76_connac_get_phy_mode(phy, vif,2869chandef->chan->band, NULL);2870} else {2871memcpy(bss->bssid, phy->macaddr, ETH_ALEN);2872}28732874return 0;2875}2876EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_basic_tlv);28772878#define ENTER_PM_STATE 12879#define EXIT_PM_STATE 22880int mt76_connac_mcu_set_pm(struct mt76_dev *dev, int band, int enter)2881{2882struct {2883u8 pm_number;2884u8 pm_state;2885u8 bssid[ETH_ALEN];2886u8 dtim_period;2887u8 wlan_idx_lo;2888__le16 bcn_interval;2889__le32 aid;2890__le32 rx_filter;2891u8 band_idx;2892u8 wlan_idx_hi;2893u8 rsv[2];2894__le32 feature;2895u8 omac_idx;2896u8 wmm_idx;2897u8 bcn_loss_cnt;2898u8 bcn_sp_duration;2899} __packed req = {2900.pm_number = 5,2901.pm_state = enter ? ENTER_PM_STATE : EXIT_PM_STATE,2902.band_idx = band,2903};29042905return mt76_mcu_send_msg(dev, MCU_EXT_CMD(PM_STATE_CTRL), &req,2906sizeof(req), true);2907}2908EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_pm);29092910int mt76_connac_mcu_restart(struct mt76_dev *dev)2911{2912struct {2913u8 power_mode;2914u8 rsv[3];2915} req = {2916.power_mode = 1,2917};29182919return mt76_mcu_send_msg(dev, MCU_CMD(NIC_POWER_CTRL), &req,2920sizeof(req), false);2921}2922EXPORT_SYMBOL_GPL(mt76_connac_mcu_restart);29232924int mt76_connac_mcu_del_wtbl_all(struct mt76_dev *dev)2925{2926struct wtbl_req_hdr req = {2927.operation = WTBL_RESET_ALL,2928};29292930return mt76_mcu_send_msg(dev, MCU_EXT_CMD(WTBL_UPDATE),2931&req, sizeof(req), true);2932}2933EXPORT_SYMBOL_GPL(mt76_connac_mcu_del_wtbl_all);29342935int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index,2936u8 rx_sel, u8 val)2937{2938struct {2939u8 ctrl;2940u8 rdd_idx;2941u8 rdd_rx_sel;2942u8 val;2943u8 rsv[4];2944} __packed req = {2945.ctrl = cmd,2946.rdd_idx = index,2947.rdd_rx_sel = rx_sel,2948.val = val,2949};29502951return mt76_mcu_send_msg(dev, MCU_EXT_CMD(SET_RDD_CTRL), &req,2952sizeof(req), true);2953}2954EXPORT_SYMBOL_GPL(mt76_connac_mcu_rdd_cmd);29552956static int2957mt76_connac_mcu_send_ram_firmware(struct mt76_dev *dev,2958const struct mt76_connac2_fw_trailer *hdr,2959const u8 *data, bool is_wa)2960{2961int i, offset = 0, max_len = mt76_is_sdio(dev) ? 2048 : 4096;2962u32 override = 0, option = 0;29632964for (i = 0; i < hdr->n_region; i++) {2965const struct mt76_connac2_fw_region *region;2966u32 len, addr, mode;2967int err;29682969region = (const void *)((const u8 *)hdr -2970(hdr->n_region - i) * sizeof(*region));2971mode = mt76_connac_mcu_gen_dl_mode(dev, region->feature_set,2972is_wa);2973len = le32_to_cpu(region->len);2974addr = le32_to_cpu(region->addr);29752976if (region->feature_set & FW_FEATURE_NON_DL)2977goto next;29782979if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR)2980override = addr;29812982err = mt76_connac_mcu_init_download(dev, addr, len, mode);2983if (err) {2984dev_err(dev->dev, "Download request failed\n");2985return err;2986}29872988err = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER),2989data + offset, len, max_len);2990if (err) {2991dev_err(dev->dev, "Failed to send firmware.\n");2992return err;2993}29942995next:2996offset += len;2997}29982999if (override)3000option |= FW_START_OVERRIDE;3001if (is_wa)3002option |= FW_START_WORKING_PDA_CR4;30033004return mt76_connac_mcu_start_firmware(dev, override, option);3005}30063007int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,3008const char *fw_wa)3009{3010const struct mt76_connac2_fw_trailer *hdr;3011const struct firmware *fw;3012int ret;30133014ret = request_firmware(&fw, fw_wm, dev->dev);3015if (ret)3016return ret;30173018if (!fw || !fw->data || fw->size < sizeof(*hdr)) {3019dev_err(dev->dev, "Invalid firmware\n");3020ret = -EINVAL;3021goto out;3022}30233024hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));3025dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s",3026hdr->fw_ver, hdr->build_date);30273028ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false);3029if (ret) {3030dev_err(dev->dev, "Failed to start WM firmware\n");3031goto out;3032}30333034snprintf(dev->hw->wiphy->fw_version,3035sizeof(dev->hw->wiphy->fw_version),3036"%.10s-%.15s", hdr->fw_ver, hdr->build_date);30373038release_firmware(fw);30393040if (!fw_wa)3041return 0;30423043ret = request_firmware(&fw, fw_wa, dev->dev);3044if (ret)3045return ret;30463047if (!fw || !fw->data || fw->size < sizeof(*hdr)) {3048dev_err(dev->dev, "Invalid firmware\n");3049ret = -EINVAL;3050goto out;3051}30523053hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));3054dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s",3055hdr->fw_ver, hdr->build_date);30563057ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true);3058if (ret) {3059dev_err(dev->dev, "Failed to start WA firmware\n");3060goto out;3061}30623063snprintf(dev->hw->wiphy->fw_version,3064sizeof(dev->hw->wiphy->fw_version),3065"%.10s-%.15s", hdr->fw_ver, hdr->build_date);30663067out:3068release_firmware(fw);30693070return ret;3071}3072EXPORT_SYMBOL_GPL(mt76_connac2_load_ram);30733074static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info)3075{3076u32 mode = DL_MODE_NEED_RSP;30773078if ((!is_mt7921(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT)3079return mode;30803081switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) {3082case PATCH_SEC_ENC_TYPE_PLAIN:3083break;3084case PATCH_SEC_ENC_TYPE_AES:3085mode |= DL_MODE_ENCRYPT;3086mode |= FIELD_PREP(DL_MODE_KEY_IDX,3087(info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX;3088mode |= DL_MODE_RESET_SEC_IV;3089break;3090case PATCH_SEC_ENC_TYPE_SCRAMBLE:3091mode |= DL_MODE_ENCRYPT;3092mode |= DL_CONFIG_ENCRY_MODE_SEL;3093mode |= DL_MODE_RESET_SEC_IV;3094break;3095default:3096dev_err(dev->dev, "Encryption type not support!\n");3097}30983099return mode;3100}31013102int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)3103{3104int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096;3105const struct mt76_connac2_patch_hdr *hdr;3106const struct firmware *fw = NULL;31073108sem = mt76_connac_mcu_patch_sem_ctrl(dev, true);3109switch (sem) {3110case PATCH_IS_DL:3111return 0;3112case PATCH_NOT_DL_SEM_SUCCESS:3113break;3114default:3115dev_err(dev->dev, "Failed to get patch semaphore\n");3116return -EAGAIN;3117}31183119ret = request_firmware(&fw, fw_name, dev->dev);3120if (ret)3121goto out;31223123if (!fw || !fw->data || fw->size < sizeof(*hdr)) {3124dev_err(dev->dev, "Invalid firmware\n");3125ret = -EINVAL;3126goto out;3127}31283129hdr = (const void *)fw->data;3130dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s",3131be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);31323133for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {3134#if defined(__linux__)3135struct mt76_connac2_patch_sec *sec;3136#elif defined(__FreeBSD__)3137const struct mt76_connac2_patch_sec *sec;3138#endif3139u32 len, addr, mode;3140const u8 *dl;3141u32 sec_info;31423143#if defined(__linux__)3144sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec));3145#elif defined(__FreeBSD__)3146sec = (const void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec));3147#endif3148if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) !=3149PATCH_SEC_TYPE_INFO) {3150ret = -EINVAL;3151goto out;3152}31533154addr = be32_to_cpu(sec->info.addr);3155len = be32_to_cpu(sec->info.len);3156dl = fw->data + be32_to_cpu(sec->offs);3157sec_info = be32_to_cpu(sec->info.sec_key_idx);3158mode = mt76_connac2_get_data_mode(dev, sec_info);31593160ret = mt76_connac_mcu_init_download(dev, addr, len, mode);3161if (ret) {3162dev_err(dev->dev, "Download request failed\n");3163goto out;3164}31653166ret = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER),3167dl, len, max_len);3168if (ret) {3169dev_err(dev->dev, "Failed to send patch\n");3170goto out;3171}3172}31733174ret = mt76_connac_mcu_start_patch(dev);3175if (ret)3176dev_err(dev->dev, "Failed to start patch\n");31773178out:3179sem = mt76_connac_mcu_patch_sem_ctrl(dev, false);3180switch (sem) {3181case PATCH_REL_SEM_SUCCESS:3182break;3183default:3184ret = -EAGAIN;3185dev_err(dev->dev, "Failed to release patch semaphore\n");3186break;3187}31883189release_firmware(fw);31903191return ret;3192}3193EXPORT_SYMBOL_GPL(mt76_connac2_load_patch);31943195int mt76_connac2_mcu_fill_message(struct mt76_dev *dev, struct sk_buff *skb,3196int cmd, int *wait_seq)3197{3198int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);3199struct mt76_connac2_mcu_uni_txd *uni_txd;3200struct mt76_connac2_mcu_txd *mcu_txd;3201__le32 *txd;3202u32 val;3203u8 seq;32043205/* TODO: make dynamic based on msg type */3206dev->mcu.timeout = 20 * HZ;32073208seq = ++dev->mcu.msg_seq & 0xf;3209if (!seq)3210seq = ++dev->mcu.msg_seq & 0xf;32113212if (cmd == MCU_CMD(FW_SCATTER))3213goto exit;32143215txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);3216txd = (__le32 *)skb_push(skb, txd_len);32173218val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |3219FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) |3220FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0);3221txd[0] = cpu_to_le32(val);32223223val = MT_TXD1_LONG_FORMAT |3224FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD);3225txd[1] = cpu_to_le32(val);32263227if (cmd & __MCU_CMD_FIELD_UNI) {3228uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd;3229uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));3230uni_txd->option = MCU_CMD_UNI_EXT_ACK;3231uni_txd->cid = cpu_to_le16(mcu_cmd);3232uni_txd->s2d_index = MCU_S2D_H2N;3233uni_txd->pkt_type = MCU_PKT_ID;3234uni_txd->seq = seq;32353236goto exit;3237}32383239mcu_txd = (struct mt76_connac2_mcu_txd *)txd;3240mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));3241mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU,3242MT_TX_MCU_PORT_RX_Q0));3243mcu_txd->pkt_type = MCU_PKT_ID;3244mcu_txd->seq = seq;3245mcu_txd->cid = mcu_cmd;3246mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);32473248if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {3249if (cmd & __MCU_CMD_FIELD_QUERY)3250mcu_txd->set_query = MCU_Q_QUERY;3251else3252mcu_txd->set_query = MCU_Q_SET;3253mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;3254} else {3255mcu_txd->set_query = MCU_Q_NA;3256}32573258if (cmd & __MCU_CMD_FIELD_WA)3259mcu_txd->s2d_index = MCU_S2D_H2C;3260else3261mcu_txd->s2d_index = MCU_S2D_H2N;32623263exit:3264if (wait_seq)3265*wait_seq = seq;32663267return 0;3268}3269EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message);32703271MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");3272MODULE_DESCRIPTION("MediaTek MT76x connac layer helpers");3273MODULE_LICENSE("Dual BSD/GPL");327432753276