Path: blob/main/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c
48378 views
// SPDX-License-Identifier: ISC1/* 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}16631664return mt76_connac_mcu_uni_set_chctx(phy, mvif, ctx);1665}1666EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss);16671668void mt76_connac_mcu_build_rnr_scan_param(struct mt76_dev *mdev,1669struct cfg80211_scan_request *sreq)1670{1671struct ieee80211_channel **scan_list = sreq->channels;1672int i, bssid_index = 0;16731674/* clear 6G active Scan BSSID table */1675memset(&mdev->rnr, 0, sizeof(mdev->rnr));16761677for (i = 0; i < sreq->n_6ghz_params; i++) {1678u8 ch_idx = sreq->scan_6ghz_params[i].channel_idx;1679int k = 0;16801681/* Remove the duplicated BSSID */1682for (k = 0; k < bssid_index; k++) {1683if (!memcmp(&mdev->rnr.bssid[k],1684sreq->scan_6ghz_params[i].bssid,1685ETH_ALEN))1686break;1687}16881689if (k == bssid_index &&1690bssid_index < MT76_RNR_SCAN_MAX_BSSIDS) {1691memcpy(&mdev->rnr.bssid[bssid_index++],1692sreq->scan_6ghz_params[i].bssid, ETH_ALEN);1693mdev->rnr.channel[k] = scan_list[ch_idx]->hw_value;1694}1695}16961697mdev->rnr.bssid_num = bssid_index;16981699if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {1700memcpy(mdev->rnr.random_mac, sreq->mac_addr, ETH_ALEN);1701mdev->rnr.sreq_flag = sreq->flags;1702}1703}1704EXPORT_SYMBOL_GPL(mt76_connac_mcu_build_rnr_scan_param);17051706#define MT76_CONNAC_SCAN_CHANNEL_TIME 601707int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,1708struct ieee80211_scan_request *scan_req)1709{1710struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1711struct cfg80211_scan_request *sreq = &scan_req->req;1712int n_ssids = 0, err, i, duration;1713int ext_channels_num = max_t(int, sreq->n_channels - 32, 0);1714struct ieee80211_channel **scan_list = sreq->channels;1715struct mt76_dev *mdev = phy->dev;1716struct mt76_connac_mcu_scan_channel *chan;1717struct mt76_connac_hw_scan_req *req;1718struct sk_buff *skb;17191720if (test_bit(MT76_HW_SCANNING, &phy->state))1721return -EBUSY;17221723skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req));1724if (!skb)1725return -ENOMEM;17261727set_bit(MT76_HW_SCANNING, &phy->state);1728mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;17291730req = (struct mt76_connac_hw_scan_req *)skb_put_zero(skb, sizeof(*req));17311732req->seq_num = mvif->scan_seq_num | mvif->band_idx << 7;1733req->bss_idx = mvif->idx;1734req->scan_type = sreq->n_ssids ? 1 : 0;1735req->probe_req_num = sreq->n_ssids ? 2 : 0;1736req->version = 1;17371738for (i = 0; i < sreq->n_ssids; i++) {1739if (!sreq->ssids[i].ssid_len)1740continue;17411742req->ssids[n_ssids].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);1743memcpy(req->ssids[n_ssids].ssid, sreq->ssids[i].ssid,1744sreq->ssids[i].ssid_len);1745n_ssids++;1746}1747req->ssid_type = n_ssids ? BIT(2) : BIT(0);1748req->ssid_type_ext = n_ssids ? BIT(0) : 0;1749req->ssids_num = n_ssids;17501751duration = is_mt7921(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME;1752/* increase channel time for passive scan */1753if (!sreq->n_ssids)1754duration *= 2;1755req->timeout_value = cpu_to_le16(sreq->n_channels * duration);1756req->channel_min_dwell_time = cpu_to_le16(duration);1757req->channel_dwell_time = cpu_to_le16(duration);17581759if (sreq->n_channels == 0 || sreq->n_channels > 64) {1760req->channel_type = 0;1761req->channels_num = 0;1762req->ext_channels_num = 0;1763} else {1764req->channel_type = 4;1765req->channels_num = min_t(u8, sreq->n_channels, 32);1766req->ext_channels_num = min_t(u8, ext_channels_num, 32);1767}17681769for (i = 0; i < req->channels_num + req->ext_channels_num; i++) {1770if (i >= 32)1771chan = &req->ext_channels[i - 32];1772else1773chan = &req->channels[i];17741775switch (scan_list[i]->band) {1776case NL80211_BAND_2GHZ:1777chan->band = 1;1778break;1779case NL80211_BAND_6GHZ:1780chan->band = 3;1781break;1782default:1783chan->band = 2;1784break;1785}1786chan->channel_num = scan_list[i]->hw_value;1787}17881789if (sreq->ie_len > 0) {1790memcpy(req->ies, sreq->ie, sreq->ie_len);1791req->ies_len = cpu_to_le16(sreq->ie_len);1792}17931794if (is_mt7921(phy->dev))1795req->scan_func |= SCAN_FUNC_SPLIT_SCAN;17961797memcpy(req->bssid, sreq->bssid, ETH_ALEN);1798if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {1799get_random_mask_addr(req->random_mac, sreq->mac_addr,1800sreq->mac_addr_mask);1801req->scan_func |= SCAN_FUNC_RANDOM_MAC;1802}18031804err = mt76_mcu_skb_send_msg(mdev, skb, MCU_CE_CMD(START_HW_SCAN),1805false);1806if (err < 0)1807clear_bit(MT76_HW_SCANNING, &phy->state);18081809return err;1810}1811EXPORT_SYMBOL_GPL(mt76_connac_mcu_hw_scan);18121813int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy,1814struct ieee80211_vif *vif)1815{1816struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1817struct {1818u8 seq_num;1819u8 is_ext_channel;1820u8 rsv[2];1821} __packed req = {1822.seq_num = mvif->scan_seq_num,1823};18241825if (test_and_clear_bit(MT76_HW_SCANNING, &phy->state)) {1826struct cfg80211_scan_info info = {1827.aborted = true,1828};18291830ieee80211_scan_completed(phy->hw, &info);1831}18321833return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(CANCEL_HW_SCAN),1834&req, sizeof(req), false);1835}1836EXPORT_SYMBOL_GPL(mt76_connac_mcu_cancel_hw_scan);18371838int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,1839struct ieee80211_vif *vif,1840struct cfg80211_sched_scan_request *sreq)1841{1842struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;1843struct ieee80211_channel **scan_list = sreq->channels;1844struct mt76_connac_mcu_scan_channel *chan;1845struct mt76_connac_sched_scan_req *req;1846struct mt76_dev *mdev = phy->dev;1847struct cfg80211_match_set *match;1848struct cfg80211_ssid *ssid;1849struct sk_buff *skb;1850int i;18511852skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req) + sreq->ie_len);1853if (!skb)1854return -ENOMEM;18551856mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f;18571858req = (struct mt76_connac_sched_scan_req *)skb_put_zero(skb, sizeof(*req));1859req->version = 1;1860req->seq_num = mvif->scan_seq_num | mvif->band_idx << 7;18611862if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {1863u8 *addr = is_mt7663(phy->dev) ? req->mt7663.random_mac1864: req->mt7921.random_mac;18651866req->scan_func = 1;1867get_random_mask_addr(addr, sreq->mac_addr,1868sreq->mac_addr_mask);1869}1870if (is_mt7921(phy->dev)) {1871req->mt7921.bss_idx = mvif->idx;1872req->mt7921.delay = cpu_to_le32(sreq->delay);1873}18741875req->ssids_num = sreq->n_ssids;1876for (i = 0; i < req->ssids_num; i++) {1877ssid = &sreq->ssids[i];1878memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len);1879req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len);1880}18811882req->match_num = sreq->n_match_sets;1883for (i = 0; i < req->match_num; i++) {1884match = &sreq->match_sets[i];1885memcpy(req->match[i].ssid, match->ssid.ssid,1886match->ssid.ssid_len);1887req->match[i].rssi_th = cpu_to_le32(match->rssi_thold);1888req->match[i].ssid_len = match->ssid.ssid_len;1889}18901891req->channel_type = sreq->n_channels ? 4 : 0;1892req->channels_num = min_t(u8, sreq->n_channels, 64);1893for (i = 0; i < req->channels_num; i++) {1894chan = &req->channels[i];18951896switch (scan_list[i]->band) {1897case NL80211_BAND_2GHZ:1898chan->band = 1;1899break;1900case NL80211_BAND_6GHZ:1901chan->band = 3;1902break;1903default:1904chan->band = 2;1905break;1906}1907chan->channel_num = scan_list[i]->hw_value;1908}19091910req->intervals_num = sreq->n_scan_plans;1911for (i = 0; i < req->intervals_num; i++)1912req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval);19131914if (sreq->ie_len > 0) {1915req->ie_len = cpu_to_le16(sreq->ie_len);1916memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len);1917}19181919return mt76_mcu_skb_send_msg(mdev, skb, MCU_CE_CMD(SCHED_SCAN_REQ),1920false);1921}1922EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_req);19231924int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy,1925struct ieee80211_vif *vif,1926bool enable)1927{1928struct {1929u8 active; /* 0: enabled 1: disabled */1930u8 rsv[3];1931} __packed req = {1932.active = !enable,1933};19341935if (enable)1936set_bit(MT76_HW_SCHED_SCANNING, &phy->state);1937else1938clear_bit(MT76_HW_SCHED_SCANNING, &phy->state);19391940return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(SCHED_SCAN_ENABLE),1941&req, sizeof(req), false);1942}1943EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable);19441945int mt76_connac_mcu_chip_config(struct mt76_dev *dev)1946{1947struct mt76_connac_config req = {1948.resp_type = 0,1949};19501951memcpy(req.data, "assert", 7);19521953return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG),1954&req, sizeof(req), false);1955}1956EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config);19571958int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable)1959{1960struct mt76_connac_config req = {1961.resp_type = 0,1962};19631964snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !enable);19651966return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG),1967&req, sizeof(req), false);1968}1969EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep);19701971int mt76_connac_sta_state_dp(struct mt76_dev *dev,1972enum ieee80211_sta_state old_state,1973enum ieee80211_sta_state new_state)1974{1975if ((old_state == IEEE80211_STA_ASSOC &&1976new_state == IEEE80211_STA_AUTHORIZED) ||1977(old_state == IEEE80211_STA_NONE &&1978new_state == IEEE80211_STA_NOTEXIST))1979mt76_connac_mcu_set_deep_sleep(dev, true);19801981if ((old_state == IEEE80211_STA_NOTEXIST &&1982new_state == IEEE80211_STA_NONE) ||1983(old_state == IEEE80211_STA_AUTHORIZED &&1984new_state == IEEE80211_STA_ASSOC))1985mt76_connac_mcu_set_deep_sleep(dev, false);19861987return 0;1988}1989EXPORT_SYMBOL_GPL(mt76_connac_sta_state_dp);19901991void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,1992struct mt76_connac_coredump *coredump)1993{1994spin_lock_bh(&dev->lock);1995__skb_queue_tail(&coredump->msg_list, skb);1996spin_unlock_bh(&dev->lock);19971998coredump->last_activity = jiffies;19992000queue_delayed_work(dev->wq, &coredump->work,2001MT76_CONNAC_COREDUMP_TIMEOUT);2002}2003EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);20042005static void2006mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,2007struct mt76_power_limits *limits,2008enum nl80211_band band)2009{2010int max_power = is_mt7921(dev) ? 127 : 63;2011int i, offset = sizeof(limits->cck);20122013memset(sku, max_power, MT_SKU_POWER_LIMIT);20142015if (band == NL80211_BAND_2GHZ) {2016/* cck */2017memcpy(sku, limits->cck, sizeof(limits->cck));2018}20192020/* ofdm */2021memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm));2022offset += sizeof(limits->ofdm);20232024/* ht */2025for (i = 0; i < 2; i++) {2026memcpy(&sku[offset], limits->mcs[i], 8);2027offset += 8;2028}2029sku[offset++] = limits->mcs[0][0];20302031/* vht */2032for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) {2033memcpy(&sku[offset], limits->mcs[i],2034ARRAY_SIZE(limits->mcs[i]));2035offset += 12;2036}20372038if (!is_mt7921(dev))2039return;20402041/* he */2042for (i = 0; i < ARRAY_SIZE(limits->ru); i++) {2043memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i]));2044offset += ARRAY_SIZE(limits->ru[i]);2045}2046}20472048s8 mt76_connac_get_ch_power(struct mt76_phy *phy,2049struct ieee80211_channel *chan,2050s8 target_power)2051{2052struct mt76_dev *dev = phy->dev;2053struct ieee80211_supported_band *sband;2054int i;20552056switch (chan->band) {2057case NL80211_BAND_2GHZ:2058sband = &phy->sband_2g.sband;2059break;2060case NL80211_BAND_5GHZ:2061sband = &phy->sband_5g.sband;2062break;2063case NL80211_BAND_6GHZ:2064sband = &phy->sband_6g.sband;2065break;2066default:2067return target_power;2068}20692070for (i = 0; i < sband->n_channels; i++) {2071struct ieee80211_channel *ch = &sband->channels[i];20722073if (ch->hw_value == chan->hw_value) {2074if (!(ch->flags & IEEE80211_CHAN_DISABLED)) {2075int power = 2 * ch->max_reg_power;20762077if (is_mt7663(dev) && (power > 63 || power < -64))2078power = 63;2079target_power = min_t(s8, power, target_power);2080}2081break;2082}2083}20842085return target_power;2086}2087EXPORT_SYMBOL_GPL(mt76_connac_get_ch_power);20882089static int2090mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,2091enum nl80211_band band)2092{2093struct mt76_dev *dev = phy->dev;2094int sku_len, batch_len = is_mt7921(dev) ? 8 : 16;2095static const u8 chan_list_2ghz[] = {20961, 2, 3, 4, 5, 6, 7,20978, 9, 10, 11, 12, 13, 142098};2099static const u8 chan_list_5ghz[] = {210036, 38, 40, 42, 44, 46, 48,210150, 52, 54, 56, 58, 60, 62,210264, 100, 102, 104, 106, 108, 110,2103112, 114, 116, 118, 120, 122, 124,2104126, 128, 132, 134, 136, 138, 140,2105142, 144, 149, 151, 153, 155, 157,2106159, 161, 165, 169, 173, 1772107};2108static const u8 chan_list_6ghz[] = {21091, 3, 5, 7, 9, 11, 13,211015, 17, 19, 21, 23, 25, 27,211129, 33, 35, 37, 39, 41, 43,211245, 47, 49, 51, 53, 55, 57,211359, 61, 65, 67, 69, 71, 73,211475, 77, 79, 81, 83, 85, 87,211589, 91, 93, 97, 99, 101, 103,2116105, 107, 109, 111, 113, 115, 117,2117119, 121, 123, 125, 129, 131, 133,2118135, 137, 139, 141, 143, 145, 147,2119149, 151, 153, 155, 157, 161, 163,2120165, 167, 169, 171, 173, 175, 177,2121179, 181, 183, 185, 187, 189, 193,2122195, 197, 199, 201, 203, 205, 207,2123209, 211, 213, 215, 217, 219, 221,2124225, 227, 229, 2332125};2126int i, n_chan, batch_size, idx = 0, tx_power, last_ch, err = 0;2127struct mt76_connac_sku_tlv sku_tlbv;2128struct mt76_power_limits *limits;2129const u8 *ch_list;21302131limits = devm_kmalloc(dev->dev, sizeof(*limits), GFP_KERNEL);2132if (!limits)2133return -ENOMEM;21342135sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;2136tx_power = 2 * phy->hw->conf.power_level;2137if (!tx_power)2138tx_power = 127;21392140if (band == NL80211_BAND_2GHZ) {2141n_chan = ARRAY_SIZE(chan_list_2ghz);2142ch_list = chan_list_2ghz;2143} else if (band == NL80211_BAND_6GHZ) {2144n_chan = ARRAY_SIZE(chan_list_6ghz);2145ch_list = chan_list_6ghz;2146} else {2147n_chan = ARRAY_SIZE(chan_list_5ghz);2148ch_list = chan_list_5ghz;2149}2150batch_size = DIV_ROUND_UP(n_chan, batch_len);21512152if (phy->cap.has_6ghz)2153last_ch = chan_list_6ghz[ARRAY_SIZE(chan_list_6ghz) - 1];2154else if (phy->cap.has_5ghz)2155last_ch = chan_list_5ghz[ARRAY_SIZE(chan_list_5ghz) - 1];2156else2157last_ch = chan_list_2ghz[ARRAY_SIZE(chan_list_2ghz) - 1];21582159for (i = 0; i < batch_size; i++) {2160struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {};2161int j, msg_len, num_ch;2162struct sk_buff *skb;21632164num_ch = i == batch_size - 1 ? n_chan - i * batch_len : batch_len;2165msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);2166skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);2167if (!skb) {2168err = -ENOMEM;2169goto out;2170}21712172skb_reserve(skb, sizeof(tx_power_tlv));21732174BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));2175memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));2176tx_power_tlv.n_chan = num_ch;21772178switch (band) {2179case NL80211_BAND_2GHZ:2180tx_power_tlv.band = 1;2181break;2182case NL80211_BAND_6GHZ:2183tx_power_tlv.band = 3;2184break;2185default:2186tx_power_tlv.band = 2;2187break;2188}21892190for (j = 0; j < num_ch; j++, idx++) {2191struct ieee80211_channel chan = {2192.hw_value = ch_list[idx],2193.band = band,2194};2195s8 reg_power, sar_power;21962197reg_power = mt76_connac_get_ch_power(phy, &chan,2198tx_power);2199sar_power = mt76_get_sar_power(phy, &chan, reg_power);22002201mt76_get_rate_power_limits(phy, &chan, limits,2202sar_power);22032204tx_power_tlv.last_msg = ch_list[idx] == last_ch;2205sku_tlbv.channel = ch_list[idx];22062207mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,2208limits, band);2209skb_put_data(skb, &sku_tlbv, sku_len);2210}2211__skb_push(skb, sizeof(tx_power_tlv));2212memcpy(skb->data, &tx_power_tlv, sizeof(tx_power_tlv));22132214err = mt76_mcu_skb_send_msg(dev, skb,2215MCU_CE_CMD(SET_RATE_TX_POWER),2216false);2217if (err < 0)2218goto out;2219}22202221out:2222devm_kfree(dev->dev, limits);2223return err;2224}22252226int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)2227{2228int err;22292230if (phy->cap.has_2ghz) {2231err = mt76_connac_mcu_rate_txpower_band(phy,2232NL80211_BAND_2GHZ);2233if (err < 0)2234return err;2235}2236if (phy->cap.has_5ghz) {2237err = mt76_connac_mcu_rate_txpower_band(phy,2238NL80211_BAND_5GHZ);2239if (err < 0)2240return err;2241}2242if (phy->cap.has_6ghz) {2243err = mt76_connac_mcu_rate_txpower_band(phy,2244NL80211_BAND_6GHZ);2245if (err < 0)2246return err;2247}22482249return 0;2250}2251EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);22522253int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev,2254struct mt76_vif_link *vif,2255struct ieee80211_bss_conf *info)2256{2257struct ieee80211_vif *mvif = container_of(info, struct ieee80211_vif,2258bss_conf);2259struct sk_buff *skb;2260int i, len = min_t(int, mvif->cfg.arp_addr_cnt,2261IEEE80211_BSS_ARP_ADDR_LIST_LEN);2262struct {2263struct {2264u8 bss_idx;2265u8 pad[3];2266} __packed hdr;2267struct mt76_connac_arpns_tlv arp;2268} req_hdr = {2269.hdr = {2270.bss_idx = vif->idx,2271},2272.arp = {2273.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),2274.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),2275.ips_num = len,2276.mode = 2, /* update */2277.option = 1,2278},2279};22802281skb = mt76_mcu_msg_alloc(dev, NULL,2282sizeof(req_hdr) + len * sizeof(__be32));2283if (!skb)2284return -ENOMEM;22852286skb_put_data(skb, &req_hdr, sizeof(req_hdr));2287for (i = 0; i < len; i++)2288skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32));22892290return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true);2291}2292EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_arp_filter);22932294int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw,2295struct ieee80211_vif *vif)2296{2297struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2298int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow;2299struct mt76_phy *phy = hw->priv;2300struct {2301__le32 ct_win;2302u8 bss_idx;2303u8 rsv[3];2304} __packed req = {2305.ct_win = cpu_to_le32(ct_window),2306.bss_idx = mvif->idx,2307};23082309return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(SET_P2P_OPPPS),2310&req, sizeof(req), false);2311}2312EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_p2p_oppps);23132314#ifdef CONFIG_PM23152316const struct wiphy_wowlan_support mt76_connac_wowlan_support = {2317.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |2318WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT,2319.n_patterns = 1,2320.pattern_min_len = 1,2321.pattern_max_len = MT76_CONNAC_WOW_PATTEN_MAX_LEN,2322.max_nd_match_sets = 10,2323};2324EXPORT_SYMBOL_GPL(mt76_connac_wowlan_support);23252326static void2327mt76_connac_mcu_key_iter(struct ieee80211_hw *hw,2328struct ieee80211_vif *vif,2329struct ieee80211_sta *sta,2330struct ieee80211_key_conf *key,2331void *data)2332{2333struct mt76_connac_gtk_rekey_tlv *gtk_tlv = data;2334u32 cipher;23352336if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&2337key->cipher != WLAN_CIPHER_SUITE_CCMP &&2338key->cipher != WLAN_CIPHER_SUITE_TKIP)2339return;23402341if (key->cipher == WLAN_CIPHER_SUITE_TKIP)2342cipher = BIT(3);2343else2344cipher = BIT(4);23452346/* we are assuming here to have a single pairwise key */2347if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {2348if (key->cipher == WLAN_CIPHER_SUITE_TKIP)2349gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1);2350else2351gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2);23522353gtk_tlv->pairwise_cipher = cpu_to_le32(cipher);2354gtk_tlv->keyid = key->keyidx;2355} else {2356gtk_tlv->group_cipher = cpu_to_le32(cipher);2357}2358}23592360int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,2361struct ieee80211_vif *vif,2362struct cfg80211_gtk_rekey_data *key)2363{2364struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2365struct mt76_connac_gtk_rekey_tlv *gtk_tlv;2366struct mt76_phy *phy = hw->priv;2367struct sk_buff *skb;2368struct {2369u8 bss_idx;2370u8 pad[3];2371} __packed hdr = {2372.bss_idx = mvif->idx,2373};23742375skb = mt76_mcu_msg_alloc(phy->dev, NULL,2376sizeof(hdr) + sizeof(*gtk_tlv));2377if (!skb)2378return -ENOMEM;23792380skb_put_data(skb, &hdr, sizeof(hdr));2381gtk_tlv = (struct mt76_connac_gtk_rekey_tlv *)skb_put_zero(skb,2382sizeof(*gtk_tlv));2383gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY);2384gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv));2385gtk_tlv->rekey_mode = 2;2386gtk_tlv->option = 1;23872388rcu_read_lock();2389ieee80211_iter_keys_rcu(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv);2390rcu_read_unlock();23912392memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN);2393memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN);2394memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN);23952396return mt76_mcu_skb_send_msg(phy->dev, skb,2397MCU_UNI_CMD(OFFLOAD), true);2398}2399EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_gtk_rekey);24002401static int2402mt76_connac_mcu_set_arp_filter(struct mt76_dev *dev, struct ieee80211_vif *vif,2403bool suspend)2404{2405struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2406struct {2407struct {2408u8 bss_idx;2409u8 pad[3];2410} __packed hdr;2411struct mt76_connac_arpns_tlv arpns;2412} req = {2413.hdr = {2414.bss_idx = mvif->idx,2415},2416.arpns = {2417.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),2418.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),2419.mode = suspend,2420},2421};24222423return mt76_mcu_send_msg(dev, MCU_UNI_CMD(OFFLOAD), &req,2424sizeof(req), true);2425}24262427int2428mt76_connac_mcu_set_gtk_rekey(struct mt76_dev *dev, struct ieee80211_vif *vif,2429bool suspend)2430{2431struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2432struct {2433struct {2434u8 bss_idx;2435u8 pad[3];2436} __packed hdr;2437struct mt76_connac_gtk_rekey_tlv gtk_tlv;2438} __packed req = {2439.hdr = {2440.bss_idx = mvif->idx,2441},2442.gtk_tlv = {2443.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY),2444.len = cpu_to_le16(sizeof(struct mt76_connac_gtk_rekey_tlv)),2445.rekey_mode = !suspend,2446},2447};24482449return mt76_mcu_send_msg(dev, MCU_UNI_CMD(OFFLOAD), &req,2450sizeof(req), true);2451}2452EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_gtk_rekey);24532454int2455mt76_connac_mcu_set_suspend_mode(struct mt76_dev *dev,2456struct ieee80211_vif *vif,2457bool enable, u8 mdtim,2458bool wow_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_suspend_tlv suspend_tlv;2467} req = {2468.hdr = {2469.bss_idx = mvif->idx,2470},2471.suspend_tlv = {2472.tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING),2473.len = cpu_to_le16(sizeof(struct mt76_connac_suspend_tlv)),2474.enable = enable,2475.mdtim = mdtim,2476.wow_suspend = wow_suspend,2477},2478};24792480return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req,2481sizeof(req), true);2482}2483EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_mode);24842485static int2486mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev,2487struct ieee80211_vif *vif,2488u8 index, bool enable,2489struct cfg80211_pkt_pattern *pattern)2490{2491struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2492struct mt76_connac_wow_pattern_tlv *ptlv;2493struct sk_buff *skb;2494struct req_hdr {2495u8 bss_idx;2496u8 pad[3];2497} __packed hdr = {2498.bss_idx = mvif->idx,2499};25002501skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*ptlv));2502if (!skb)2503return -ENOMEM;25042505skb_put_data(skb, &hdr, sizeof(hdr));2506ptlv = (struct mt76_connac_wow_pattern_tlv *)skb_put_zero(skb, sizeof(*ptlv));2507ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN);2508ptlv->len = cpu_to_le16(sizeof(*ptlv));2509ptlv->data_len = pattern->pattern_len;2510ptlv->enable = enable;2511ptlv->index = index;25122513memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len);2514memcpy(ptlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8));25152516return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SUSPEND), true);2517}25182519int2520mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,2521bool suspend, struct cfg80211_wowlan *wowlan)2522{2523struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2524struct mt76_dev *dev = phy->dev;2525struct {2526struct {2527u8 bss_idx;2528u8 pad[3];2529} __packed hdr;2530struct mt76_connac_wow_ctrl_tlv wow_ctrl_tlv;2531struct mt76_connac_wow_gpio_param_tlv gpio_tlv;2532} req = {2533.hdr = {2534.bss_idx = mvif->idx,2535},2536.wow_ctrl_tlv = {2537.tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL),2538.len = cpu_to_le16(sizeof(struct mt76_connac_wow_ctrl_tlv)),2539.cmd = suspend ? 1 : 2,2540},2541.gpio_tlv = {2542.tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM),2543.len = cpu_to_le16(sizeof(struct mt76_connac_wow_gpio_param_tlv)),2544.gpio_pin = 0xff, /* follow fw about GPIO pin */2545},2546};25472548if (wowlan->magic_pkt)2549req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC;2550if (wowlan->disconnect)2551req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT |2552UNI_WOW_DETECT_TYPE_BCN_LOST);2553if (wowlan->nd_config) {2554mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config);2555req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT;2556mt76_connac_mcu_sched_scan_enable(phy, vif, suspend);2557}2558if (wowlan->n_patterns)2559req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP;25602561if (mt76_is_mmio(dev))2562req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE;2563else if (mt76_is_usb(dev))2564req.wow_ctrl_tlv.wakeup_hif = WOW_USB;2565else if (mt76_is_sdio(dev))2566req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO;25672568return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req,2569sizeof(req), true);2570}2571EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_wow_ctrl);25722573int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend, bool wait_resp)2574{2575struct {2576struct {2577u8 hif_type; /* 0x0: HIF_SDIO2578* 0x1: HIF_USB2579* 0x2: HIF_PCIE2580*/2581u8 pad[3];2582} __packed hdr;2583struct hif_suspend_tlv {2584__le16 tag;2585__le16 len;2586u8 suspend;2587u8 pad[7];2588} __packed hif_suspend;2589} req = {2590.hif_suspend = {2591.tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */2592.len = cpu_to_le16(sizeof(struct hif_suspend_tlv)),2593.suspend = suspend,2594},2595};25962597if (mt76_is_mmio(dev))2598req.hdr.hif_type = 2;2599else if (mt76_is_usb(dev))2600req.hdr.hif_type = 1;2601else if (mt76_is_sdio(dev))2602req.hdr.hif_type = 0;26032604return mt76_mcu_send_msg(dev, MCU_UNI_CMD(HIF_CTRL), &req,2605sizeof(req), wait_resp);2606}2607EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_hif_suspend);26082609void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,2610struct ieee80211_vif *vif)2611{2612struct mt76_phy *phy = priv;2613bool suspend = !test_bit(MT76_STATE_RUNNING, &phy->state);2614struct ieee80211_hw *hw = phy->hw;2615struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config;2616int i;26172618mt76_connac_mcu_set_gtk_rekey(phy->dev, vif, suspend);2619mt76_connac_mcu_set_arp_filter(phy->dev, vif, suspend);26202621mt76_connac_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true);26222623for (i = 0; i < wowlan->n_patterns; i++)2624mt76_connac_mcu_set_wow_pattern(phy->dev, vif, i, suspend,2625&wowlan->patterns[i]);2626mt76_connac_mcu_set_wow_ctrl(phy, vif, suspend, wowlan);2627}2628EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter);2629#endif /* CONFIG_PM */26302631u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset)2632{2633struct {2634__le32 addr;2635__le32 val;2636} __packed req = {2637.addr = cpu_to_le32(offset),2638};26392640return mt76_mcu_send_msg(dev, MCU_CE_QUERY(REG_READ), &req,2641sizeof(req), true);2642}2643EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_rr);26442645void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val)2646{2647struct {2648__le32 addr;2649__le32 val;2650} __packed req = {2651.addr = cpu_to_le32(offset),2652.val = cpu_to_le32(val),2653};26542655mt76_mcu_send_msg(dev, MCU_CE_CMD(REG_WRITE), &req,2656sizeof(req), false);2657}2658EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_wr);26592660static int2661mt76_connac_mcu_sta_key_tlv(struct mt76_connac_sta_key_conf *sta_key_conf,2662struct sk_buff *skb,2663struct ieee80211_key_conf *key,2664enum set_key_cmd cmd)2665{2666struct sta_rec_sec *sec;2667u32 len = sizeof(*sec);2668struct tlv *tlv;26692670tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));2671sec = (struct sta_rec_sec *)tlv;2672sec->add = cmd;26732674if (cmd == SET_KEY) {2675struct sec_key *sec_key;2676u8 cipher;26772678cipher = mt76_connac_mcu_get_cipher(key->cipher);2679if (cipher == MCU_CIPHER_NONE)2680return -EOPNOTSUPP;26812682sec_key = &sec->key[0];2683sec_key->cipher_len = sizeof(*sec_key);26842685if (cipher == MCU_CIPHER_BIP_CMAC_128) {2686sec_key->cipher_id = MCU_CIPHER_AES_CCMP;2687sec_key->key_id = sta_key_conf->keyidx;2688sec_key->key_len = 16;2689memcpy(sec_key->key, sta_key_conf->key, 16);26902691sec_key = &sec->key[1];2692sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128;2693sec_key->cipher_len = sizeof(*sec_key);2694sec_key->key_len = 16;2695memcpy(sec_key->key, key->key, 16);2696sec->n_cipher = 2;2697} else {2698sec_key->cipher_id = cipher;2699sec_key->key_id = key->keyidx;2700sec_key->key_len = key->keylen;2701memcpy(sec_key->key, key->key, key->keylen);27022703if (cipher == MCU_CIPHER_TKIP) {2704/* Rx/Tx MIC keys are swapped */2705memcpy(sec_key->key + 16, key->key + 24, 8);2706memcpy(sec_key->key + 24, key->key + 16, 8);2707}27082709/* store key_conf for BIP batch update */2710if (cipher == MCU_CIPHER_AES_CCMP) {2711memcpy(sta_key_conf->key, key->key, key->keylen);2712sta_key_conf->keyidx = key->keyidx;2713}27142715len -= sizeof(*sec_key);2716sec->n_cipher = 1;2717}2718} else {2719len -= sizeof(sec->key);2720sec->n_cipher = 0;2721}2722sec->len = cpu_to_le16(len);27232724return 0;2725}27262727int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,2728struct mt76_connac_sta_key_conf *sta_key_conf,2729struct ieee80211_key_conf *key, int mcu_cmd,2730struct mt76_wcid *wcid, enum set_key_cmd cmd)2731{2732struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2733struct sk_buff *skb;2734int ret;27352736skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);2737if (IS_ERR(skb))2738return PTR_ERR(skb);27392740ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd);2741if (ret)2742return ret;27432744ret = mt76_connac_mcu_sta_wed_update(dev, skb);2745if (ret)2746return ret;27472748return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);2749}2750EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_key);27512752/* SIFS 20us + 512 byte beacon transmitted by 1Mbps (3906us) */2753#define BCN_TX_ESTIMATE_TIME (4096 + 20)2754void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif_link *mvif)2755{2756struct bss_info_ext_bss *ext;2757int ext_bss_idx, tsf_offset;2758struct tlv *tlv;27592760ext_bss_idx = mvif->omac_idx - EXT_BSSID_START;2761if (ext_bss_idx < 0)2762return;27632764tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext));27652766ext = (struct bss_info_ext_bss *)tlv;2767tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;2768ext->mbss_tsf_offset = cpu_to_le32(tsf_offset);2769}2770EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_ext_tlv);27712772int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb,2773struct ieee80211_vif *vif,2774struct ieee80211_sta *sta,2775struct mt76_phy *phy, u16 wlan_idx,2776bool enable)2777{2778struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;2779u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA;2780struct bss_info_basic *bss;2781struct tlv *tlv;27822783tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss));2784bss = (struct bss_info_basic *)tlv;27852786switch (vif->type) {2787case NL80211_IFTYPE_MESH_POINT:2788case NL80211_IFTYPE_MONITOR:2789break;2790case NL80211_IFTYPE_AP:2791if (ieee80211_hw_check(phy->hw, SUPPORTS_MULTI_BSSID)) {2792u8 bssid_id = vif->bss_conf.bssid_indicator;2793struct wiphy *wiphy = phy->hw->wiphy;27942795if (bssid_id > ilog2(wiphy->mbssid_max_interfaces))2796return -EINVAL;27972798bss->non_tx_bssid = vif->bss_conf.bssid_index;2799bss->max_bssid = bssid_id;2800}2801break;2802case NL80211_IFTYPE_STATION:2803if (enable) {2804rcu_read_lock();2805if (!sta)2806sta = ieee80211_find_sta(vif,2807vif->bss_conf.bssid);2808/* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */2809if (sta) {2810struct mt76_wcid *wcid;28112812wcid = (struct mt76_wcid *)sta->drv_priv;2813wlan_idx = wcid->idx;2814}2815rcu_read_unlock();2816}2817break;2818case NL80211_IFTYPE_ADHOC:2819type = NETWORK_IBSS;2820break;2821default:2822WARN_ON(1);2823break;2824}28252826bss->network_type = cpu_to_le32(type);2827bss->bmc_wcid_lo = to_wcid_lo(wlan_idx);2828bss->bmc_wcid_hi = to_wcid_hi(wlan_idx);2829bss->wmm_idx = mvif->wmm_idx;2830bss->active = enable;2831bss->cipher = mvif->cipher;28322833if (vif->type != NL80211_IFTYPE_MONITOR) {2834struct cfg80211_chan_def *chandef = &phy->chandef;28352836memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);2837bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);2838bss->dtim_period = vif->bss_conf.dtim_period;2839bss->phy_mode = mt76_connac_get_phy_mode(phy, vif,2840chandef->chan->band, NULL);2841} else {2842memcpy(bss->bssid, phy->macaddr, ETH_ALEN);2843}28442845return 0;2846}2847EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_basic_tlv);28482849#define ENTER_PM_STATE 12850#define EXIT_PM_STATE 22851int mt76_connac_mcu_set_pm(struct mt76_dev *dev, int band, int enter)2852{2853struct {2854u8 pm_number;2855u8 pm_state;2856u8 bssid[ETH_ALEN];2857u8 dtim_period;2858u8 wlan_idx_lo;2859__le16 bcn_interval;2860__le32 aid;2861__le32 rx_filter;2862u8 band_idx;2863u8 wlan_idx_hi;2864u8 rsv[2];2865__le32 feature;2866u8 omac_idx;2867u8 wmm_idx;2868u8 bcn_loss_cnt;2869u8 bcn_sp_duration;2870} __packed req = {2871.pm_number = 5,2872.pm_state = enter ? ENTER_PM_STATE : EXIT_PM_STATE,2873.band_idx = band,2874};28752876return mt76_mcu_send_msg(dev, MCU_EXT_CMD(PM_STATE_CTRL), &req,2877sizeof(req), true);2878}2879EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_pm);28802881int mt76_connac_mcu_restart(struct mt76_dev *dev)2882{2883struct {2884u8 power_mode;2885u8 rsv[3];2886} req = {2887.power_mode = 1,2888};28892890return mt76_mcu_send_msg(dev, MCU_CMD(NIC_POWER_CTRL), &req,2891sizeof(req), false);2892}2893EXPORT_SYMBOL_GPL(mt76_connac_mcu_restart);28942895int mt76_connac_mcu_del_wtbl_all(struct mt76_dev *dev)2896{2897struct wtbl_req_hdr req = {2898.operation = WTBL_RESET_ALL,2899};29002901return mt76_mcu_send_msg(dev, MCU_EXT_CMD(WTBL_UPDATE),2902&req, sizeof(req), true);2903}2904EXPORT_SYMBOL_GPL(mt76_connac_mcu_del_wtbl_all);29052906int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index,2907u8 rx_sel, u8 val)2908{2909struct {2910u8 ctrl;2911u8 rdd_idx;2912u8 rdd_rx_sel;2913u8 val;2914u8 rsv[4];2915} __packed req = {2916.ctrl = cmd,2917.rdd_idx = index,2918.rdd_rx_sel = rx_sel,2919.val = val,2920};29212922return mt76_mcu_send_msg(dev, MCU_EXT_CMD(SET_RDD_CTRL), &req,2923sizeof(req), true);2924}2925EXPORT_SYMBOL_GPL(mt76_connac_mcu_rdd_cmd);29262927static int2928mt76_connac_mcu_send_ram_firmware(struct mt76_dev *dev,2929const struct mt76_connac2_fw_trailer *hdr,2930const u8 *data, bool is_wa)2931{2932int i, offset = 0, max_len = mt76_is_sdio(dev) ? 2048 : 4096;2933u32 override = 0, option = 0;29342935for (i = 0; i < hdr->n_region; i++) {2936const struct mt76_connac2_fw_region *region;2937u32 len, addr, mode;2938int err;29392940region = (const void *)((const u8 *)hdr -2941(hdr->n_region - i) * sizeof(*region));2942mode = mt76_connac_mcu_gen_dl_mode(dev, region->feature_set,2943is_wa);2944len = le32_to_cpu(region->len);2945addr = le32_to_cpu(region->addr);29462947if (region->feature_set & FW_FEATURE_NON_DL)2948goto next;29492950if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR)2951override = addr;29522953err = mt76_connac_mcu_init_download(dev, addr, len, mode);2954if (err) {2955dev_err(dev->dev, "Download request failed\n");2956return err;2957}29582959err = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER),2960data + offset, len, max_len);2961if (err) {2962dev_err(dev->dev, "Failed to send firmware.\n");2963return err;2964}29652966next:2967offset += len;2968}29692970if (override)2971option |= FW_START_OVERRIDE;2972if (is_wa)2973option |= FW_START_WORKING_PDA_CR4;29742975return mt76_connac_mcu_start_firmware(dev, override, option);2976}29772978int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,2979const char *fw_wa)2980{2981const struct mt76_connac2_fw_trailer *hdr;2982const struct firmware *fw;2983int ret;29842985ret = request_firmware(&fw, fw_wm, dev->dev);2986if (ret)2987return ret;29882989if (!fw || !fw->data || fw->size < sizeof(*hdr)) {2990dev_err(dev->dev, "Invalid firmware\n");2991ret = -EINVAL;2992goto out;2993}29942995hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));2996dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",2997hdr->fw_ver, hdr->build_date);29982999ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false);3000if (ret) {3001dev_err(dev->dev, "Failed to start WM firmware\n");3002goto out;3003}30043005snprintf(dev->hw->wiphy->fw_version,3006sizeof(dev->hw->wiphy->fw_version),3007"%.10s-%.15s", hdr->fw_ver, hdr->build_date);30083009release_firmware(fw);30103011if (!fw_wa)3012return 0;30133014ret = request_firmware(&fw, fw_wa, 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, "WA Firmware Version: %.10s, Build Time: %.15s\n",3026hdr->fw_ver, hdr->build_date);30273028ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true);3029if (ret) {3030dev_err(dev->dev, "Failed to start WA 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);30373038out:3039release_firmware(fw);30403041return ret;3042}3043EXPORT_SYMBOL_GPL(mt76_connac2_load_ram);30443045static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info)3046{3047u32 mode = DL_MODE_NEED_RSP;30483049if ((!is_mt7921(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT)3050return mode;30513052switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) {3053case PATCH_SEC_ENC_TYPE_PLAIN:3054break;3055case PATCH_SEC_ENC_TYPE_AES:3056mode |= DL_MODE_ENCRYPT;3057mode |= FIELD_PREP(DL_MODE_KEY_IDX,3058(info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX;3059mode |= DL_MODE_RESET_SEC_IV;3060break;3061case PATCH_SEC_ENC_TYPE_SCRAMBLE:3062mode |= DL_MODE_ENCRYPT;3063mode |= DL_CONFIG_ENCRY_MODE_SEL;3064mode |= DL_MODE_RESET_SEC_IV;3065break;3066default:3067dev_err(dev->dev, "Encryption type not support!\n");3068}30693070return mode;3071}30723073int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)3074{3075int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096;3076const struct mt76_connac2_patch_hdr *hdr;3077const struct firmware *fw = NULL;30783079sem = mt76_connac_mcu_patch_sem_ctrl(dev, true);3080switch (sem) {3081case PATCH_IS_DL:3082return 0;3083case PATCH_NOT_DL_SEM_SUCCESS:3084break;3085default:3086dev_err(dev->dev, "Failed to get patch semaphore\n");3087return -EAGAIN;3088}30893090ret = request_firmware(&fw, fw_name, dev->dev);3091if (ret)3092goto out;30933094if (!fw || !fw->data || fw->size < sizeof(*hdr)) {3095dev_err(dev->dev, "Invalid firmware\n");3096ret = -EINVAL;3097goto out;3098}30993100hdr = (const void *)fw->data;3101dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",3102be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);31033104for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {3105#if defined(__linux__)3106struct mt76_connac2_patch_sec *sec;3107#elif defined(__FreeBSD__)3108const struct mt76_connac2_patch_sec *sec;3109#endif3110u32 len, addr, mode;3111const u8 *dl;3112u32 sec_info;31133114#if defined(__linux__)3115sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec));3116#elif defined(__FreeBSD__)3117sec = (const void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec));3118#endif3119if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) !=3120PATCH_SEC_TYPE_INFO) {3121ret = -EINVAL;3122goto out;3123}31243125addr = be32_to_cpu(sec->info.addr);3126len = be32_to_cpu(sec->info.len);3127dl = fw->data + be32_to_cpu(sec->offs);3128sec_info = be32_to_cpu(sec->info.sec_key_idx);3129mode = mt76_connac2_get_data_mode(dev, sec_info);31303131ret = mt76_connac_mcu_init_download(dev, addr, len, mode);3132if (ret) {3133dev_err(dev->dev, "Download request failed\n");3134goto out;3135}31363137ret = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER),3138dl, len, max_len);3139if (ret) {3140dev_err(dev->dev, "Failed to send patch\n");3141goto out;3142}3143}31443145ret = mt76_connac_mcu_start_patch(dev);3146if (ret)3147dev_err(dev->dev, "Failed to start patch\n");31483149out:3150sem = mt76_connac_mcu_patch_sem_ctrl(dev, false);3151switch (sem) {3152case PATCH_REL_SEM_SUCCESS:3153break;3154default:3155ret = -EAGAIN;3156dev_err(dev->dev, "Failed to release patch semaphore\n");3157break;3158}31593160release_firmware(fw);31613162return ret;3163}3164EXPORT_SYMBOL_GPL(mt76_connac2_load_patch);31653166int mt76_connac2_mcu_fill_message(struct mt76_dev *dev, struct sk_buff *skb,3167int cmd, int *wait_seq)3168{3169int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);3170struct mt76_connac2_mcu_uni_txd *uni_txd;3171struct mt76_connac2_mcu_txd *mcu_txd;3172__le32 *txd;3173u32 val;3174u8 seq;31753176/* TODO: make dynamic based on msg type */3177dev->mcu.timeout = 20 * HZ;31783179seq = ++dev->mcu.msg_seq & 0xf;3180if (!seq)3181seq = ++dev->mcu.msg_seq & 0xf;31823183if (cmd == MCU_CMD(FW_SCATTER))3184goto exit;31853186txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);3187txd = (__le32 *)skb_push(skb, txd_len);31883189val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |3190FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) |3191FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0);3192txd[0] = cpu_to_le32(val);31933194val = MT_TXD1_LONG_FORMAT |3195FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD);3196txd[1] = cpu_to_le32(val);31973198if (cmd & __MCU_CMD_FIELD_UNI) {3199uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd;3200uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));3201uni_txd->option = MCU_CMD_UNI_EXT_ACK;3202uni_txd->cid = cpu_to_le16(mcu_cmd);3203uni_txd->s2d_index = MCU_S2D_H2N;3204uni_txd->pkt_type = MCU_PKT_ID;3205uni_txd->seq = seq;32063207goto exit;3208}32093210mcu_txd = (struct mt76_connac2_mcu_txd *)txd;3211mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));3212mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU,3213MT_TX_MCU_PORT_RX_Q0));3214mcu_txd->pkt_type = MCU_PKT_ID;3215mcu_txd->seq = seq;3216mcu_txd->cid = mcu_cmd;3217mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);32183219if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) {3220if (cmd & __MCU_CMD_FIELD_QUERY)3221mcu_txd->set_query = MCU_Q_QUERY;3222else3223mcu_txd->set_query = MCU_Q_SET;3224mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid;3225} else {3226mcu_txd->set_query = MCU_Q_NA;3227}32283229if (cmd & __MCU_CMD_FIELD_WA)3230mcu_txd->s2d_index = MCU_S2D_H2C;3231else3232mcu_txd->s2d_index = MCU_S2D_H2N;32333234exit:3235if (wait_seq)3236*wait_seq = seq;32373238return 0;3239}3240EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message);32413242MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");3243MODULE_DESCRIPTION("MediaTek MT76x connac layer helpers");3244MODULE_LICENSE("Dual BSD/GPL");324532463247