summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7996/mcu.c')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.c319
1 files changed, 221 insertions, 98 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index ddd555942c73..994526c65bfc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -13,7 +13,7 @@
#define fw_name(_dev, name, ...) ({ \
char *_fw; \
switch (mt76_chip(&(_dev)->mt76)) { \
- case 0x7992: \
+ case MT7992_DEVICE_ID: \
switch ((_dev)->var.type) { \
case MT7992_VAR_TYPE_23: \
_fw = MT7992_##name##_23; \
@@ -22,7 +22,10 @@
_fw = MT7992_##name; \
} \
break; \
- case 0x7990: \
+ case MT7990_DEVICE_ID: \
+ _fw = MT7990_##name; \
+ break; \
+ case MT7996_DEVICE_ID: \
default: \
switch ((_dev)->var.type) { \
case MT7996_VAR_TYPE_233: \
@@ -265,7 +268,7 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);
txd = (__le32 *)skb_push(skb, txd_len);
- if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state) && mt7996_has_wa(dev))
qid = MT_MCUQ_WA;
else
qid = MT_MCUQ_WM;
@@ -335,8 +338,12 @@ exit:
int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
{
struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
__le32 args[3];
- } req = {
+ } __packed req = {
.args = {
cpu_to_le32(a1),
cpu_to_le32(a2),
@@ -344,7 +351,16 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
},
};
- return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false);
+ if (mt7996_has_wa(dev))
+ return mt76_mcu_send_msg(&dev->mt76, cmd, &req.args,
+ sizeof(req.args), false);
+
+ req.tag = cpu_to_le16(cmd == MCU_WA_PARAM_CMD(QUERY) ? UNI_CMD_SDO_QUERY :
+ UNI_CMD_SDO_SET);
+ req.len = cpu_to_le16(sizeof(req) - 4);
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(SDO), &req,
+ sizeof(req), false);
}
static void
@@ -364,21 +380,27 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
r = (struct mt7996_mcu_rdd_report *)skb->data;
- if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys))
- return;
-
- if (r->band_idx == MT_RX_SEL2 && !dev->rdd2_phy)
- return;
-
- if (r->band_idx == MT_RX_SEL2)
+ switch (r->rdd_idx) {
+ case MT_RDD_IDX_BAND2:
+ mphy = dev->mt76.phys[MT_BAND2];
+ break;
+ case MT_RDD_IDX_BAND1:
+ mphy = dev->mt76.phys[MT_BAND1];
+ break;
+ case MT_RDD_IDX_BACKGROUND:
+ if (!dev->rdd2_phy)
+ return;
mphy = dev->rdd2_phy->mt76;
- else
- mphy = dev->mt76.phys[r->band_idx];
+ break;
+ default:
+ dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx);
+ return;
+ }
if (!mphy)
return;
- if (r->band_idx == MT_RX_SEL2)
+ if (r->rdd_idx == MT_RDD_IDX_BACKGROUND)
cfg80211_background_radar_event(mphy->hw->wiphy,
&dev->rdd2_chandef,
GFP_ATOMIC);
@@ -533,7 +555,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
switch (le16_to_cpu(res->tag)) {
case UNI_ALL_STA_TXRX_RATE:
wlan_idx = le16_to_cpu(res->rate[i].wlan_idx);
- wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+ wcid = mt76_wcid_ptr(dev, wlan_idx);
if (!wcid)
break;
@@ -543,7 +565,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
break;
case UNI_ALL_STA_TXRX_ADM_STAT:
wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx);
- wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+ wcid = mt76_wcid_ptr(dev, wlan_idx);
if (!wcid)
break;
@@ -557,7 +579,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
break;
case UNI_ALL_STA_TXRX_MSDU_COUNT:
wlan_idx = le16_to_cpu(res->msdu_cnt[i].wlan_idx);
- wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+ wcid = mt76_wcid_ptr(dev, wlan_idx);
if (!wcid)
break;
@@ -654,10 +676,7 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
e = (void *)skb->data;
idx = le16_to_cpu(e->wlan_id);
- if (idx >= ARRAY_SIZE(dev->mt76.wcid))
- break;
-
- wcid = rcu_dereference(dev->mt76.wcid[idx]);
+ wcid = mt76_wcid_ptr(dev, idx);
if (!wcid || !wcid->sta)
break;
@@ -1883,22 +1902,35 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
MCU_WM_UNI_CMD(RA), true);
}
-int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
- struct ieee80211_link_sta *link_sta,
- struct mt7996_vif_link *link,
- struct mt7996_sta_link *msta_link,
- void *data, u32 field)
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ void *data, u8 link_id, u32 field)
{
- struct sta_phy_uni *phy = data;
+ struct mt7996_vif *mvif = msta->vif;
+ struct mt7996_sta_link *msta_link;
struct sta_rec_ra_fixed_uni *ra;
+ struct sta_phy_uni *phy = data;
+ struct mt76_vif_link *mlink;
struct sk_buff *skb;
+ int err = -ENODEV;
struct tlv *tlv;
- skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
+ rcu_read_lock();
+
+ mlink = rcu_dereference(mvif->mt76.link[link_id]);
+ if (!mlink)
+ goto error_unlock;
+
+ msta_link = rcu_dereference(msta->link[link_id]);
+ if (!msta_link)
+ goto error_unlock;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink,
&msta_link->wcid,
MT7996_STA_UPDATE_MAX_SIZE);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
+ if (IS_ERR(skb)) {
+ err = PTR_ERR(skb);
+ goto error_unlock;
+ }
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
ra = (struct sta_rec_ra_fixed_uni *)tlv;
@@ -1913,106 +1945,149 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
if (phy)
ra->phy = *phy;
break;
- case RATE_PARAM_MMPS_UPDATE:
+ case RATE_PARAM_MMPS_UPDATE: {
+ struct ieee80211_sta *sta = wcid_to_sta(&msta_link->wcid);
+ struct ieee80211_link_sta *link_sta;
+
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta) {
+ dev_kfree_skb(skb);
+ goto error_unlock;
+ }
+
ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);
break;
+ }
default:
break;
}
ra->field = cpu_to_le32(field);
+ rcu_read_unlock();
+
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+error_unlock:
+ rcu_read_unlock();
+
+ return err;
}
static int
-mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
- struct ieee80211_link_sta *link_sta,
- struct mt7996_vif_link *link,
- struct mt7996_sta_link *msta_link)
+mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ struct ieee80211_vif *vif, u8 link_id)
{
- struct cfg80211_chan_def *chandef = &link->phy->mt76->chandef;
- struct cfg80211_bitrate_mask *mask = &link->bitrate_mask;
- enum nl80211_band band = chandef->chan->band;
+ struct ieee80211_link_sta *link_sta;
+ struct cfg80211_bitrate_mask mask;
+ struct mt7996_sta_link *msta_link;
+ struct mt7996_vif_link *link;
struct sta_phy_uni phy = {};
- int ret, nrates = 0;
+ struct ieee80211_sta *sta;
+ int ret, nrates = 0, idx;
+ enum nl80211_band band;
+ bool has_he;
#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \
do { \
- u8 i, gi = mask->control[band]._gi; \
+ u8 i, gi = mask.control[band]._gi; \
gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \
phy.sgi = gi; \
- phy.he_ltf = mask->control[band].he_ltf; \
- for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \
- if (!mask->control[band]._mcs[i]) \
+ phy.he_ltf = mask.control[band].he_ltf; \
+ for (i = 0; i < ARRAY_SIZE(mask.control[band]._mcs); i++) { \
+ if (!mask.control[band]._mcs[i]) \
continue; \
- nrates += hweight16(mask->control[band]._mcs[i]); \
- phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \
+ nrates += hweight16(mask.control[band]._mcs[i]); \
+ phy.mcs = ffs(mask.control[band]._mcs[i]) - 1; \
if (_ht) \
phy.mcs += 8 * i; \
} \
} while (0)
- if (link_sta->he_cap.has_he) {
+ rcu_read_lock();
+
+ link = mt7996_vif_link(dev, vif, link_id);
+ if (!link)
+ goto error_unlock;
+
+ msta_link = rcu_dereference(msta->link[link_id]);
+ if (!msta_link)
+ goto error_unlock;
+
+ sta = wcid_to_sta(&msta_link->wcid);
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
+ goto error_unlock;
+
+ band = link->phy->mt76->chandef.chan->band;
+ has_he = link_sta->he_cap.has_he;
+ mask = link->bitrate_mask;
+ idx = msta_link->wcid.idx;
+
+ if (has_he) {
__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
} else if (link_sta->vht_cap.vht_supported) {
__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
} else if (link_sta->ht_cap.ht_supported) {
__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
} else {
- nrates = hweight32(mask->control[band].legacy);
- phy.mcs = ffs(mask->control[band].legacy) - 1;
+ nrates = hweight32(mask.control[band].legacy);
+ phy.mcs = ffs(mask.control[band].legacy) - 1;
}
+
+ rcu_read_unlock();
+
#undef __sta_phy_bitrate_mask_check
/* fall back to auto rate control */
- if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
- mask->control[band].he_gi == GENMASK(7, 0) &&
- mask->control[band].he_ltf == GENMASK(7, 0) &&
+ if (mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
+ mask.control[band].he_gi == GENMASK(7, 0) &&
+ mask.control[band].he_ltf == GENMASK(7, 0) &&
nrates != 1)
return 0;
/* fixed single rate */
if (nrates == 1) {
- ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
- msta_link, &phy,
+ ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
RATE_PARAM_FIXED_MCS);
if (ret)
return ret;
}
/* fixed GI */
- if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
- mask->control[band].he_gi != GENMASK(7, 0)) {
+ if (mask.control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
+ mask.control[band].he_gi != GENMASK(7, 0)) {
u32 addr;
/* firmware updates only TXCMD but doesn't take WTBL into
* account, so driver should update here to reflect the
* actual txrate hardware sends out.
*/
- addr = mt7996_mac_wtbl_lmac_addr(dev, msta_link->wcid.idx, 7);
- if (link_sta->he_cap.has_he)
+ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 7);
+ if (has_he)
mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
else
mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
- ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
- msta_link, &phy,
+ ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
RATE_PARAM_FIXED_GI);
if (ret)
return ret;
}
/* fixed HE_LTF */
- if (mask->control[band].he_ltf != GENMASK(7, 0)) {
- ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
- msta_link, &phy,
+ if (mask.control[band].he_ltf != GENMASK(7, 0)) {
+ ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
RATE_PARAM_FIXED_HE_LTF);
if (ret)
return ret;
}
return 0;
+
+error_unlock:
+ rcu_read_unlock();
+
+ return -ENODEV;
}
static void
@@ -2123,21 +2198,44 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi));
}
-int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_link_sta *link_sta,
- struct mt7996_vif_link *link,
- struct mt7996_sta_link *msta_link, bool changed)
+int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ struct ieee80211_vif *vif, u8 link_id,
+ bool changed)
{
+ struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_link_sta *link_sta;
+ struct mt7996_sta_link *msta_link;
+ struct mt7996_vif_link *link;
+ struct ieee80211_sta *sta;
struct sk_buff *skb;
- int ret;
+ int ret = -ENODEV;
+
+ rcu_read_lock();
+
+ link = mt7996_vif_link(dev, vif, link_id);
+ if (!link)
+ goto error_unlock;
+
+ msta_link = rcu_dereference(msta->link[link_id]);
+ if (!msta_link)
+ goto error_unlock;
+
+ sta = wcid_to_sta(&msta_link->wcid);
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
+ goto error_unlock;
+
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ if (!link_conf)
+ goto error_unlock;
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
&msta_link->wcid,
MT7996_STA_UPDATE_MAX_SIZE);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
+ if (IS_ERR(skb)) {
+ ret = PTR_ERR(skb);
+ goto error_unlock;
+ }
/* firmware rc algorithm refers to sta_rec_he for HE control.
* once dev->rc_work changes the settings driver should also
@@ -2151,12 +2249,19 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
*/
mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link);
+ rcu_read_unlock();
+
ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
if (ret)
return ret;
- return mt7996_mcu_add_rate_ctrl_fixed(dev, link_sta, link, msta_link);
+ return mt7996_mcu_add_rate_ctrl_fixed(dev, msta, vif, link_id);
+
+error_unlock:
+ rcu_read_unlock();
+
+ return ret;
}
static int
@@ -2242,9 +2347,6 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
if (!link)
continue;
- if (!msta_link)
- continue;
-
mld_setup_link->wcid = cpu_to_le16(msta_link->wcid.idx);
mld_setup_link->bss_idx = link->mt76.idx;
mld_setup_link++;
@@ -3011,6 +3113,9 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
if (ret)
return ret;
+ if (!mt7996_has_wa(dev))
+ return 0;
+
ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP),
MT7996_RAM_TYPE_DSP);
if (ret)
@@ -3021,10 +3126,9 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
}
static int
-mt7996_firmware_state(struct mt7996_dev *dev, bool wa)
+mt7996_firmware_state(struct mt7996_dev *dev, u8 fw_state)
{
- u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE,
- wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD);
+ u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, fw_state);
if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,
state, 1000)) {
@@ -3056,13 +3160,14 @@ mt7996_mcu_restart(struct mt76_dev *dev)
static int mt7996_load_firmware(struct mt7996_dev *dev)
{
+ u8 fw_state;
int ret;
/* make sure fw is download state */
- if (mt7996_firmware_state(dev, false)) {
+ if (mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD)) {
/* restart firmware once */
mt7996_mcu_restart(&dev->mt76);
- ret = mt7996_firmware_state(dev, false);
+ ret = mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD);
if (ret) {
dev_err(dev->mt76.dev,
"Firmware is not ready for download\n");
@@ -3078,7 +3183,8 @@ static int mt7996_load_firmware(struct mt7996_dev *dev)
if (ret)
return ret;
- ret = mt7996_firmware_state(dev, true);
+ fw_state = mt7996_has_wa(dev) ? FW_STATE_RDY : FW_STATE_NORMAL_TRX;
+ ret = mt7996_firmware_state(dev, fw_state);
if (ret)
return ret;
@@ -3216,13 +3322,15 @@ int mt7996_mcu_init_firmware(struct mt7996_dev *dev)
if (ret)
return ret;
- ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
- if (ret)
- return ret;
+ if (mt7996_has_wa(dev)) {
+ ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
+ if (ret)
+ return ret;
- ret = mt7996_mcu_set_mwds(dev, 1);
- if (ret)
- return ret;
+ ret = mt7996_mcu_set_mwds(dev, 1);
+ if (ret)
+ return ret;
+ }
ret = mt7996_mcu_init_rx_airtime(dev);
if (ret)
@@ -3248,7 +3356,7 @@ int mt7996_mcu_init(struct mt7996_dev *dev)
void mt7996_mcu_exit(struct mt7996_dev *dev)
{
mt7996_mcu_restart(&dev->mt76);
- if (mt7996_firmware_state(dev, false)) {
+ if (mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD)) {
dev_err(dev->mt76.dev, "Failed to exit mcu\n");
goto out;
}
@@ -3535,11 +3643,10 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
struct cfg80211_chan_def *chandef)
{
struct mt7996_dev *dev = phy->dev;
- int err, region;
+ int err, region, rdd_idx = mt7996_get_rdd_idx(phy, true);
if (!chandef) { /* disable offchain */
- err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2,
- 0, 0);
+ err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0);
if (err)
return err;
@@ -3565,8 +3672,7 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
break;
}
- return mt7996_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2,
- 0, region);
+ return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);
}
int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
@@ -4433,8 +4539,7 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)
&req, sizeof(req), true);
}
-int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
- u8 rx_sel, u8 val)
+int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val)
{
struct {
u8 _rsv[4];
@@ -4451,8 +4556,7 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
.tag = cpu_to_le16(UNI_RDD_CTRL_PARM),
.len = cpu_to_le16(sizeof(req) - 4),
.ctrl = cmd,
- .rdd_idx = index,
- .rdd_rx_sel = rx_sel,
+ .rdd_idx = rdd_idx,
.val = val,
};
@@ -4742,7 +4846,26 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode)
mode > mt76_connac_lmac_mapping(IEEE80211_AC_VO))
return -EINVAL;
+ if (!mt7996_has_wa(dev)) {
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+ u8 cp_mode;
+ u8 rsv[3];
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_CMD_SDO_CP_MODE),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .cp_mode = mode,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(SDO),
+ &req, sizeof(req), false);
+ }
+
cp_mode = cpu_to_le32(mode);
+
return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT),
&cp_mode, sizeof(cp_mode), true);
}