1e57b7901SRyder Lee // SPDX-License-Identifier: ISC
2e57b7901SRyder Lee /* Copyright (C) 2020 MediaTek Inc. */
3e57b7901SRyder Lee
4e57b7901SRyder Lee #include <linux/fs.h>
5e57b7901SRyder Lee #include "mt7915.h"
6e57b7901SRyder Lee #include "mcu.h"
7e57b7901SRyder Lee #include "mac.h"
8e57b7901SRyder Lee #include "eeprom.h"
9e57b7901SRyder Lee
1099ad32a4SBo Jiao #define fw_name(_dev, name, ...) ({ \
1199ad32a4SBo Jiao char *_fw; \
1299ad32a4SBo Jiao switch (mt76_chip(&(_dev)->mt76)) { \
1399ad32a4SBo Jiao case 0x7915: \
1499ad32a4SBo Jiao _fw = MT7915_##name; \
1599ad32a4SBo Jiao break; \
166bad146dSAlexander Couzens case 0x7981: \
176bad146dSAlexander Couzens _fw = MT7981_##name; \
186bad146dSAlexander Couzens break; \
1999ad32a4SBo Jiao case 0x7986: \
2099ad32a4SBo Jiao _fw = MT7986_##name##__VA_ARGS__; \
2199ad32a4SBo Jiao break; \
2299ad32a4SBo Jiao default: \
2399ad32a4SBo Jiao _fw = MT7916_##name; \
2499ad32a4SBo Jiao break; \
2599ad32a4SBo Jiao } \
2699ad32a4SBo Jiao _fw; \
2799ad32a4SBo Jiao })
2899ad32a4SBo Jiao
2999ad32a4SBo Jiao #define fw_name_var(_dev, name) (mt7915_check_adie(dev, false) ? \
3099ad32a4SBo Jiao fw_name(_dev, name) : \
3199ad32a4SBo Jiao fw_name(_dev, name, _MT7975))
3299ad32a4SBo Jiao
33e57b7901SRyder Lee #define MCU_PATCH_ADDRESS 0x200000
34e57b7901SRyder Lee
35c336318fSRyder Lee #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p)
36c336318fSRyder Lee #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m)
37c336318fSRyder Lee
383dc00ecfSRyder Lee static bool sr_scene_detect = true;
393dc00ecfSRyder Lee module_param(sr_scene_detect, bool, 0644);
403dc00ecfSRyder Lee MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm");
413dc00ecfSRyder Lee
4289029a85SRyder Lee static u8
mt7915_mcu_get_sta_nss(u16 mcs_map)4389029a85SRyder Lee mt7915_mcu_get_sta_nss(u16 mcs_map)
4489029a85SRyder Lee {
4589029a85SRyder Lee u8 nss;
4689029a85SRyder Lee
4789029a85SRyder Lee for (nss = 8; nss > 0; nss--) {
4889029a85SRyder Lee u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3;
4989029a85SRyder Lee
5089029a85SRyder Lee if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED)
5189029a85SRyder Lee break;
5289029a85SRyder Lee }
5389029a85SRyder Lee
5489029a85SRyder Lee return nss - 1;
5589029a85SRyder Lee }
5689029a85SRyder Lee
5776be6c07SRyder Lee static void
mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta * sta,__le16 * he_mcs,u16 mcs_map)5876be6c07SRyder Lee mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
59ade25ca7SPeter Chiu u16 mcs_map)
6076be6c07SRyder Lee {
6176be6c07SRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
6299ad32a4SBo Jiao struct mt7915_dev *dev = msta->vif->phy->dev;
63ade25ca7SPeter Chiu enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
64ade25ca7SPeter Chiu const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs;
65046d2e7cSSriram R int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
6676be6c07SRyder Lee
6776be6c07SRyder Lee for (nss = 0; nss < max_nss; nss++) {
6876be6c07SRyder Lee int mcs;
6976be6c07SRyder Lee
7076be6c07SRyder Lee switch ((mcs_map >> (2 * nss)) & 0x3) {
7176be6c07SRyder Lee case IEEE80211_HE_MCS_SUPPORT_0_11:
7276be6c07SRyder Lee mcs = GENMASK(11, 0);
7376be6c07SRyder Lee break;
7476be6c07SRyder Lee case IEEE80211_HE_MCS_SUPPORT_0_9:
7576be6c07SRyder Lee mcs = GENMASK(9, 0);
7676be6c07SRyder Lee break;
7776be6c07SRyder Lee case IEEE80211_HE_MCS_SUPPORT_0_7:
7876be6c07SRyder Lee mcs = GENMASK(7, 0);
7976be6c07SRyder Lee break;
8076be6c07SRyder Lee default:
8176be6c07SRyder Lee mcs = 0;
8276be6c07SRyder Lee }
8376be6c07SRyder Lee
8476be6c07SRyder Lee mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1;
8576be6c07SRyder Lee
8676be6c07SRyder Lee switch (mcs) {
8776be6c07SRyder Lee case 0 ... 7:
8876be6c07SRyder Lee mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
8976be6c07SRyder Lee break;
9076be6c07SRyder Lee case 8 ... 9:
9176be6c07SRyder Lee mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
9276be6c07SRyder Lee break;
9376be6c07SRyder Lee case 10 ... 11:
9476be6c07SRyder Lee mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
9576be6c07SRyder Lee break;
9676be6c07SRyder Lee default:
9776be6c07SRyder Lee mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
9876be6c07SRyder Lee break;
9976be6c07SRyder Lee }
10076be6c07SRyder Lee mcs_map &= ~(0x3 << (nss * 2));
10176be6c07SRyder Lee mcs_map |= mcs << (nss * 2);
10276be6c07SRyder Lee
10399ad32a4SBo Jiao /* only support 2ss on 160MHz for mt7915 */
10499ad32a4SBo Jiao if (is_mt7915(&dev->mt76) && nss > 1 &&
105046d2e7cSSriram R sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
10676be6c07SRyder Lee break;
10776be6c07SRyder Lee }
10876be6c07SRyder Lee
10976be6c07SRyder Lee *he_mcs = cpu_to_le16(mcs_map);
11076be6c07SRyder Lee }
11176be6c07SRyder Lee
11276be6c07SRyder Lee static void
mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta * sta,__le16 * vht_mcs,const u16 * mask)11376be6c07SRyder Lee mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
11476be6c07SRyder Lee const u16 *mask)
11576be6c07SRyder Lee {
11699ad32a4SBo Jiao struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
11799ad32a4SBo Jiao struct mt7915_dev *dev = msta->vif->phy->dev;
118046d2e7cSSriram R u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
119046d2e7cSSriram R int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
12076be6c07SRyder Lee u16 mcs;
12176be6c07SRyder Lee
12276be6c07SRyder Lee for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
12376be6c07SRyder Lee switch (mcs_map & 0x3) {
12476be6c07SRyder Lee case IEEE80211_VHT_MCS_SUPPORT_0_9:
12576be6c07SRyder Lee mcs = GENMASK(9, 0);
12676be6c07SRyder Lee break;
12776be6c07SRyder Lee case IEEE80211_VHT_MCS_SUPPORT_0_8:
12876be6c07SRyder Lee mcs = GENMASK(8, 0);
12976be6c07SRyder Lee break;
13076be6c07SRyder Lee case IEEE80211_VHT_MCS_SUPPORT_0_7:
13176be6c07SRyder Lee mcs = GENMASK(7, 0);
13276be6c07SRyder Lee break;
13376be6c07SRyder Lee default:
13476be6c07SRyder Lee mcs = 0;
13576be6c07SRyder Lee }
13676be6c07SRyder Lee
13776be6c07SRyder Lee vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]);
13876be6c07SRyder Lee
13999ad32a4SBo Jiao /* only support 2ss on 160MHz for mt7915 */
14099ad32a4SBo Jiao if (is_mt7915(&dev->mt76) && nss > 1 &&
141046d2e7cSSriram R sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
14276be6c07SRyder Lee break;
14376be6c07SRyder Lee }
14476be6c07SRyder Lee }
14576be6c07SRyder Lee
14676be6c07SRyder Lee static void
mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta * sta,u8 * ht_mcs,const u8 * mask)14776be6c07SRyder Lee mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
14876be6c07SRyder Lee const u8 *mask)
14976be6c07SRyder Lee {
150046d2e7cSSriram R int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
15176be6c07SRyder Lee
15276be6c07SRyder Lee for (nss = 0; nss < max_nss; nss++)
153046d2e7cSSriram R ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss];
15476be6c07SRyder Lee }
15576be6c07SRyder Lee
156e452c6ebSFelix Fietkau static int
mt7915_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)157e452c6ebSFelix Fietkau mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
158e452c6ebSFelix Fietkau struct sk_buff *skb, int seq)
159e452c6ebSFelix Fietkau {
160fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
161e452c6ebSFelix Fietkau int ret = 0;
162e452c6ebSFelix Fietkau
163e452c6ebSFelix Fietkau if (!skb) {
16453d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
165e452c6ebSFelix Fietkau cmd, seq);
166e452c6ebSFelix Fietkau return -ETIMEDOUT;
167e452c6ebSFelix Fietkau }
168e452c6ebSFelix Fietkau
169fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
170161a7528SPeter Chiu if (seq != rxd->seq &&
171161a7528SPeter Chiu !(rxd->eid == MCU_CMD_EXT_CID &&
172161a7528SPeter Chiu rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
173e452c6ebSFelix Fietkau return -EAGAIN;
174e452c6ebSFelix Fietkau
175c203dd62SFelix Fietkau if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
176e452c6ebSFelix Fietkau skb_pull(skb, sizeof(*rxd) - 4);
177e452c6ebSFelix Fietkau ret = *skb->data;
178c203dd62SFelix Fietkau } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
179e452c6ebSFelix Fietkau skb_pull(skb, sizeof(*rxd) + 4);
180e452c6ebSFelix Fietkau ret = le32_to_cpu(*(__le32 *)skb->data);
181c203dd62SFelix Fietkau } else {
182fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
183e452c6ebSFelix Fietkau }
184e452c6ebSFelix Fietkau
185e452c6ebSFelix Fietkau return ret;
186e452c6ebSFelix Fietkau }
187e452c6ebSFelix Fietkau
188e452c6ebSFelix Fietkau static int
mt7915_mcu_send_message(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * wait_seq)189e452c6ebSFelix Fietkau mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
190e57b7901SRyder Lee int cmd, int *wait_seq)
191e57b7901SRyder Lee {
192e452c6ebSFelix Fietkau struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
193b7c56875SNathan Chancellor enum mt76_mcuq_id qid;
194d2f5c8edSLorenzo Bianconi int ret;
195e57b7901SRyder Lee
196d2f5c8edSLorenzo Bianconi ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, wait_seq);
197d2f5c8edSLorenzo Bianconi if (ret)
198d2f5c8edSLorenzo Bianconi return ret;
199e452c6ebSFelix Fietkau
200d2f5c8edSLorenzo Bianconi if (cmd == MCU_CMD(FW_SCATTER))
201b7c56875SNathan Chancellor qid = MT_MCUQ_FWDL;
202d2f5c8edSLorenzo Bianconi else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
203b7c56875SNathan Chancellor qid = MT_MCUQ_WA;
204b8135057SLorenzo Bianconi else
205b7c56875SNathan Chancellor qid = MT_MCUQ_WM;
206e57b7901SRyder Lee
207b7c56875SNathan Chancellor return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
208e57b7901SRyder Lee }
209e57b7901SRyder Lee
mt7915_mcu_wa_cmd(struct mt7915_dev * dev,int cmd,u32 a1,u32 a2,u32 a3)21090f5daeaSShayne Chen int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
211f1fd2caeSFelix Fietkau {
212f1fd2caeSFelix Fietkau struct {
213f1fd2caeSFelix Fietkau __le32 args[3];
214f1fd2caeSFelix Fietkau } req = {
215f1fd2caeSFelix Fietkau .args = {
216f1fd2caeSFelix Fietkau cpu_to_le32(a1),
217f1fd2caeSFelix Fietkau cpu_to_le32(a2),
218f1fd2caeSFelix Fietkau cpu_to_le32(a3),
219f1fd2caeSFelix Fietkau },
220f1fd2caeSFelix Fietkau };
221f1fd2caeSFelix Fietkau
22290f5daeaSShayne Chen return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false);
223f1fd2caeSFelix Fietkau }
224f1fd2caeSFelix Fietkau
225f1fd2caeSFelix Fietkau static void
mt7915_mcu_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)226e57b7901SRyder Lee mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
227e57b7901SRyder Lee {
228d0a9123eSJohannes Berg if (vif->bss_conf.csa_active)
229e57b7901SRyder Lee ieee80211_csa_finish(vif);
230e57b7901SRyder Lee }
231e57b7901SRyder Lee
232e57b7901SRyder Lee static void
mt7915_mcu_rx_csa_notify(struct mt7915_dev * dev,struct sk_buff * skb)233b6d20ce4SRyder Lee mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb)
234b6d20ce4SRyder Lee {
235b6d20ce4SRyder Lee struct mt76_phy *mphy = &dev->mt76.phy;
236b6d20ce4SRyder Lee struct mt7915_mcu_csa_notify *c;
237b6d20ce4SRyder Lee
238b6d20ce4SRyder Lee c = (struct mt7915_mcu_csa_notify *)skb->data;
239b6d20ce4SRyder Lee
2407a53eecdSRyder Lee if (c->band_idx > MT_BAND1)
2417a53eecdSRyder Lee return;
2427a53eecdSRyder Lee
2433eb50cc9SRyder Lee if ((c->band_idx && !dev->phy.mt76->band_idx) &&
2443eb50cc9SRyder Lee dev->mt76.phys[MT_BAND1])
245dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
246b6d20ce4SRyder Lee
247b6d20ce4SRyder Lee ieee80211_iterate_active_interfaces_atomic(mphy->hw,
248b6d20ce4SRyder Lee IEEE80211_IFACE_ITER_RESUME_ALL,
249b6d20ce4SRyder Lee mt7915_mcu_csa_finish, mphy->hw);
250b6d20ce4SRyder Lee }
251b6d20ce4SRyder Lee
252b6d20ce4SRyder Lee static void
mt7915_mcu_rx_thermal_notify(struct mt7915_dev * dev,struct sk_buff * skb)25334b877d9SRyder Lee mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb)
25434b877d9SRyder Lee {
25534b877d9SRyder Lee struct mt76_phy *mphy = &dev->mt76.phy;
25634b877d9SRyder Lee struct mt7915_mcu_thermal_notify *t;
25734b877d9SRyder Lee struct mt7915_phy *phy;
25834b877d9SRyder Lee
25934b877d9SRyder Lee t = (struct mt7915_mcu_thermal_notify *)skb->data;
26034b877d9SRyder Lee if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE)
26134b877d9SRyder Lee return;
26234b877d9SRyder Lee
2637a53eecdSRyder Lee if (t->ctrl.band_idx > MT_BAND1)
2647a53eecdSRyder Lee return;
2657a53eecdSRyder Lee
2663eb50cc9SRyder Lee if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) &&
2673eb50cc9SRyder Lee dev->mt76.phys[MT_BAND1])
268dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
26934b877d9SRyder Lee
27034b877d9SRyder Lee phy = (struct mt7915_phy *)mphy->priv;
27134b877d9SRyder Lee phy->throttle_state = t->ctrl.duty.duty_cycle;
27234b877d9SRyder Lee }
27334b877d9SRyder Lee
27434b877d9SRyder Lee static void
mt7915_mcu_rx_radar_detected(struct mt7915_dev * dev,struct sk_buff * skb)275e57b7901SRyder Lee mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
276e57b7901SRyder Lee {
277e57b7901SRyder Lee struct mt76_phy *mphy = &dev->mt76.phy;
278e57b7901SRyder Lee struct mt7915_mcu_rdd_report *r;
279e57b7901SRyder Lee
280e57b7901SRyder Lee r = (struct mt7915_mcu_rdd_report *)skb->data;
281e57b7901SRyder Lee
2829a399407SStanleyYP Wang if (r->band_idx > MT_RX_SEL2)
2837a53eecdSRyder Lee return;
2847a53eecdSRyder Lee
2853eb50cc9SRyder Lee if ((r->band_idx && !dev->phy.mt76->band_idx) &&
2863eb50cc9SRyder Lee dev->mt76.phys[MT_BAND1])
287dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
288e57b7901SRyder Lee
28901f2cef0SLorenzo Bianconi if (r->band_idx == MT_RX_SEL2)
29001f2cef0SLorenzo Bianconi cfg80211_background_radar_event(mphy->hw->wiphy,
29101f2cef0SLorenzo Bianconi &dev->rdd2_chandef,
29201f2cef0SLorenzo Bianconi GFP_ATOMIC);
29301f2cef0SLorenzo Bianconi else
294e57b7901SRyder Lee ieee80211_radar_detected(mphy->hw);
295e57b7901SRyder Lee dev->hw_pattern++;
296e57b7901SRyder Lee }
297e57b7901SRyder Lee
298e57b7901SRyder Lee static void
mt7915_mcu_rx_log_message(struct mt7915_dev * dev,struct sk_buff * skb)2995517f78bSRyder Lee mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
3005517f78bSRyder Lee {
301fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
302988845c9SFelix Fietkau int len = skb->len - sizeof(*rxd);
303fc6ee71aSLorenzo Bianconi const char *data, *type;
304fc6ee71aSLorenzo Bianconi
305fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
306fc6ee71aSLorenzo Bianconi data = (char *)&rxd[1];
3075517f78bSRyder Lee
3085517f78bSRyder Lee switch (rxd->s2d_index) {
3095517f78bSRyder Lee case 0:
310988845c9SFelix Fietkau if (mt7915_debugfs_rx_log(dev, data, len))
311988845c9SFelix Fietkau return;
312988845c9SFelix Fietkau
3135517f78bSRyder Lee type = "WM";
3145517f78bSRyder Lee break;
3155517f78bSRyder Lee case 2:
3165517f78bSRyder Lee type = "WA";
3175517f78bSRyder Lee break;
3185517f78bSRyder Lee default:
3195517f78bSRyder Lee type = "unknown";
3205517f78bSRyder Lee break;
3215517f78bSRyder Lee }
3225517f78bSRyder Lee
323988845c9SFelix Fietkau wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
3245517f78bSRyder Lee }
3255517f78bSRyder Lee
3265517f78bSRyder Lee static void
mt7915_mcu_cca_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)327b4b9f0a3SLorenzo Bianconi mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
328b4b9f0a3SLorenzo Bianconi {
329d0a9123eSJohannes Berg if (!vif->bss_conf.color_change_active)
330b4b9f0a3SLorenzo Bianconi return;
331b4b9f0a3SLorenzo Bianconi
332b4b9f0a3SLorenzo Bianconi ieee80211_color_change_finish(vif);
333b4b9f0a3SLorenzo Bianconi }
334b4b9f0a3SLorenzo Bianconi
335b4b9f0a3SLorenzo Bianconi static void
mt7915_mcu_rx_bcc_notify(struct mt7915_dev * dev,struct sk_buff * skb)33632406ca4SRyder Lee mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb)
33732406ca4SRyder Lee {
33832406ca4SRyder Lee struct mt76_phy *mphy = &dev->mt76.phy;
33932406ca4SRyder Lee struct mt7915_mcu_bcc_notify *b;
34032406ca4SRyder Lee
34132406ca4SRyder Lee b = (struct mt7915_mcu_bcc_notify *)skb->data;
34232406ca4SRyder Lee
3437a53eecdSRyder Lee if (b->band_idx > MT_BAND1)
3447a53eecdSRyder Lee return;
3457a53eecdSRyder Lee
3467a53eecdSRyder Lee if ((b->band_idx && !dev->phy.mt76->band_idx) &&
3477a53eecdSRyder Lee dev->mt76.phys[MT_BAND1])
348dc44c45cSLorenzo Bianconi mphy = dev->mt76.phys[MT_BAND1];
34932406ca4SRyder Lee
35032406ca4SRyder Lee ieee80211_iterate_active_interfaces_atomic(mphy->hw,
35132406ca4SRyder Lee IEEE80211_IFACE_ITER_RESUME_ALL,
35232406ca4SRyder Lee mt7915_mcu_cca_finish, mphy->hw);
35332406ca4SRyder Lee }
35432406ca4SRyder Lee
35532406ca4SRyder Lee static void
mt7915_mcu_rx_ext_event(struct mt7915_dev * dev,struct sk_buff * skb)356e57b7901SRyder Lee mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
357e57b7901SRyder Lee {
358fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
359e57b7901SRyder Lee
360fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
361e57b7901SRyder Lee switch (rxd->ext_eid) {
36234b877d9SRyder Lee case MCU_EXT_EVENT_THERMAL_PROTECT:
36334b877d9SRyder Lee mt7915_mcu_rx_thermal_notify(dev, skb);
36434b877d9SRyder Lee break;
365e57b7901SRyder Lee case MCU_EXT_EVENT_RDD_REPORT:
366e57b7901SRyder Lee mt7915_mcu_rx_radar_detected(dev, skb);
367e57b7901SRyder Lee break;
368e57b7901SRyder Lee case MCU_EXT_EVENT_CSA_NOTIFY:
369b6d20ce4SRyder Lee mt7915_mcu_rx_csa_notify(dev, skb);
370e57b7901SRyder Lee break;
3715517f78bSRyder Lee case MCU_EXT_EVENT_FW_LOG_2_HOST:
3725517f78bSRyder Lee mt7915_mcu_rx_log_message(dev, skb);
3735517f78bSRyder Lee break;
374b4b9f0a3SLorenzo Bianconi case MCU_EXT_EVENT_BCC_NOTIFY:
37532406ca4SRyder Lee mt7915_mcu_rx_bcc_notify(dev, skb);
376b4b9f0a3SLorenzo Bianconi break;
377e57b7901SRyder Lee default:
378e57b7901SRyder Lee break;
379e57b7901SRyder Lee }
380e57b7901SRyder Lee }
381e57b7901SRyder Lee
382e57b7901SRyder Lee static void
mt7915_mcu_rx_unsolicited_event(struct mt7915_dev * dev,struct sk_buff * skb)383e57b7901SRyder Lee mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb)
384e57b7901SRyder Lee {
385fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
386e57b7901SRyder Lee
387fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
388e57b7901SRyder Lee switch (rxd->eid) {
389e57b7901SRyder Lee case MCU_EVENT_EXT:
390e57b7901SRyder Lee mt7915_mcu_rx_ext_event(dev, skb);
391e57b7901SRyder Lee break;
392e57b7901SRyder Lee default:
393e57b7901SRyder Lee break;
394e57b7901SRyder Lee }
395e57b7901SRyder Lee dev_kfree_skb(skb);
396e57b7901SRyder Lee }
397e57b7901SRyder Lee
mt7915_mcu_rx_event(struct mt7915_dev * dev,struct sk_buff * skb)398e57b7901SRyder Lee void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
399e57b7901SRyder Lee {
400fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
401e57b7901SRyder Lee
402fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
403161a7528SPeter Chiu if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
4045517f78bSRyder Lee rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
405e57b7901SRyder Lee rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
406e57b7901SRyder Lee rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
407b4b9f0a3SLorenzo Bianconi rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
408161a7528SPeter Chiu !rxd->seq) &&
409161a7528SPeter Chiu !(rxd->eid == MCU_CMD_EXT_CID &&
410161a7528SPeter Chiu rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
411e57b7901SRyder Lee mt7915_mcu_rx_unsolicited_event(dev, skb);
412e57b7901SRyder Lee else
413e57b7901SRyder Lee mt76_mcu_rx_event(&dev->mt76, skb);
414e57b7901SRyder Lee }
415e57b7901SRyder Lee
416e57b7901SRyder Lee static struct tlv *
mt7915_mcu_add_nested_subtlv(struct sk_buff * skb,int sub_tag,int sub_len,__le16 * sub_ntlv,__le16 * len)417e57b7901SRyder Lee mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len,
418e57b7901SRyder Lee __le16 *sub_ntlv, __le16 *len)
419e57b7901SRyder Lee {
420e57b7901SRyder Lee struct tlv *ptlv, tlv = {
421e57b7901SRyder Lee .tag = cpu_to_le16(sub_tag),
422e57b7901SRyder Lee .len = cpu_to_le16(sub_len),
423e57b7901SRyder Lee };
424e57b7901SRyder Lee
425ff6b26beSFelix Fietkau ptlv = skb_put_zero(skb, sub_len);
426e57b7901SRyder Lee memcpy(ptlv, &tlv, sizeof(tlv));
427e57b7901SRyder Lee
42859283d09SLiu Shixin le16_add_cpu(sub_ntlv, 1);
42959283d09SLiu Shixin le16_add_cpu(len, sub_len);
430e57b7901SRyder Lee
431e57b7901SRyder Lee return ptlv;
432e57b7901SRyder Lee }
433e57b7901SRyder Lee
434e57b7901SRyder Lee /** bss info **/
4356094f86fSRyder Lee struct mt7915_he_obss_narrow_bw_ru_data {
4366094f86fSRyder Lee bool tolerated;
4376094f86fSRyder Lee };
4386094f86fSRyder Lee
mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy * wiphy,struct cfg80211_bss * bss,void * _data)4396094f86fSRyder Lee static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
4406094f86fSRyder Lee struct cfg80211_bss *bss,
4416094f86fSRyder Lee void *_data)
4426094f86fSRyder Lee {
4436094f86fSRyder Lee struct mt7915_he_obss_narrow_bw_ru_data *data = _data;
4446094f86fSRyder Lee const struct element *elem;
4456094f86fSRyder Lee
446ffbebe76SRyder Lee rcu_read_lock();
447f9a5c056SRyder Lee elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY);
4486094f86fSRyder Lee
449d45dac07SRyder Lee if (!elem || elem->datalen <= 10 ||
4506094f86fSRyder Lee !(elem->data[10] &
4516094f86fSRyder Lee WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT))
4526094f86fSRyder Lee data->tolerated = false;
453ffbebe76SRyder Lee
454ffbebe76SRyder Lee rcu_read_unlock();
4556094f86fSRyder Lee }
4566094f86fSRyder Lee
mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw * hw,struct ieee80211_vif * vif)4576094f86fSRyder Lee static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
4586094f86fSRyder Lee struct ieee80211_vif *vif)
4596094f86fSRyder Lee {
4606094f86fSRyder Lee struct mt7915_he_obss_narrow_bw_ru_data iter_data = {
4616094f86fSRyder Lee .tolerated = true,
4626094f86fSRyder Lee };
4636094f86fSRyder Lee
4646094f86fSRyder Lee if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR))
4656094f86fSRyder Lee return false;
4666094f86fSRyder Lee
4676094f86fSRyder Lee cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef,
4686094f86fSRyder Lee mt7915_check_he_obss_narrow_bw_ru_iter,
4696094f86fSRyder Lee &iter_data);
4706094f86fSRyder Lee
4716094f86fSRyder Lee /*
4726094f86fSRyder Lee * If there is at least one AP on radar channel that cannot
4736094f86fSRyder Lee * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.
4746094f86fSRyder Lee */
4756094f86fSRyder Lee return !iter_data.tolerated;
4766094f86fSRyder Lee }
4776094f86fSRyder Lee
478e57b7901SRyder Lee static void
mt7915_mcu_bss_rfch_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)479e57b7901SRyder Lee mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
480e57b7901SRyder Lee struct mt7915_phy *phy)
481e57b7901SRyder Lee {
482e57b7901SRyder Lee struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
483e57b7901SRyder Lee struct bss_info_rf_ch *ch;
484e57b7901SRyder Lee struct tlv *tlv;
485e57b7901SRyder Lee int freq1 = chandef->center_freq1;
486e57b7901SRyder Lee
487069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch));
488e57b7901SRyder Lee
489e57b7901SRyder Lee ch = (struct bss_info_rf_ch *)tlv;
490e57b7901SRyder Lee ch->pri_ch = chandef->chan->hw_value;
491e57b7901SRyder Lee ch->center_ch0 = ieee80211_frequency_to_channel(freq1);
49244c73d17SLorenzo Bianconi ch->bw = mt76_connac_chan_bw(chandef);
493e57b7901SRyder Lee
494e57b7901SRyder Lee if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
495e57b7901SRyder Lee int freq2 = chandef->center_freq2;
496e57b7901SRyder Lee
497e57b7901SRyder Lee ch->center_ch1 = ieee80211_frequency_to_channel(freq2);
498e57b7901SRyder Lee }
499e57b7901SRyder Lee
5006094f86fSRyder Lee if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) {
501006b9d4aSBo Jiao struct mt76_phy *mphy = phy->mt76;
5026094f86fSRyder Lee
5036094f86fSRyder Lee ch->he_ru26_block =
5046094f86fSRyder Lee mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif);
5056094f86fSRyder Lee ch->he_all_disable = false;
5066094f86fSRyder Lee } else {
507e57b7901SRyder Lee ch->he_all_disable = true;
508e57b7901SRyder Lee }
5096094f86fSRyder Lee }
510e57b7901SRyder Lee
511e57b7901SRyder Lee static void
mt7915_mcu_bss_ra_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)512e57b7901SRyder Lee mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
513e57b7901SRyder Lee struct mt7915_phy *phy)
514e57b7901SRyder Lee {
515ee0863aeSPeter Chiu int max_nss = hweight8(phy->mt76->antenna_mask);
516e57b7901SRyder Lee struct bss_info_ra *ra;
517e57b7901SRyder Lee struct tlv *tlv;
518e57b7901SRyder Lee
519069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra));
520e57b7901SRyder Lee
521e57b7901SRyder Lee ra = (struct bss_info_ra *)tlv;
522e57b7901SRyder Lee ra->op_mode = vif->type == NL80211_IFTYPE_AP;
523e57b7901SRyder Lee ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC;
524e57b7901SRyder Lee ra->short_preamble = true;
525e57b7901SRyder Lee ra->tx_streams = max_nss;
526e57b7901SRyder Lee ra->rx_streams = max_nss;
527e57b7901SRyder Lee ra->algo = 4;
528e57b7901SRyder Lee ra->train_up_rule = 2;
529e57b7901SRyder Lee ra->train_up_high_thres = 110;
530e57b7901SRyder Lee ra->train_up_rule_rssi = -70;
531e57b7901SRyder Lee ra->low_traffic_thres = 2;
532e57b7901SRyder Lee ra->phy_cap = cpu_to_le32(0xfdf);
533e57b7901SRyder Lee ra->interval = cpu_to_le32(500);
534e57b7901SRyder Lee ra->fast_interval = cpu_to_le32(100);
535e57b7901SRyder Lee }
536e57b7901SRyder Lee
537e57b7901SRyder Lee static void
mt7915_mcu_bss_he_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)5386094f86fSRyder Lee mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
5396094f86fSRyder Lee struct mt7915_phy *phy)
5406094f86fSRyder Lee {
5416094f86fSRyder Lee #define DEFAULT_HE_PE_DURATION 4
5426094f86fSRyder Lee #define DEFAULT_HE_DURATION_RTS_THRES 1023
5436094f86fSRyder Lee const struct ieee80211_sta_he_cap *cap;
5446094f86fSRyder Lee struct bss_info_he *he;
5456094f86fSRyder Lee struct tlv *tlv;
5466094f86fSRyder Lee
547e6d557a7SLorenzo Bianconi cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
5486094f86fSRyder Lee
549069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
5506094f86fSRyder Lee
5516094f86fSRyder Lee he = (struct bss_info_he *)tlv;
5522fe1a5d6SFelix Fietkau he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
5536094f86fSRyder Lee if (!he->he_pe_duration)
5546094f86fSRyder Lee he->he_pe_duration = DEFAULT_HE_PE_DURATION;
5556094f86fSRyder Lee
5562fe1a5d6SFelix Fietkau he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
5576094f86fSRyder Lee if (!he->he_rts_thres)
5586094f86fSRyder Lee he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
5596094f86fSRyder Lee
5606094f86fSRyder Lee he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;
5616094f86fSRyder Lee he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;
5626094f86fSRyder Lee he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
5636094f86fSRyder Lee }
5646094f86fSRyder Lee
5656094f86fSRyder Lee static void
mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff * skb)566b443e55fSRyder Lee mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
567b443e55fSRyder Lee {
568b443e55fSRyder Lee #define TXD_CMP_MAP1 GENMASK(15, 0)
569b443e55fSRyder Lee #define TXD_CMP_MAP2 (GENMASK(31, 0) & ~BIT(23))
570b443e55fSRyder Lee struct bss_info_hw_amsdu *amsdu;
571b443e55fSRyder Lee struct tlv *tlv;
572b443e55fSRyder Lee
573069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
574b443e55fSRyder Lee
575b443e55fSRyder Lee amsdu = (struct bss_info_hw_amsdu *)tlv;
576b443e55fSRyder Lee amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
577b443e55fSRyder Lee amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
578b443e55fSRyder Lee amsdu->trig_thres = cpu_to_le16(2);
579b443e55fSRyder Lee amsdu->enable = true;
580b443e55fSRyder Lee }
581b443e55fSRyder Lee
582b443e55fSRyder Lee static void
mt7915_mcu_bss_bmc_tlv(struct sk_buff * skb,struct mt7915_phy * phy)583e57b7901SRyder Lee mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy)
584e57b7901SRyder Lee {
585e57b7901SRyder Lee struct bss_info_bmc_rate *bmc;
586e57b7901SRyder Lee struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
587e57b7901SRyder Lee enum nl80211_band band = chandef->chan->band;
588e57b7901SRyder Lee struct tlv *tlv;
589e57b7901SRyder Lee
590069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc));
591e57b7901SRyder Lee
592e57b7901SRyder Lee bmc = (struct bss_info_bmc_rate *)tlv;
593e57b7901SRyder Lee if (band == NL80211_BAND_2GHZ) {
594e57b7901SRyder Lee bmc->short_preamble = true;
595e57b7901SRyder Lee } else {
596e57b7901SRyder Lee bmc->bc_trans = cpu_to_le16(0x2000);
597e57b7901SRyder Lee bmc->mc_trans = cpu_to_le16(0x2080);
598e57b7901SRyder Lee }
599e57b7901SRyder Lee }
600e57b7901SRyder Lee
6018aa2c6f4SFelix Fietkau static int
mt7915_mcu_muar_config(struct mt7915_phy * phy,struct ieee80211_vif * vif,bool bssid,bool enable)6028aa2c6f4SFelix Fietkau mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif,
6038aa2c6f4SFelix Fietkau bool bssid, bool enable)
6048aa2c6f4SFelix Fietkau {
6058aa2c6f4SFelix Fietkau struct mt7915_dev *dev = phy->dev;
6068aa2c6f4SFelix Fietkau struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
6076cf4392fSLorenzo Bianconi u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
6088aa2c6f4SFelix Fietkau u32 mask = phy->omac_mask >> 32 & ~BIT(idx);
6098aa2c6f4SFelix Fietkau const u8 *addr = vif->addr;
6108aa2c6f4SFelix Fietkau struct {
6118aa2c6f4SFelix Fietkau u8 mode;
6128aa2c6f4SFelix Fietkau u8 force_clear;
6138aa2c6f4SFelix Fietkau u8 clear_bitmap[8];
6148aa2c6f4SFelix Fietkau u8 entry_count;
6158aa2c6f4SFelix Fietkau u8 write;
6168aa2c6f4SFelix Fietkau u8 band;
6178aa2c6f4SFelix Fietkau
6188aa2c6f4SFelix Fietkau u8 index;
6198aa2c6f4SFelix Fietkau u8 bssid;
6208aa2c6f4SFelix Fietkau u8 addr[ETH_ALEN];
6218aa2c6f4SFelix Fietkau } __packed req = {
6228aa2c6f4SFelix Fietkau .mode = !!mask || enable,
6238aa2c6f4SFelix Fietkau .entry_count = 1,
6248aa2c6f4SFelix Fietkau .write = 1,
6253eb50cc9SRyder Lee .band = phy->mt76->band_idx,
6268aa2c6f4SFelix Fietkau .index = idx * 2 + bssid,
6278aa2c6f4SFelix Fietkau };
6288aa2c6f4SFelix Fietkau
6298aa2c6f4SFelix Fietkau if (bssid)
6308aa2c6f4SFelix Fietkau addr = vif->bss_conf.bssid;
6318aa2c6f4SFelix Fietkau
6328aa2c6f4SFelix Fietkau if (enable)
6338aa2c6f4SFelix Fietkau ether_addr_copy(req.addr, addr);
6348aa2c6f4SFelix Fietkau
635c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req,
636cb5cdd4cSFelix Fietkau sizeof(req), true);
6378aa2c6f4SFelix Fietkau }
6388aa2c6f4SFelix Fietkau
mt7915_mcu_add_bss_info(struct mt7915_phy * phy,struct ieee80211_vif * vif,int enable)639e57b7901SRyder Lee int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
640e57b7901SRyder Lee struct ieee80211_vif *vif, int enable)
641e57b7901SRyder Lee {
642e57b7901SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
643e2c93b68SLorenzo Bianconi struct mt7915_dev *dev = phy->dev;
644e57b7901SRyder Lee struct sk_buff *skb;
645e57b7901SRyder Lee
6466cf4392fSLorenzo Bianconi if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) {
6479add4bf2SFelix Fietkau mt7915_mcu_muar_config(phy, vif, false, enable);
6488aa2c6f4SFelix Fietkau mt7915_mcu_muar_config(phy, vif, true, enable);
6499add4bf2SFelix Fietkau }
6508aa2c6f4SFelix Fietkau
651e2c93b68SLorenzo Bianconi skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
6523e68af62SRyder Lee MT7915_BSS_UPDATE_MAX_SIZE);
653e57b7901SRyder Lee if (IS_ERR(skb))
654e57b7901SRyder Lee return PTR_ERR(skb);
655e57b7901SRyder Lee
656e57b7901SRyder Lee /* bss_omac must be first */
657e57b7901SRyder Lee if (enable)
65854735e11SLorenzo Bianconi mt76_connac_mcu_bss_omac_tlv(skb, vif);
659e57b7901SRyder Lee
66049126ac1SLorenzo Bianconi mt76_connac_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76,
66149126ac1SLorenzo Bianconi mvif->sta.wcid.idx, enable);
662e57b7901SRyder Lee
663dae0dc2bSShayne Chen if (vif->type == NL80211_IFTYPE_MONITOR)
664dae0dc2bSShayne Chen goto out;
665dae0dc2bSShayne Chen
666e57b7901SRyder Lee if (enable) {
667e57b7901SRyder Lee mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
668e57b7901SRyder Lee mt7915_mcu_bss_bmc_tlv(skb, phy);
669e57b7901SRyder Lee mt7915_mcu_bss_ra_tlv(skb, vif, phy);
670b443e55fSRyder Lee mt7915_mcu_bss_hw_amsdu_tlv(skb);
671e57b7901SRyder Lee
6726094f86fSRyder Lee if (vif->bss_conf.he_support)
6736094f86fSRyder Lee mt7915_mcu_bss_he_tlv(skb, vif, phy);
6746094f86fSRyder Lee
6756cf4392fSLorenzo Bianconi if (mvif->mt76.omac_idx >= EXT_BSSID_START &&
6766cf4392fSLorenzo Bianconi mvif->mt76.omac_idx < REPEATER_BSSID_START)
67764f4e823SLorenzo Bianconi mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
678e57b7901SRyder Lee }
679dae0dc2bSShayne Chen out:
680e2c93b68SLorenzo Bianconi return mt76_mcu_skb_send_msg(&dev->mt76, skb,
681c203dd62SFelix Fietkau MCU_EXT_CMD(BSS_INFO_UPDATE), true);
682e57b7901SRyder Lee }
683e57b7901SRyder Lee
684e57b7901SRyder Lee /** starec & wtbl **/
mt7915_mcu_add_tx_ba(struct mt7915_dev * dev,struct ieee80211_ampdu_params * params,bool enable)685e57b7901SRyder Lee int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
686e57b7901SRyder Lee struct ieee80211_ampdu_params *params,
687e57b7901SRyder Lee bool enable)
688e57b7901SRyder Lee {
689b5322e44SLorenzo Bianconi struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
690b5322e44SLorenzo Bianconi struct mt7915_vif *mvif = msta->vif;
6913f5625e9SFelix Fietkau int ret;
692b5322e44SLorenzo Bianconi
6933f5625e9SFelix Fietkau mt76_worker_disable(&dev->mt76.tx_worker);
694b5322e44SLorenzo Bianconi if (enable && !params->amsdu)
695b5322e44SLorenzo Bianconi msta->wcid.amsdu = false;
6963f5625e9SFelix Fietkau ret = mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
697b5322e44SLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE),
698b5322e44SLorenzo Bianconi enable, true);
6993f5625e9SFelix Fietkau mt76_worker_enable(&dev->mt76.tx_worker);
7003f5625e9SFelix Fietkau
7013f5625e9SFelix Fietkau return ret;
702e57b7901SRyder Lee }
703e57b7901SRyder Lee
mt7915_mcu_add_rx_ba(struct mt7915_dev * dev,struct ieee80211_ampdu_params * params,bool enable)704e57b7901SRyder Lee int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
705e57b7901SRyder Lee struct ieee80211_ampdu_params *params,
706e57b7901SRyder Lee bool enable)
707e57b7901SRyder Lee {
708b5322e44SLorenzo Bianconi struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
709b5322e44SLorenzo Bianconi struct mt7915_vif *mvif = msta->vif;
710b5322e44SLorenzo Bianconi
711b5322e44SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
712b5322e44SLorenzo Bianconi MCU_EXT_CMD(STA_REC_UPDATE),
713b5322e44SLorenzo Bianconi enable, false);
714e57b7901SRyder Lee }
715e57b7901SRyder Lee
716e57b7901SRyder Lee static void
mt7915_mcu_sta_he_tlv(struct sk_buff * skb,struct ieee80211_sta * sta,struct ieee80211_vif * vif)71722dffbddSRyder Lee mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
71822dffbddSRyder Lee struct ieee80211_vif *vif)
719c336318fSRyder Lee {
72002a89404SFelix Fietkau struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
721046d2e7cSSriram R struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
722ade25ca7SPeter Chiu struct ieee80211_he_mcs_nss_supp mcs_map;
723c336318fSRyder Lee struct sta_rec_he *he;
724c336318fSRyder Lee struct tlv *tlv;
725c336318fSRyder Lee u32 cap = 0;
726c336318fSRyder Lee
727046d2e7cSSriram R if (!sta->deflink.he_cap.has_he)
72889bbd373SShayne Chen return;
72989bbd373SShayne Chen
730069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
731c336318fSRyder Lee
732c336318fSRyder Lee he = (struct sta_rec_he *)tlv;
733c336318fSRyder Lee
734c336318fSRyder Lee if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)
735c336318fSRyder Lee cap |= STA_REC_HE_CAP_HTC;
736c336318fSRyder Lee
737c336318fSRyder Lee if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
738c336318fSRyder Lee cap |= STA_REC_HE_CAP_BSR;
739c336318fSRyder Lee
740c336318fSRyder Lee if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
741c336318fSRyder Lee cap |= STA_REC_HE_CAP_OM;
742c336318fSRyder Lee
7432f516444SJohannes Berg if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU)
744c336318fSRyder Lee cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU;
745c336318fSRyder Lee
746c336318fSRyder Lee if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
747c336318fSRyder Lee cap |= STA_REC_HE_CAP_BQR;
748c336318fSRyder Lee
749c336318fSRyder Lee if (elem->phy_cap_info[0] &
750c336318fSRyder Lee (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G |
751c336318fSRyder Lee IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
752c336318fSRyder Lee cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
753c336318fSRyder Lee
75402a89404SFelix Fietkau if (mvif->cap.he_ldpc &&
755499da720SMeiChia Chiu (elem->phy_cap_info[1] &
75622dffbddSRyder Lee IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
757c336318fSRyder Lee cap |= STA_REC_HE_CAP_LDPC;
758c336318fSRyder Lee
759c336318fSRyder Lee if (elem->phy_cap_info[1] &
760c336318fSRyder Lee IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US)
761c336318fSRyder Lee cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI;
762c336318fSRyder Lee
763c336318fSRyder Lee if (elem->phy_cap_info[2] &
764c336318fSRyder Lee IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US)
765c336318fSRyder Lee cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI;
766c336318fSRyder Lee
767c336318fSRyder Lee if (elem->phy_cap_info[2] &
768c336318fSRyder Lee IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ)
769c336318fSRyder Lee cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC;
770c336318fSRyder Lee
771c336318fSRyder Lee if (elem->phy_cap_info[2] &
772c336318fSRyder Lee IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
773c336318fSRyder Lee cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;
774c336318fSRyder Lee
775c336318fSRyder Lee if (elem->phy_cap_info[6] &
7763176487fSShayne Chen IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB)
7773176487fSShayne Chen cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
7783176487fSShayne Chen
7793176487fSShayne Chen if (elem->phy_cap_info[6] &
780c336318fSRyder Lee IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)
781c336318fSRyder Lee cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;
782c336318fSRyder Lee
783c336318fSRyder Lee if (elem->phy_cap_info[7] &
784c336318fSRyder Lee IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI)
785c336318fSRyder Lee cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI;
786c336318fSRyder Lee
787c336318fSRyder Lee if (elem->phy_cap_info[7] &
788c336318fSRyder Lee IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ)
789c336318fSRyder Lee cap |= STA_REC_HE_CAP_GT_80M_TX_STBC;
790c336318fSRyder Lee
791c336318fSRyder Lee if (elem->phy_cap_info[7] &
792c336318fSRyder Lee IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
793c336318fSRyder Lee cap |= STA_REC_HE_CAP_GT_80M_RX_STBC;
794c336318fSRyder Lee
795c336318fSRyder Lee if (elem->phy_cap_info[8] &
796c336318fSRyder Lee IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI)
797c336318fSRyder Lee cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI;
798c336318fSRyder Lee
799c336318fSRyder Lee if (elem->phy_cap_info[8] &
800c336318fSRyder Lee IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI)
801c336318fSRyder Lee cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;
802c336318fSRyder Lee
803c336318fSRyder Lee if (elem->phy_cap_info[9] &
804c336318fSRyder Lee IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)
805c336318fSRyder Lee cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;
806c336318fSRyder Lee
807c336318fSRyder Lee if (elem->phy_cap_info[9] &
808c336318fSRyder Lee IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU)
809c336318fSRyder Lee cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242;
810c336318fSRyder Lee
811c336318fSRyder Lee he->he_cap = cpu_to_le32(cap);
812c336318fSRyder Lee
813046d2e7cSSriram R mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
814046d2e7cSSriram R switch (sta->deflink.bandwidth) {
815c336318fSRyder Lee case IEEE80211_STA_RX_BW_160:
816c336318fSRyder Lee if (elem->phy_cap_info[0] &
817c336318fSRyder Lee IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
81876be6c07SRyder Lee mt7915_mcu_set_sta_he_mcs(sta,
81976be6c07SRyder Lee &he->max_nss_mcs[CMD_HE_MCS_BW8080],
820ade25ca7SPeter Chiu le16_to_cpu(mcs_map.rx_mcs_80p80));
821c336318fSRyder Lee
82276be6c07SRyder Lee mt7915_mcu_set_sta_he_mcs(sta,
82376be6c07SRyder Lee &he->max_nss_mcs[CMD_HE_MCS_BW160],
824ade25ca7SPeter Chiu le16_to_cpu(mcs_map.rx_mcs_160));
825aab662ccSGustavo A. R. Silva fallthrough;
826c336318fSRyder Lee default:
82776be6c07SRyder Lee mt7915_mcu_set_sta_he_mcs(sta,
82876be6c07SRyder Lee &he->max_nss_mcs[CMD_HE_MCS_BW80],
829ade25ca7SPeter Chiu le16_to_cpu(mcs_map.rx_mcs_80));
830c336318fSRyder Lee break;
831c336318fSRyder Lee }
832c336318fSRyder Lee
833c336318fSRyder Lee he->t_frame_dur =
834c336318fSRyder Lee HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
835c336318fSRyder Lee he->max_ampdu_exp =
836c336318fSRyder Lee HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]);
837c336318fSRyder Lee
838c336318fSRyder Lee he->bw_set =
839c336318fSRyder Lee HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]);
840c336318fSRyder Lee he->device_class =
841c336318fSRyder Lee HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]);
842c336318fSRyder Lee he->punc_pream_rx =
843c336318fSRyder Lee HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
844c336318fSRyder Lee
845c336318fSRyder Lee he->dcm_tx_mode =
846c336318fSRyder Lee HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]);
847c336318fSRyder Lee he->dcm_tx_max_nss =
848c336318fSRyder Lee HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]);
849c336318fSRyder Lee he->dcm_rx_mode =
850c336318fSRyder Lee HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]);
851c336318fSRyder Lee he->dcm_rx_max_nss =
852c336318fSRyder Lee HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]);
853c336318fSRyder Lee he->dcm_rx_max_nss =
854c336318fSRyder Lee HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]);
855c336318fSRyder Lee
856c336318fSRyder Lee he->pkt_ext = 2;
857c336318fSRyder Lee }
858c336318fSRyder Lee
859c336318fSRyder Lee static void
mt7915_mcu_sta_muru_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_sta * sta,struct ieee80211_vif * vif)860c3f2ed58SFelix Fietkau mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
861c3f2ed58SFelix Fietkau struct ieee80211_sta *sta, struct ieee80211_vif *vif)
862c336318fSRyder Lee {
86302a89404SFelix Fietkau struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
864046d2e7cSSriram R struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
865c336318fSRyder Lee struct sta_rec_muru *muru;
866c336318fSRyder Lee struct tlv *tlv;
867c336318fSRyder Lee
86816bff457SShayne Chen if (vif->type != NL80211_IFTYPE_STATION &&
86916bff457SShayne Chen vif->type != NL80211_IFTYPE_AP)
87016bff457SShayne Chen return;
87116bff457SShayne Chen
872069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
873c336318fSRyder Lee
874c336318fSRyder Lee muru = (struct sta_rec_muru *)tlv;
87522dffbddSRyder Lee
87602a89404SFelix Fietkau muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
87702a89404SFelix Fietkau mvif->cap.vht_mu_ebfer ||
87802a89404SFelix Fietkau mvif->cap.vht_mu_ebfee;
879c3f2ed58SFelix Fietkau if (!is_mt7915(&dev->mt76))
880d98a7272SMeiChia Chiu muru->cfg.mimo_ul_en = true;
881d98a7272SMeiChia Chiu muru->cfg.ofdma_dl_en = true;
882c336318fSRyder Lee
883046d2e7cSSriram R if (sta->deflink.vht_cap.vht_supported)
88416bff457SShayne Chen muru->mimo_dl.vht_mu_bfee =
885046d2e7cSSriram R !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
88616bff457SShayne Chen
887046d2e7cSSriram R if (!sta->deflink.he_cap.has_he)
88816bff457SShayne Chen return;
88916bff457SShayne Chen
89016bff457SShayne Chen muru->mimo_dl.partial_bw_dl_mimo =
89116bff457SShayne Chen HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
89216bff457SShayne Chen
89316bff457SShayne Chen muru->mimo_ul.full_ul_mimo =
89416bff457SShayne Chen HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
89516bff457SShayne Chen muru->mimo_ul.partial_ul_mimo =
89616bff457SShayne Chen HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
89716bff457SShayne Chen
898c336318fSRyder Lee muru->ofdma_dl.punc_pream_rx =
899c336318fSRyder Lee HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
900c336318fSRyder Lee muru->ofdma_dl.he_20m_in_40m_2g =
901c336318fSRyder Lee HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
902c336318fSRyder Lee muru->ofdma_dl.he_20m_in_160m =
903c336318fSRyder Lee HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
904c336318fSRyder Lee muru->ofdma_dl.he_80m_in_160m =
905c336318fSRyder Lee HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
906c336318fSRyder Lee
907c336318fSRyder Lee muru->ofdma_ul.t_frame_dur =
908c336318fSRyder Lee HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
909c336318fSRyder Lee muru->ofdma_ul.mu_cascading =
910c336318fSRyder Lee HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
911c336318fSRyder Lee muru->ofdma_ul.uo_ra =
912c336318fSRyder Lee HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
913c336318fSRyder Lee }
914c336318fSRyder Lee
915b70946ceSRyder Lee static void
mt7915_mcu_sta_ht_tlv(struct sk_buff * skb,struct ieee80211_sta * sta)91689bbd373SShayne Chen mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
91789bbd373SShayne Chen {
91889bbd373SShayne Chen struct sta_rec_ht *ht;
91989bbd373SShayne Chen struct tlv *tlv;
92089bbd373SShayne Chen
921046d2e7cSSriram R if (!sta->deflink.ht_cap.ht_supported)
922b4d093e3SMeiChia Chiu return;
923b4d093e3SMeiChia Chiu
924069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
92589bbd373SShayne Chen
92689bbd373SShayne Chen ht = (struct sta_rec_ht *)tlv;
927046d2e7cSSriram R ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
92889bbd373SShayne Chen }
92989bbd373SShayne Chen
93089bbd373SShayne Chen static void
mt7915_mcu_sta_vht_tlv(struct sk_buff * skb,struct ieee80211_sta * sta)931b70946ceSRyder Lee mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
932f68e6a1fSRyder Lee {
933b70946ceSRyder Lee struct sta_rec_vht *vht;
934b70946ceSRyder Lee struct tlv *tlv;
935f68e6a1fSRyder Lee
936046d2e7cSSriram R if (!sta->deflink.vht_cap.vht_supported)
93789bbd373SShayne Chen return;
93889bbd373SShayne Chen
939069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
940f68e6a1fSRyder Lee
941b70946ceSRyder Lee vht = (struct sta_rec_vht *)tlv;
942046d2e7cSSriram R vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
943046d2e7cSSriram R vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
944046d2e7cSSriram R vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
945f68e6a1fSRyder Lee }
946f68e6a1fSRyder Lee
947c336318fSRyder Lee static void
mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)948be1954ffSPeter Chiu mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
949be1954ffSPeter Chiu struct ieee80211_vif *vif, struct ieee80211_sta *sta)
950b443e55fSRyder Lee {
951b443e55fSRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
952b443e55fSRyder Lee struct sta_rec_amsdu *amsdu;
953b443e55fSRyder Lee struct tlv *tlv;
954b443e55fSRyder Lee
95589bbd373SShayne Chen if (vif->type != NL80211_IFTYPE_STATION &&
95689bbd373SShayne Chen vif->type != NL80211_IFTYPE_AP)
95789bbd373SShayne Chen return;
95889bbd373SShayne Chen
9594c51541dSBenjamin Berg if (!sta->deflink.agg.max_amsdu_len)
960b443e55fSRyder Lee return;
961b443e55fSRyder Lee
962069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
963b443e55fSRyder Lee amsdu = (struct sta_rec_amsdu *)tlv;
964b443e55fSRyder Lee amsdu->max_amsdu_num = 8;
965b443e55fSRyder Lee amsdu->amsdu_en = true;
966b443e55fSRyder Lee msta->wcid.amsdu = true;
967be1954ffSPeter Chiu
9684c51541dSBenjamin Berg switch (sta->deflink.agg.max_amsdu_len) {
969be1954ffSPeter Chiu case IEEE80211_MAX_MPDU_LEN_VHT_11454:
970be1954ffSPeter Chiu if (!is_mt7915(&dev->mt76)) {
971be1954ffSPeter Chiu amsdu->max_mpdu_size =
972be1954ffSPeter Chiu IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
973be1954ffSPeter Chiu return;
974be1954ffSPeter Chiu }
975be1954ffSPeter Chiu fallthrough;
976be1954ffSPeter Chiu case IEEE80211_MAX_MPDU_LEN_HT_7935:
977be1954ffSPeter Chiu case IEEE80211_MAX_MPDU_LEN_VHT_7991:
978be1954ffSPeter Chiu amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
979be1954ffSPeter Chiu return;
980be1954ffSPeter Chiu default:
981be1954ffSPeter Chiu amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
982be1954ffSPeter Chiu return;
983be1954ffSPeter Chiu }
984b443e55fSRyder Lee }
985b443e55fSRyder Lee
98689bbd373SShayne Chen static int
mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)98789bbd373SShayne Chen mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
98889bbd373SShayne Chen struct ieee80211_vif *vif, struct ieee80211_sta *sta)
98989bbd373SShayne Chen {
99089bbd373SShayne Chen struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
99189bbd373SShayne Chen struct mt7915_sta *msta;
99289bbd373SShayne Chen struct wtbl_req_hdr *wtbl_hdr;
9935121585eSLorenzo Bianconi struct mt76_wcid *wcid;
99489bbd373SShayne Chen struct tlv *tlv;
99589bbd373SShayne Chen
99689bbd373SShayne Chen msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
9975121585eSLorenzo Bianconi wcid = sta ? &msta->wcid : NULL;
99889bbd373SShayne Chen
999069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
1000a0792e15SLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
1001a0792e15SLorenzo Bianconi WTBL_RESET_AND_SET, tlv,
1002a0792e15SLorenzo Bianconi &skb);
100389bbd373SShayne Chen if (IS_ERR(wtbl_hdr))
100489bbd373SShayne Chen return PTR_ERR(wtbl_hdr);
100589bbd373SShayne Chen
1006c7720971SLorenzo Bianconi mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, skb, vif, sta, tlv,
1007c7720971SLorenzo Bianconi wtbl_hdr);
10085121585eSLorenzo Bianconi mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
100989bbd373SShayne Chen if (sta)
1010187169deSLorenzo Bianconi mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
101102a89404SFelix Fietkau wtbl_hdr, mvif->cap.ht_ldpc,
101202a89404SFelix Fietkau mvif->cap.vht_ldpc);
101389bbd373SShayne Chen
101489bbd373SShayne Chen return 0;
101589bbd373SShayne Chen }
101689bbd373SShayne Chen
1017f89f297aSRyder Lee static inline bool
mt7915_is_ebf_supported(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool bfee)1018f89f297aSRyder Lee mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
1019f89f297aSRyder Lee struct ieee80211_sta *sta, bool bfee)
1020f89f297aSRyder Lee {
102102a89404SFelix Fietkau struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1022f03f274bSMeiChia Chiu int sts = hweight16(phy->mt76->chainmask);
1023f89f297aSRyder Lee
1024f89f297aSRyder Lee if (vif->type != NL80211_IFTYPE_STATION &&
1025f89f297aSRyder Lee vif->type != NL80211_IFTYPE_AP)
1026f89f297aSRyder Lee return false;
1027f89f297aSRyder Lee
1028f03f274bSMeiChia Chiu if (!bfee && sts < 2)
1029f89f297aSRyder Lee return false;
1030f89f297aSRyder Lee
1031046d2e7cSSriram R if (sta->deflink.he_cap.has_he) {
1032046d2e7cSSriram R struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
1033f89f297aSRyder Lee
1034f89f297aSRyder Lee if (bfee)
103502a89404SFelix Fietkau return mvif->cap.he_su_ebfee &&
1036f89f297aSRyder Lee HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
1037f89f297aSRyder Lee else
103802a89404SFelix Fietkau return mvif->cap.he_su_ebfer &&
1039f89f297aSRyder Lee HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
1040f89f297aSRyder Lee }
1041f89f297aSRyder Lee
1042046d2e7cSSriram R if (sta->deflink.vht_cap.vht_supported) {
1043046d2e7cSSriram R u32 cap = sta->deflink.vht_cap.cap;
1044f89f297aSRyder Lee
1045f89f297aSRyder Lee if (bfee)
104602a89404SFelix Fietkau return mvif->cap.vht_su_ebfee &&
1047f89f297aSRyder Lee (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
1048f89f297aSRyder Lee else
104902a89404SFelix Fietkau return mvif->cap.vht_su_ebfer &&
1050f89f297aSRyder Lee (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
1051f89f297aSRyder Lee }
1052f89f297aSRyder Lee
1053f89f297aSRyder Lee return false;
1054f89f297aSRyder Lee }
1055f89f297aSRyder Lee
1056e57b7901SRyder Lee static void
mt7915_mcu_sta_sounding_rate(struct sta_rec_bf * bf)105789029a85SRyder Lee mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
105889029a85SRyder Lee {
105989029a85SRyder Lee bf->sounding_phy = MT_PHY_TYPE_OFDM;
106089029a85SRyder Lee bf->ndp_rate = 0; /* mcs0 */
106189029a85SRyder Lee bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */
106289029a85SRyder Lee bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */
106389029a85SRyder Lee }
106489029a85SRyder Lee
106589029a85SRyder Lee static void
mt7915_mcu_sta_bfer_ht(struct ieee80211_sta * sta,struct mt7915_phy * phy,struct sta_rec_bf * bf)10666d6dc980SRyder Lee mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
10676d6dc980SRyder Lee struct sta_rec_bf *bf)
106889029a85SRyder Lee {
1069046d2e7cSSriram R struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
107089029a85SRyder Lee u8 n = 0;
107189029a85SRyder Lee
107289029a85SRyder Lee bf->tx_mode = MT_PHY_TYPE_HT;
107389029a85SRyder Lee
10742c3b26f2SLorenzo Bianconi if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) &&
107589029a85SRyder Lee (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED))
107689029a85SRyder Lee n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK,
107789029a85SRyder Lee mcs->tx_params);
107889029a85SRyder Lee else if (mcs->rx_mask[3])
107989029a85SRyder Lee n = 3;
108089029a85SRyder Lee else if (mcs->rx_mask[2])
108189029a85SRyder Lee n = 2;
108289029a85SRyder Lee else if (mcs->rx_mask[1])
108389029a85SRyder Lee n = 1;
108489029a85SRyder Lee
1085a56c431eSRyder Lee bf->nrow = hweight8(phy->mt76->chainmask) - 1;
1086a56c431eSRyder Lee bf->ncol = min_t(u8, bf->nrow, n);
10876d6dc980SRyder Lee bf->ibf_ncol = n;
108889029a85SRyder Lee }
108989029a85SRyder Lee
109089029a85SRyder Lee static void
mt7915_mcu_sta_bfer_vht(struct ieee80211_sta * sta,struct mt7915_phy * phy,struct sta_rec_bf * bf,bool explicit)109189029a85SRyder Lee mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
10926d6dc980SRyder Lee struct sta_rec_bf *bf, bool explicit)
109389029a85SRyder Lee {
1094046d2e7cSSriram R struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
109589029a85SRyder Lee struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
10966d6dc980SRyder Lee u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
10976d6dc980SRyder Lee u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
10986d6dc980SRyder Lee u8 tx_ant = hweight8(phy->mt76->chainmask) - 1;
109989029a85SRyder Lee
110089029a85SRyder Lee bf->tx_mode = MT_PHY_TYPE_VHT;
11016d6dc980SRyder Lee
11026d6dc980SRyder Lee if (explicit) {
1103a56c431eSRyder Lee u8 sts, snd_dim;
110489029a85SRyder Lee
110589029a85SRyder Lee mt7915_mcu_sta_sounding_rate(bf);
1106a56c431eSRyder Lee
1107a56c431eSRyder Lee sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
110889029a85SRyder Lee pc->cap);
1109a56c431eSRyder Lee snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
111089029a85SRyder Lee vc->cap);
1111a56c431eSRyder Lee bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
1112a56c431eSRyder Lee bf->ncol = min_t(u8, nss_mcs, bf->nrow);
1113a56c431eSRyder Lee bf->ibf_ncol = bf->ncol;
111489029a85SRyder Lee
1115046d2e7cSSriram R if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
1116a56c431eSRyder Lee bf->nrow = 1;
11176d6dc980SRyder Lee } else {
1118a56c431eSRyder Lee bf->nrow = tx_ant;
1119a56c431eSRyder Lee bf->ncol = min_t(u8, nss_mcs, bf->nrow);
11206d6dc980SRyder Lee bf->ibf_ncol = nss_mcs;
11216d6dc980SRyder Lee
1122046d2e7cSSriram R if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
11236d6dc980SRyder Lee bf->ibf_nrow = 1;
11246d6dc980SRyder Lee }
112589029a85SRyder Lee }
112689029a85SRyder Lee
112789029a85SRyder Lee static void
mt7915_mcu_sta_bfer_he(struct ieee80211_sta * sta,struct ieee80211_vif * vif,struct mt7915_phy * phy,struct sta_rec_bf * bf)112889029a85SRyder Lee mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
112989029a85SRyder Lee struct mt7915_phy *phy, struct sta_rec_bf *bf)
113089029a85SRyder Lee {
1131046d2e7cSSriram R struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
113289029a85SRyder Lee struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
1133e6d557a7SLorenzo Bianconi const struct ieee80211_sta_he_cap *vc =
1134e6d557a7SLorenzo Bianconi mt76_connac_get_he_phy_cap(phy->mt76, vif);
11356d6dc980SRyder Lee const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
11366d6dc980SRyder Lee u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
11376d6dc980SRyder Lee u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
1138a56c431eSRyder Lee u8 snd_dim, sts;
113989029a85SRyder Lee
114089029a85SRyder Lee bf->tx_mode = MT_PHY_TYPE_HE_SU;
1141a56c431eSRyder Lee
114289029a85SRyder Lee mt7915_mcu_sta_sounding_rate(bf);
1143a56c431eSRyder Lee
114476cf4221SJohannes Berg bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
114589029a85SRyder Lee pe->phy_cap_info[6]);
114676cf4221SJohannes Berg bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
114789029a85SRyder Lee pe->phy_cap_info[6]);
1148a56c431eSRyder Lee snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
114989029a85SRyder Lee ve->phy_cap_info[5]);
1150a56c431eSRyder Lee sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
115189029a85SRyder Lee pe->phy_cap_info[4]);
1152a56c431eSRyder Lee bf->nrow = min_t(u8, snd_dim, sts);
1153a56c431eSRyder Lee bf->ncol = min_t(u8, nss_mcs, bf->nrow);
1154a56c431eSRyder Lee bf->ibf_ncol = bf->ncol;
115589029a85SRyder Lee
1156046d2e7cSSriram R if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
115789029a85SRyder Lee return;
115889029a85SRyder Lee
115989029a85SRyder Lee /* go over for 160MHz and 80p80 */
116089029a85SRyder Lee if (pe->phy_cap_info[0] &
116189029a85SRyder Lee IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
116289029a85SRyder Lee mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160);
116389029a85SRyder Lee nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
116489029a85SRyder Lee
1165cade6939SShayne Chen bf->ncol_gt_bw80 = nss_mcs;
116689029a85SRyder Lee }
116789029a85SRyder Lee
116889029a85SRyder Lee if (pe->phy_cap_info[0] &
116989029a85SRyder Lee IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
117089029a85SRyder Lee mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80);
117189029a85SRyder Lee nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
117289029a85SRyder Lee
1173cade6939SShayne Chen if (bf->ncol_gt_bw80)
1174cade6939SShayne Chen bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs);
117589029a85SRyder Lee else
1176cade6939SShayne Chen bf->ncol_gt_bw80 = nss_mcs;
117789029a85SRyder Lee }
117889029a85SRyder Lee
1179a56c431eSRyder Lee snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
118089029a85SRyder Lee ve->phy_cap_info[5]);
1181a56c431eSRyder Lee sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
118289029a85SRyder Lee pe->phy_cap_info[4]);
118389029a85SRyder Lee
1184cade6939SShayne Chen bf->nrow_gt_bw80 = min_t(int, snd_dim, sts);
118589029a85SRyder Lee }
118689029a85SRyder Lee
118789029a85SRyder Lee static void
mt7915_mcu_sta_bfer_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1188f89f297aSRyder Lee mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
1189f89f297aSRyder Lee struct ieee80211_vif *vif, struct ieee80211_sta *sta)
119089029a85SRyder Lee {
1191f89f297aSRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1192006b9d4aSBo Jiao struct mt7915_phy *phy = mvif->phy;
1193b9027e08SLorenzo Bianconi int tx_ant = hweight8(phy->mt76->chainmask) - 1;
119489029a85SRyder Lee struct sta_rec_bf *bf;
119589029a85SRyder Lee struct tlv *tlv;
119689029a85SRyder Lee const u8 matrix[4][4] = {
119789029a85SRyder Lee {0, 0, 0, 0},
119889029a85SRyder Lee {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */
119989029a85SRyder Lee {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */
120089029a85SRyder Lee {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */
120189029a85SRyder Lee };
1202f89f297aSRyder Lee bool ebf;
120389029a85SRyder Lee
1204046d2e7cSSriram R if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
1205b4d093e3SMeiChia Chiu return;
1206b4d093e3SMeiChia Chiu
1207f89f297aSRyder Lee ebf = mt7915_is_ebf_supported(phy, vif, sta, false);
1208f89f297aSRyder Lee if (!ebf && !dev->ibf)
1209f89f297aSRyder Lee return;
121089029a85SRyder Lee
1211069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
121289029a85SRyder Lee bf = (struct sta_rec_bf *)tlv;
121389029a85SRyder Lee
12146d6dc980SRyder Lee /* he: eBF only, in accordance with spec
12156d6dc980SRyder Lee * vht: support eBF and iBF
12166d6dc980SRyder Lee * ht: iBF only, since mac80211 lacks of eBF support
12176d6dc980SRyder Lee */
1218046d2e7cSSriram R if (sta->deflink.he_cap.has_he && ebf)
12196d6dc980SRyder Lee mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
1220046d2e7cSSriram R else if (sta->deflink.vht_cap.vht_supported)
1221f89f297aSRyder Lee mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
1222046d2e7cSSriram R else if (sta->deflink.ht_cap.ht_supported)
12236d6dc980SRyder Lee mt7915_mcu_sta_bfer_ht(sta, phy, bf);
12246d6dc980SRyder Lee else
12256d6dc980SRyder Lee return;
12266d6dc980SRyder Lee
1227a56c431eSRyder Lee bf->bf_cap = ebf ? ebf : dev->ibf << 1;
1228046d2e7cSSriram R bf->bw = sta->deflink.bandwidth;
1229046d2e7cSSriram R bf->ibf_dbw = sta->deflink.bandwidth;
123089029a85SRyder Lee bf->ibf_nrow = tx_ant;
12316d6dc980SRyder Lee
1232046d2e7cSSriram R if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
12336d6dc980SRyder Lee bf->ibf_timeout = 0x48;
12346d6dc980SRyder Lee else
123589029a85SRyder Lee bf->ibf_timeout = 0x18;
123689029a85SRyder Lee
1237a56c431eSRyder Lee if (ebf && bf->nrow != tx_ant)
1238a56c431eSRyder Lee bf->mem_20m = matrix[tx_ant][bf->ncol];
123989029a85SRyder Lee else
1240a56c431eSRyder Lee bf->mem_20m = matrix[bf->nrow][bf->ncol];
124189029a85SRyder Lee
1242046d2e7cSSriram R switch (sta->deflink.bandwidth) {
124389029a85SRyder Lee case IEEE80211_STA_RX_BW_160:
124489029a85SRyder Lee case IEEE80211_STA_RX_BW_80:
124589029a85SRyder Lee bf->mem_total = bf->mem_20m * 2;
124689029a85SRyder Lee break;
124789029a85SRyder Lee case IEEE80211_STA_RX_BW_40:
124889029a85SRyder Lee bf->mem_total = bf->mem_20m;
124989029a85SRyder Lee break;
125089029a85SRyder Lee case IEEE80211_STA_RX_BW_20:
125189029a85SRyder Lee default:
125289029a85SRyder Lee break;
125389029a85SRyder Lee }
125489029a85SRyder Lee }
125589029a85SRyder Lee
12562af34fa3SRyder Lee static void
mt7915_mcu_sta_bfee_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1257f89f297aSRyder Lee mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
1258f89f297aSRyder Lee struct ieee80211_vif *vif, struct ieee80211_sta *sta)
12592af34fa3SRyder Lee {
1260f89f297aSRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1261006b9d4aSBo Jiao struct mt7915_phy *phy = mvif->phy;
1262b9027e08SLorenzo Bianconi int tx_ant = hweight8(phy->mt76->chainmask) - 1;
12632af34fa3SRyder Lee struct sta_rec_bfee *bfee;
12642af34fa3SRyder Lee struct tlv *tlv;
1265a56c431eSRyder Lee u8 nrow = 0;
12662af34fa3SRyder Lee
1267046d2e7cSSriram R if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
1268b4d093e3SMeiChia Chiu return;
1269b4d093e3SMeiChia Chiu
1270f89f297aSRyder Lee if (!mt7915_is_ebf_supported(phy, vif, sta, true))
1271f89f297aSRyder Lee return;
1272f89f297aSRyder Lee
1273069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
12742af34fa3SRyder Lee bfee = (struct sta_rec_bfee *)tlv;
12752af34fa3SRyder Lee
1276046d2e7cSSriram R if (sta->deflink.he_cap.has_he) {
1277046d2e7cSSriram R struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
12782af34fa3SRyder Lee
1279a56c431eSRyder Lee nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
12802af34fa3SRyder Lee pe->phy_cap_info[5]);
1281046d2e7cSSriram R } else if (sta->deflink.vht_cap.vht_supported) {
1282046d2e7cSSriram R struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
12832af34fa3SRyder Lee
1284a56c431eSRyder Lee nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
12852af34fa3SRyder Lee pc->cap);
12862af34fa3SRyder Lee }
12872af34fa3SRyder Lee
12882af34fa3SRyder Lee /* reply with identity matrix to avoid 2x2 BF negative gain */
1289a56c431eSRyder Lee bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
12902af34fa3SRyder Lee }
12912af34fa3SRyder Lee
12928f058354SRyder Lee static enum mcu_mmps_mode
mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)12938f058354SRyder Lee mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
12948f058354SRyder Lee {
12958f058354SRyder Lee switch (smps) {
12968f058354SRyder Lee case IEEE80211_SMPS_OFF:
12978f058354SRyder Lee return MCU_MMPS_DISABLE;
12988f058354SRyder Lee case IEEE80211_SMPS_STATIC:
12998f058354SRyder Lee return MCU_MMPS_STATIC;
13008f058354SRyder Lee case IEEE80211_SMPS_DYNAMIC:
13018f058354SRyder Lee return MCU_MMPS_DYNAMIC;
13028f058354SRyder Lee default:
13038f058354SRyder Lee return MCU_MMPS_DISABLE;
13048f058354SRyder Lee }
13058f058354SRyder Lee }
13068f058354SRyder Lee
mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,void * data,u32 field)130770fd1333SRyder Lee int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
130870fd1333SRyder Lee struct ieee80211_vif *vif,
130970fd1333SRyder Lee struct ieee80211_sta *sta,
131070fd1333SRyder Lee void *data, u32 field)
131170fd1333SRyder Lee {
131270fd1333SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
131370fd1333SRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
131470fd1333SRyder Lee struct sta_phy *phy = data;
131570fd1333SRyder Lee struct sta_rec_ra_fixed *ra;
131670fd1333SRyder Lee struct sk_buff *skb;
131770fd1333SRyder Lee struct tlv *tlv;
131870fd1333SRyder Lee
1319e2c93b68SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1320e2c93b68SLorenzo Bianconi &msta->wcid);
132170fd1333SRyder Lee if (IS_ERR(skb))
132270fd1333SRyder Lee return PTR_ERR(skb);
132370fd1333SRyder Lee
1324069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
132570fd1333SRyder Lee ra = (struct sta_rec_ra_fixed *)tlv;
132670fd1333SRyder Lee
132770fd1333SRyder Lee switch (field) {
132870fd1333SRyder Lee case RATE_PARAM_AUTO:
132970fd1333SRyder Lee break;
13309a93364dSRyder Lee case RATE_PARAM_FIXED:
133170fd1333SRyder Lee case RATE_PARAM_FIXED_MCS:
133270fd1333SRyder Lee case RATE_PARAM_FIXED_GI:
133370fd1333SRyder Lee case RATE_PARAM_FIXED_HE_LTF:
13348f058354SRyder Lee if (phy)
133570fd1333SRyder Lee ra->phy = *phy;
133670fd1333SRyder Lee break;
13378f058354SRyder Lee case RATE_PARAM_MMPS_UPDATE:
1338261ce887SBenjamin Berg ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
13398f058354SRyder Lee break;
13407a9a957bSShayne Chen case RATE_PARAM_SPE_UPDATE:
13417a9a957bSShayne Chen ra->spe_idx = *(u8 *)data;
13427a9a957bSShayne Chen break;
134370fd1333SRyder Lee default:
134470fd1333SRyder Lee break;
134570fd1333SRyder Lee }
134670fd1333SRyder Lee ra->field = cpu_to_le32(field);
134770fd1333SRyder Lee
134870fd1333SRyder Lee return mt76_mcu_skb_send_msg(&dev->mt76, skb,
134970fd1333SRyder Lee MCU_EXT_CMD(STA_REC_UPDATE), true);
135070fd1333SRyder Lee }
135170fd1333SRyder Lee
mt7915_mcu_add_smps(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)13528f058354SRyder Lee int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
13538f058354SRyder Lee struct ieee80211_sta *sta)
13548f058354SRyder Lee {
13558f058354SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
13568f058354SRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
13578f058354SRyder Lee struct wtbl_req_hdr *wtbl_hdr;
13588f058354SRyder Lee struct tlv *sta_wtbl;
13598f058354SRyder Lee struct sk_buff *skb;
13608f058354SRyder Lee int ret;
13618f058354SRyder Lee
1362e2c93b68SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1363e2c93b68SLorenzo Bianconi &msta->wcid);
13648f058354SRyder Lee if (IS_ERR(skb))
13658f058354SRyder Lee return PTR_ERR(skb);
13668f058354SRyder Lee
1367069c8e34SLorenzo Bianconi sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
1368069c8e34SLorenzo Bianconi sizeof(struct tlv));
1369a0792e15SLorenzo Bianconi wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
1370a0792e15SLorenzo Bianconi WTBL_SET, sta_wtbl, &skb);
13718f058354SRyder Lee if (IS_ERR(wtbl_hdr))
13728f058354SRyder Lee return PTR_ERR(wtbl_hdr);
13738f058354SRyder Lee
13742557e568SLorenzo Bianconi mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr);
13758f058354SRyder Lee
13768f058354SRyder Lee ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
13778f058354SRyder Lee MCU_EXT_CMD(STA_REC_UPDATE), true);
13788f058354SRyder Lee if (ret)
13798f058354SRyder Lee return ret;
13808f058354SRyder Lee
13818f058354SRyder Lee return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL,
13828f058354SRyder Lee RATE_PARAM_MMPS_UPDATE);
13838f058354SRyder Lee }
13848f058354SRyder Lee
138570fd1333SRyder Lee static int
mt7915_mcu_set_spe_idx(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)13867a9a957bSShayne Chen mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif,
13877a9a957bSShayne Chen struct ieee80211_sta *sta)
13887a9a957bSShayne Chen {
13897a9a957bSShayne Chen struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
13907a9a957bSShayne Chen struct mt76_phy *mphy = mvif->phy->mt76;
13917a9a957bSShayne Chen u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
13927a9a957bSShayne Chen
13937a9a957bSShayne Chen return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
13947a9a957bSShayne Chen RATE_PARAM_SPE_UPDATE);
13957a9a957bSShayne Chen }
13967a9a957bSShayne Chen
13977a9a957bSShayne Chen static int
mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)139870fd1333SRyder Lee mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
139970fd1333SRyder Lee struct ieee80211_vif *vif,
140070fd1333SRyder Lee struct ieee80211_sta *sta)
140170fd1333SRyder Lee {
140270fd1333SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
140370fd1333SRyder Lee struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
140470fd1333SRyder Lee struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
140570fd1333SRyder Lee enum nl80211_band band = chandef->chan->band;
140670fd1333SRyder Lee struct sta_phy phy = {};
140770fd1333SRyder Lee int ret, nrates = 0;
140870fd1333SRyder Lee
1409c6d3e16aSHoward Hsu #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \
141070fd1333SRyder Lee do { \
141170fd1333SRyder Lee u8 i, gi = mask->control[band]._gi; \
141270fd1333SRyder Lee gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \
1413046d2e7cSSriram R for (i = 0; i <= sta->deflink.bandwidth; i++) { \
141470fd1333SRyder Lee phy.sgi |= gi << (i << (_he)); \
141570fd1333SRyder Lee phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\
141670fd1333SRyder Lee } \
1417c41d2a07SMeiChia Chiu for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \
1418c41d2a07SMeiChia Chiu if (!mask->control[band]._mcs[i]) \
1419c41d2a07SMeiChia Chiu continue; \
142070fd1333SRyder Lee nrates += hweight16(mask->control[band]._mcs[i]); \
1421c41d2a07SMeiChia Chiu phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \
1422c6d3e16aSHoward Hsu if (_ht) \
1423c6d3e16aSHoward Hsu phy.mcs += 8 * i; \
1424c41d2a07SMeiChia Chiu } \
142570fd1333SRyder Lee } while (0)
142670fd1333SRyder Lee
1427046d2e7cSSriram R if (sta->deflink.he_cap.has_he) {
1428c6d3e16aSHoward Hsu __sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
1429046d2e7cSSriram R } else if (sta->deflink.vht_cap.vht_supported) {
1430c6d3e16aSHoward Hsu __sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
1431046d2e7cSSriram R } else if (sta->deflink.ht_cap.ht_supported) {
1432c6d3e16aSHoward Hsu __sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
143370fd1333SRyder Lee } else {
143470fd1333SRyder Lee nrates = hweight32(mask->control[band].legacy);
143570fd1333SRyder Lee phy.mcs = ffs(mask->control[band].legacy) - 1;
143670fd1333SRyder Lee }
143770fd1333SRyder Lee #undef __sta_phy_bitrate_mask_check
143870fd1333SRyder Lee
143970fd1333SRyder Lee /* fall back to auto rate control */
144070fd1333SRyder Lee if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
144170fd1333SRyder Lee mask->control[band].he_gi == GENMASK(7, 0) &&
144270fd1333SRyder Lee mask->control[band].he_ltf == GENMASK(7, 0) &&
144370fd1333SRyder Lee nrates != 1)
144470fd1333SRyder Lee return 0;
144570fd1333SRyder Lee
144670fd1333SRyder Lee /* fixed single rate */
144770fd1333SRyder Lee if (nrates == 1) {
144870fd1333SRyder Lee ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
144970fd1333SRyder Lee RATE_PARAM_FIXED_MCS);
145070fd1333SRyder Lee if (ret)
145170fd1333SRyder Lee return ret;
145270fd1333SRyder Lee }
145370fd1333SRyder Lee
145470fd1333SRyder Lee /* fixed GI */
145570fd1333SRyder Lee if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
145670fd1333SRyder Lee mask->control[band].he_gi != GENMASK(7, 0)) {
145770fd1333SRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
145870fd1333SRyder Lee u32 addr;
145970fd1333SRyder Lee
146070fd1333SRyder Lee /* firmware updates only TXCMD but doesn't take WTBL into
146170fd1333SRyder Lee * account, so driver should update here to reflect the
146270fd1333SRyder Lee * actual txrate hardware sends out.
146370fd1333SRyder Lee */
146470fd1333SRyder Lee addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
1465046d2e7cSSriram R if (sta->deflink.he_cap.has_he)
146670fd1333SRyder Lee mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
146770fd1333SRyder Lee else
146870fd1333SRyder Lee mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
146970fd1333SRyder Lee
147070fd1333SRyder Lee ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
147170fd1333SRyder Lee RATE_PARAM_FIXED_GI);
147270fd1333SRyder Lee if (ret)
147370fd1333SRyder Lee return ret;
147470fd1333SRyder Lee }
147570fd1333SRyder Lee
147670fd1333SRyder Lee /* fixed HE_LTF */
147770fd1333SRyder Lee if (mask->control[band].he_ltf != GENMASK(7, 0)) {
147870fd1333SRyder Lee ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
147970fd1333SRyder Lee RATE_PARAM_FIXED_HE_LTF);
148070fd1333SRyder Lee if (ret)
148170fd1333SRyder Lee return ret;
148270fd1333SRyder Lee }
148370fd1333SRyder Lee
14847a9a957bSShayne Chen return mt7915_mcu_set_spe_idx(dev, vif, sta);
148570fd1333SRyder Lee }
148670fd1333SRyder Lee
148789029a85SRyder Lee static void
mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff * skb,struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1488e57b7901SRyder Lee mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
148916234741SRyder Lee struct ieee80211_vif *vif, struct ieee80211_sta *sta)
1490e57b7901SRyder Lee {
1491a441a77aSRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1492e6d557a7SLorenzo Bianconi struct mt76_phy *mphy = mvif->phy->mt76;
1493e6d557a7SLorenzo Bianconi struct cfg80211_chan_def *chandef = &mphy->chandef;
149476be6c07SRyder Lee struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
1495a441a77aSRyder Lee enum nl80211_band band = chandef->chan->band;
1496e57b7901SRyder Lee struct sta_rec_ra *ra;
1497e57b7901SRyder Lee struct tlv *tlv;
1498046d2e7cSSriram R u32 supp_rate = sta->deflink.supp_rates[band];
1499a441a77aSRyder Lee u32 cap = sta->wme ? STA_CAP_WMM : 0;
1500e57b7901SRyder Lee
1501069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
1502e57b7901SRyder Lee ra = (struct sta_rec_ra *)tlv;
150316234741SRyder Lee
1504e57b7901SRyder Lee ra->valid = true;
1505e57b7901SRyder Lee ra->auto_rate = true;
1506e6d557a7SLorenzo Bianconi ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
1507a441a77aSRyder Lee ra->channel = chandef->chan->hw_value;
1508046d2e7cSSriram R ra->bw = sta->deflink.bandwidth;
1509046d2e7cSSriram R ra->phy.bw = sta->deflink.bandwidth;
1510261ce887SBenjamin Berg ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
1511e57b7901SRyder Lee
1512a441a77aSRyder Lee if (supp_rate) {
151376be6c07SRyder Lee supp_rate &= mask->control[band].legacy;
1514a441a77aSRyder Lee ra->rate_len = hweight32(supp_rate);
1515a441a77aSRyder Lee
1516e57b7901SRyder Lee if (band == NL80211_BAND_2GHZ) {
1517e57b7901SRyder Lee ra->supp_mode = MODE_CCK;
1518e57b7901SRyder Lee ra->supp_cck_rate = supp_rate & GENMASK(3, 0);
1519e57b7901SRyder Lee
1520a441a77aSRyder Lee if (ra->rate_len > 4) {
1521e57b7901SRyder Lee ra->supp_mode |= MODE_OFDM;
1522e57b7901SRyder Lee ra->supp_ofdm_rate = supp_rate >> 4;
1523e57b7901SRyder Lee }
1524e57b7901SRyder Lee } else {
1525e57b7901SRyder Lee ra->supp_mode = MODE_OFDM;
1526e57b7901SRyder Lee ra->supp_ofdm_rate = supp_rate;
1527e57b7901SRyder Lee }
1528e57b7901SRyder Lee }
1529e57b7901SRyder Lee
1530046d2e7cSSriram R if (sta->deflink.ht_cap.ht_supported) {
1531e57b7901SRyder Lee ra->supp_mode |= MODE_HT;
1532046d2e7cSSriram R ra->af = sta->deflink.ht_cap.ampdu_factor;
1533046d2e7cSSriram R ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
1534e57b7901SRyder Lee
1535e57b7901SRyder Lee cap |= STA_CAP_HT;
1536046d2e7cSSriram R if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
1537e57b7901SRyder Lee cap |= STA_CAP_SGI_20;
1538046d2e7cSSriram R if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
1539e57b7901SRyder Lee cap |= STA_CAP_SGI_40;
1540046d2e7cSSriram R if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
1541e57b7901SRyder Lee cap |= STA_CAP_TX_STBC;
1542046d2e7cSSriram R if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
1543e57b7901SRyder Lee cap |= STA_CAP_RX_STBC;
154402a89404SFelix Fietkau if (mvif->cap.ht_ldpc &&
1545046d2e7cSSriram R (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
1546e57b7901SRyder Lee cap |= STA_CAP_LDPC;
154776be6c07SRyder Lee
154870fd1333SRyder Lee mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
154970fd1333SRyder Lee mask->control[band].ht_mcs);
155076be6c07SRyder Lee ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
1551e57b7901SRyder Lee }
1552e57b7901SRyder Lee
1553046d2e7cSSriram R if (sta->deflink.vht_cap.vht_supported) {
1554a441a77aSRyder Lee u8 af;
1555e57b7901SRyder Lee
155676be6c07SRyder Lee ra->supp_mode |= MODE_VHT;
1557e57b7901SRyder Lee af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
1558046d2e7cSSriram R sta->deflink.vht_cap.cap);
1559e57b7901SRyder Lee ra->af = max_t(u8, ra->af, af);
1560e57b7901SRyder Lee
1561e57b7901SRyder Lee cap |= STA_CAP_VHT;
1562046d2e7cSSriram R if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
1563e57b7901SRyder Lee cap |= STA_CAP_VHT_SGI_80;
1564046d2e7cSSriram R if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
1565e57b7901SRyder Lee cap |= STA_CAP_VHT_SGI_160;
1566046d2e7cSSriram R if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
1567e57b7901SRyder Lee cap |= STA_CAP_VHT_TX_STBC;
1568046d2e7cSSriram R if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
1569e57b7901SRyder Lee cap |= STA_CAP_VHT_RX_STBC;
157002a89404SFelix Fietkau if (mvif->cap.vht_ldpc &&
1571046d2e7cSSriram R (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
1572e57b7901SRyder Lee cap |= STA_CAP_VHT_LDPC;
1573e57b7901SRyder Lee
157470fd1333SRyder Lee mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
157570fd1333SRyder Lee mask->control[band].vht_mcs);
1576e57b7901SRyder Lee }
1577e57b7901SRyder Lee
1578046d2e7cSSriram R if (sta->deflink.he_cap.has_he) {
1579c336318fSRyder Lee ra->supp_mode |= MODE_HE;
1580c336318fSRyder Lee cap |= STA_CAP_HE;
1581b4d093e3SMeiChia Chiu
1582046d2e7cSSriram R if (sta->deflink.he_6ghz_capa.capa)
1583046d2e7cSSriram R ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
1584b4d093e3SMeiChia Chiu IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
1585c336318fSRyder Lee }
1586c336318fSRyder Lee
1587a441a77aSRyder Lee ra->sta_cap = cpu_to_le32(cap);
1588e57b7901SRyder Lee }
1589e57b7901SRyder Lee
mt7915_mcu_add_rate_ctrl(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool changed)1590e57b7901SRyder Lee int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
15912eec60dcSRyder Lee struct ieee80211_sta *sta, bool changed)
1592e57b7901SRyder Lee {
1593e57b7901SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1594e57b7901SRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
1595e57b7901SRyder Lee struct sk_buff *skb;
159670fd1333SRyder Lee int ret;
1597e57b7901SRyder Lee
1598e2c93b68SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1599e2c93b68SLorenzo Bianconi &msta->wcid);
1600e57b7901SRyder Lee if (IS_ERR(skb))
1601e57b7901SRyder Lee return PTR_ERR(skb);
1602e57b7901SRyder Lee
16032eec60dcSRyder Lee /* firmware rc algorithm refers to sta_rec_he for HE control.
16042eec60dcSRyder Lee * once dev->rc_work changes the settings driver should also
16052eec60dcSRyder Lee * update sta_rec_he here.
16062eec60dcSRyder Lee */
1607b4d093e3SMeiChia Chiu if (changed)
16082eec60dcSRyder Lee mt7915_mcu_sta_he_tlv(skb, sta, vif);
16092eec60dcSRyder Lee
161070fd1333SRyder Lee /* sta_rec_ra accommodates BW, NSS and only MCS range format
161170fd1333SRyder Lee * i.e 0-{7,8,9} for VHT.
161270fd1333SRyder Lee */
1613e57b7901SRyder Lee mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
1614e57b7901SRyder Lee
161570fd1333SRyder Lee ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
1616c203dd62SFelix Fietkau MCU_EXT_CMD(STA_REC_UPDATE), true);
161770fd1333SRyder Lee if (ret)
161870fd1333SRyder Lee return ret;
161970fd1333SRyder Lee
162070fd1333SRyder Lee /* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE,
162170fd1333SRyder Lee * and updates as peer fixed rate parameters, which overrides
162270fd1333SRyder Lee * sta_rec_ra and firmware rate control algorithm.
162370fd1333SRyder Lee */
162470fd1333SRyder Lee return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
1625f68e6a1fSRyder Lee }
1626f68e6a1fSRyder Lee
1627798bffd8SRyder Lee static int
mt7915_mcu_add_group(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1628798bffd8SRyder Lee mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1629798bffd8SRyder Lee struct ieee80211_sta *sta)
1630798bffd8SRyder Lee {
1631798bffd8SRyder Lee #define MT_STA_BSS_GROUP 1
1632798bffd8SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
163389bbd373SShayne Chen struct mt7915_sta *msta;
1634798bffd8SRyder Lee struct {
1635798bffd8SRyder Lee __le32 action;
1636798bffd8SRyder Lee u8 wlan_idx_lo;
1637798bffd8SRyder Lee u8 status;
1638798bffd8SRyder Lee u8 wlan_idx_hi;
1639798bffd8SRyder Lee u8 rsv0[5];
1640798bffd8SRyder Lee __le32 val;
1641798bffd8SRyder Lee u8 rsv1[8];
1642798bffd8SRyder Lee } __packed req = {
1643798bffd8SRyder Lee .action = cpu_to_le32(MT_STA_BSS_GROUP),
16446cf4392fSLorenzo Bianconi .val = cpu_to_le32(mvif->mt76.idx % 16),
1645798bffd8SRyder Lee };
1646798bffd8SRyder Lee
164789bbd373SShayne Chen msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
164889bbd373SShayne Chen req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx);
164989bbd373SShayne Chen req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx);
165089bbd373SShayne Chen
1651798bffd8SRyder Lee return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req,
1652798bffd8SRyder Lee sizeof(req), true);
1653798bffd8SRyder Lee }
1654798bffd8SRyder Lee
mt7915_mcu_add_sta(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)1655e57b7901SRyder Lee int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1656e57b7901SRyder Lee struct ieee80211_sta *sta, bool enable)
1657e57b7901SRyder Lee {
1658e57b7901SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1659e57b7901SRyder Lee struct mt7915_sta *msta;
1660e57b7901SRyder Lee struct sk_buff *skb;
166189bbd373SShayne Chen int ret;
1662e57b7901SRyder Lee
1663e57b7901SRyder Lee msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
1664e57b7901SRyder Lee
1665e2c93b68SLorenzo Bianconi skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1666e2c93b68SLorenzo Bianconi &msta->wcid);
1667e57b7901SRyder Lee if (IS_ERR(skb))
1668e57b7901SRyder Lee return PTR_ERR(skb);
1669e57b7901SRyder Lee
167089bbd373SShayne Chen /* starec basic */
16711b83d17cSSean Wang mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable,
16728e3e7567SShayne Chen !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
167389bbd373SShayne Chen if (!enable)
167489bbd373SShayne Chen goto out;
1675e57b7901SRyder Lee
167689bbd373SShayne Chen /* tag order is in accordance with firmware dependency. */
1677b4d093e3SMeiChia Chiu if (sta) {
167889bbd373SShayne Chen /* starec bfer */
167989bbd373SShayne Chen mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta);
168089bbd373SShayne Chen /* starec ht */
168189bbd373SShayne Chen mt7915_mcu_sta_ht_tlv(skb, sta);
168289bbd373SShayne Chen /* starec vht */
168389bbd373SShayne Chen mt7915_mcu_sta_vht_tlv(skb, sta);
168489bbd373SShayne Chen /* starec uapsd */
1685836c0c98SLorenzo Bianconi mt76_connac_mcu_sta_uapsd(skb, vif, sta);
1686e57b7901SRyder Lee }
1687e57b7901SRyder Lee
168889bbd373SShayne Chen ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta);
1689a43736cdSLorenzo Bianconi if (ret) {
1690a43736cdSLorenzo Bianconi dev_kfree_skb(skb);
169189bbd373SShayne Chen return ret;
1692a43736cdSLorenzo Bianconi }
169389bbd373SShayne Chen
1694b4d093e3SMeiChia Chiu if (sta) {
169589bbd373SShayne Chen /* starec amsdu */
1696be1954ffSPeter Chiu mt7915_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
169789bbd373SShayne Chen /* starec he */
169889bbd373SShayne Chen mt7915_mcu_sta_he_tlv(skb, sta, vif);
169989bbd373SShayne Chen /* starec muru */
1700c3f2ed58SFelix Fietkau mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif);
170189bbd373SShayne Chen /* starec bfee */
170289bbd373SShayne Chen mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta);
170389bbd373SShayne Chen }
170489bbd373SShayne Chen
170589bbd373SShayne Chen ret = mt7915_mcu_add_group(dev, vif, sta);
1706a43736cdSLorenzo Bianconi if (ret) {
1707a43736cdSLorenzo Bianconi dev_kfree_skb(skb);
170889bbd373SShayne Chen return ret;
1709a43736cdSLorenzo Bianconi }
171089bbd373SShayne Chen out:
17114f831d18SLorenzo Bianconi ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
17124f831d18SLorenzo Bianconi if (ret)
17134f831d18SLorenzo Bianconi return ret;
17144f831d18SLorenzo Bianconi
1715fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&dev->mt76, skb,
1716c203dd62SFelix Fietkau MCU_EXT_CMD(STA_REC_UPDATE), true);
1717e57b7901SRyder Lee }
1718e57b7901SRyder Lee
mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev * dev)1719c6cde7b7SSujuan Chen int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev)
1720c6cde7b7SSujuan Chen {
1721c6cde7b7SSujuan Chen #ifdef CONFIG_NET_MEDIATEK_SOC_WED
1722c6cde7b7SSujuan Chen struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
1723c6cde7b7SSujuan Chen struct {
1724c6cde7b7SSujuan Chen __le32 args[2];
1725c6cde7b7SSujuan Chen } req = {
1726c6cde7b7SSujuan Chen .args[0] = cpu_to_le32(1),
1727c6cde7b7SSujuan Chen .args[1] = cpu_to_le32(6),
1728c6cde7b7SSujuan Chen };
1729c6cde7b7SSujuan Chen
1730c6cde7b7SSujuan Chen return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL,
1731c6cde7b7SSujuan Chen &req, sizeof(req));
1732c6cde7b7SSujuan Chen #else
1733c6cde7b7SSujuan Chen return 0;
1734c6cde7b7SSujuan Chen #endif
1735c6cde7b7SSujuan Chen }
1736c6cde7b7SSujuan Chen
mt7915_mcu_add_dev_info(struct mt7915_phy * phy,struct ieee80211_vif * vif,bool enable)17378aa2c6f4SFelix Fietkau int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
1738e57b7901SRyder Lee struct ieee80211_vif *vif, bool enable)
1739e57b7901SRyder Lee {
17408aa2c6f4SFelix Fietkau struct mt7915_dev *dev = phy->dev;
1741e57b7901SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1742e57b7901SRyder Lee struct {
1743e57b7901SRyder Lee struct req_hdr {
1744e57b7901SRyder Lee u8 omac_idx;
17456f917bbaSRyder Lee u8 band_idx;
1746e57b7901SRyder Lee __le16 tlv_num;
1747e57b7901SRyder Lee u8 is_tlv_append;
1748e57b7901SRyder Lee u8 rsv[3];
1749e57b7901SRyder Lee } __packed hdr;
1750e57b7901SRyder Lee struct req_tlv {
1751e57b7901SRyder Lee __le16 tag;
1752e57b7901SRyder Lee __le16 len;
1753e57b7901SRyder Lee u8 active;
17546f917bbaSRyder Lee u8 band_idx;
1755e57b7901SRyder Lee u8 omac_addr[ETH_ALEN];
1756e57b7901SRyder Lee } __packed tlv;
1757e57b7901SRyder Lee } data = {
1758e57b7901SRyder Lee .hdr = {
17596cf4392fSLorenzo Bianconi .omac_idx = mvif->mt76.omac_idx,
17606f917bbaSRyder Lee .band_idx = mvif->mt76.band_idx,
1761e57b7901SRyder Lee .tlv_num = cpu_to_le16(1),
1762e57b7901SRyder Lee .is_tlv_append = 1,
1763e57b7901SRyder Lee },
1764e57b7901SRyder Lee .tlv = {
1765e57b7901SRyder Lee .tag = cpu_to_le16(DEV_INFO_ACTIVE),
1766e57b7901SRyder Lee .len = cpu_to_le16(sizeof(struct req_tlv)),
1767e57b7901SRyder Lee .active = enable,
17686f917bbaSRyder Lee .band_idx = mvif->mt76.band_idx,
1769e57b7901SRyder Lee },
1770e57b7901SRyder Lee };
1771e57b7901SRyder Lee
17726cf4392fSLorenzo Bianconi if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
17738aa2c6f4SFelix Fietkau return mt7915_mcu_muar_config(phy, vif, false, enable);
17748aa2c6f4SFelix Fietkau
1775e57b7901SRyder Lee memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
1776c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
1777e57b7901SRyder Lee &data, sizeof(data), true);
1778e57b7901SRyder Lee }
1779e57b7901SRyder Lee
1780e57b7901SRyder Lee static void
mt7915_mcu_beacon_cntdwn(struct ieee80211_vif * vif,struct sk_buff * rskb,struct sk_buff * skb,struct bss_info_bcn * bcn,struct ieee80211_mutable_offsets * offs)1781b4b9f0a3SLorenzo Bianconi mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
1782b4b9f0a3SLorenzo Bianconi struct sk_buff *skb, struct bss_info_bcn *bcn,
1783e57b7901SRyder Lee struct ieee80211_mutable_offsets *offs)
1784e57b7901SRyder Lee {
1785b4b9f0a3SLorenzo Bianconi struct bss_info_bcn_cntdwn *info;
1786e57b7901SRyder Lee struct tlv *tlv;
1787b4b9f0a3SLorenzo Bianconi int sub_tag;
1788e57b7901SRyder Lee
1789b4b9f0a3SLorenzo Bianconi if (!offs->cntdwn_counter_offs[0])
1790b4b9f0a3SLorenzo Bianconi return;
1791b4b9f0a3SLorenzo Bianconi
1792d0a9123eSJohannes Berg sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC;
1793b4b9f0a3SLorenzo Bianconi tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info),
1794b4b9f0a3SLorenzo Bianconi &bcn->sub_ntlv, &bcn->len);
1795b4b9f0a3SLorenzo Bianconi info = (struct bss_info_bcn_cntdwn *)tlv;
1796b4b9f0a3SLorenzo Bianconi info->cnt = skb->data[offs->cntdwn_counter_offs[0]];
1797e57b7901SRyder Lee }
1798e57b7901SRyder Lee
1799e57b7901SRyder Lee static void
mt7915_mcu_beacon_mbss(struct sk_buff * rskb,struct sk_buff * skb,struct ieee80211_vif * vif,struct bss_info_bcn * bcn,struct ieee80211_mutable_offsets * offs)18006b7f9affSLorenzo Bianconi mt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
18016b7f9affSLorenzo Bianconi struct ieee80211_vif *vif, struct bss_info_bcn *bcn,
18026b7f9affSLorenzo Bianconi struct ieee80211_mutable_offsets *offs)
18036b7f9affSLorenzo Bianconi {
18046b7f9affSLorenzo Bianconi struct bss_info_bcn_mbss *mbss;
18056b7f9affSLorenzo Bianconi const struct element *elem;
18066b7f9affSLorenzo Bianconi struct tlv *tlv;
18076b7f9affSLorenzo Bianconi
18086b7f9affSLorenzo Bianconi if (!vif->bss_conf.bssid_indicator)
18096b7f9affSLorenzo Bianconi return;
18106b7f9affSLorenzo Bianconi
18116b7f9affSLorenzo Bianconi tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID,
18126b7f9affSLorenzo Bianconi sizeof(*mbss), &bcn->sub_ntlv,
18136b7f9affSLorenzo Bianconi &bcn->len);
18146b7f9affSLorenzo Bianconi
18156b7f9affSLorenzo Bianconi mbss = (struct bss_info_bcn_mbss *)tlv;
18166b7f9affSLorenzo Bianconi mbss->offset[0] = cpu_to_le16(offs->tim_offset);
18176b7f9affSLorenzo Bianconi mbss->bitmap = cpu_to_le32(1);
18186b7f9affSLorenzo Bianconi
18196b7f9affSLorenzo Bianconi for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID,
18206b7f9affSLorenzo Bianconi &skb->data[offs->mbssid_off],
18216b7f9affSLorenzo Bianconi skb->len - offs->mbssid_off) {
18226b7f9affSLorenzo Bianconi const struct element *sub_elem;
18236b7f9affSLorenzo Bianconi
18246b7f9affSLorenzo Bianconi if (elem->datalen < 2)
18256b7f9affSLorenzo Bianconi continue;
18266b7f9affSLorenzo Bianconi
18276b7f9affSLorenzo Bianconi for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) {
1828aa796f12SLorenzo Bianconi const struct ieee80211_bssid_index *idx;
1829aa796f12SLorenzo Bianconi const u8 *idx_ie;
18306b7f9affSLorenzo Bianconi
18316b7f9affSLorenzo Bianconi if (sub_elem->id || sub_elem->datalen < 4)
18326b7f9affSLorenzo Bianconi continue; /* not a valid BSS profile */
18336b7f9affSLorenzo Bianconi
18346b7f9affSLorenzo Bianconi /* Find WLAN_EID_MULTI_BSSID_IDX
18356b7f9affSLorenzo Bianconi * in the merged nontransmitted profile
18366b7f9affSLorenzo Bianconi */
1837aa796f12SLorenzo Bianconi idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
18386b7f9affSLorenzo Bianconi sub_elem->data,
18396b7f9affSLorenzo Bianconi sub_elem->datalen);
1840aa796f12SLorenzo Bianconi if (!idx_ie || idx_ie[1] < sizeof(*idx))
18416b7f9affSLorenzo Bianconi continue;
18426b7f9affSLorenzo Bianconi
1843aa796f12SLorenzo Bianconi idx = (void *)(idx_ie + 2);
1844aa796f12SLorenzo Bianconi if (!idx->bssid_index || idx->bssid_index > 31)
1845aa796f12SLorenzo Bianconi continue;
1846aa796f12SLorenzo Bianconi
1847aa796f12SLorenzo Bianconi mbss->offset[idx->bssid_index] =
1848aa796f12SLorenzo Bianconi cpu_to_le16(idx_ie - skb->data);
1849aa796f12SLorenzo Bianconi mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index));
18506b7f9affSLorenzo Bianconi }
18516b7f9affSLorenzo Bianconi }
18526b7f9affSLorenzo Bianconi }
18536b7f9affSLorenzo Bianconi
18546b7f9affSLorenzo Bianconi static void
mt7915_mcu_beacon_cont(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct sk_buff * rskb,struct sk_buff * skb,struct bss_info_bcn * bcn,struct ieee80211_mutable_offsets * offs)1855b4b9f0a3SLorenzo Bianconi mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1856b4b9f0a3SLorenzo Bianconi struct sk_buff *rskb, struct sk_buff *skb,
1857b4b9f0a3SLorenzo Bianconi struct bss_info_bcn *bcn,
1858e57b7901SRyder Lee struct ieee80211_mutable_offsets *offs)
1859e57b7901SRyder Lee {
1860e57b7901SRyder Lee struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1861e57b7901SRyder Lee struct bss_info_bcn_cont *cont;
1862e57b7901SRyder Lee struct tlv *tlv;
1863e57b7901SRyder Lee u8 *buf;
1864e57b7901SRyder Lee int len = sizeof(*cont) + MT_TXD_SIZE + skb->len;
1865e57b7901SRyder Lee
1866869f0646SMeiChia Chiu len = (len & 0x3) ? ((len | 0x3) + 1) : len;
1867e57b7901SRyder Lee tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT,
1868e57b7901SRyder Lee len, &bcn->sub_ntlv, &bcn->len);
1869e57b7901SRyder Lee
1870e57b7901SRyder Lee cont = (struct bss_info_bcn_cont *)tlv;
1871e57b7901SRyder Lee cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1872e57b7901SRyder Lee cont->tim_ofs = cpu_to_le16(offs->tim_offset);
1873e57b7901SRyder Lee
1874b4b9f0a3SLorenzo Bianconi if (offs->cntdwn_counter_offs[0]) {
1875b4b9f0a3SLorenzo Bianconi u16 offset = offs->cntdwn_counter_offs[0];
1876b4b9f0a3SLorenzo Bianconi
1877d0a9123eSJohannes Berg if (vif->bss_conf.csa_active)
1878b4b9f0a3SLorenzo Bianconi cont->csa_ofs = cpu_to_le16(offset - 4);
1879d0a9123eSJohannes Berg if (vif->bss_conf.color_change_active)
1880b4b9f0a3SLorenzo Bianconi cont->bcc_ofs = cpu_to_le16(offset - 3);
1881b4b9f0a3SLorenzo Bianconi }
1882e57b7901SRyder Lee
1883e57b7901SRyder Lee buf = (u8 *)tlv + sizeof(*cont);
1884d502e300SLorenzo Bianconi mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
18851d5af0acSFelix Fietkau 0, BSS_CHANGED_BEACON);
1886e57b7901SRyder Lee memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
1887e57b7901SRyder Lee }
1888e57b7901SRyder Lee
1889671985baSMeiChia Chiu int
mt7915_mcu_add_inband_discov(struct mt7915_dev * dev,struct ieee80211_vif * vif,u32 changed)1890671985baSMeiChia Chiu mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1891869f0646SMeiChia Chiu u32 changed)
1892869f0646SMeiChia Chiu {
1893869f0646SMeiChia Chiu #define OFFLOAD_TX_MODE_SU BIT(0)
1894869f0646SMeiChia Chiu #define OFFLOAD_TX_MODE_MU BIT(1)
1895869f0646SMeiChia Chiu struct ieee80211_hw *hw = mt76_hw(dev);
1896869f0646SMeiChia Chiu struct mt7915_phy *phy = mt7915_hw_phy(hw);
1897869f0646SMeiChia Chiu struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1898869f0646SMeiChia Chiu struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
1899869f0646SMeiChia Chiu enum nl80211_band band = chandef->chan->band;
1900869f0646SMeiChia Chiu struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1901671985baSMeiChia Chiu struct bss_info_bcn *bcn;
1902869f0646SMeiChia Chiu struct bss_info_inband_discovery *discov;
1903869f0646SMeiChia Chiu struct ieee80211_tx_info *info;
1904671985baSMeiChia Chiu struct sk_buff *rskb, *skb = NULL;
1905671985baSMeiChia Chiu struct tlv *tlv, *sub_tlv;
1906869f0646SMeiChia Chiu bool ext_phy = phy != &dev->phy;
1907869f0646SMeiChia Chiu u8 *buf, interval;
1908869f0646SMeiChia Chiu int len;
1909869f0646SMeiChia Chiu
1910671985baSMeiChia Chiu if (vif->bss_conf.nontransmitted)
1911671985baSMeiChia Chiu return 0;
1912671985baSMeiChia Chiu
1913671985baSMeiChia Chiu rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
1914671985baSMeiChia Chiu MT7915_MAX_BSS_OFFLOAD_SIZE);
1915671985baSMeiChia Chiu if (IS_ERR(rskb))
1916671985baSMeiChia Chiu return PTR_ERR(rskb);
1917671985baSMeiChia Chiu
1918671985baSMeiChia Chiu tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
1919671985baSMeiChia Chiu bcn = (struct bss_info_bcn *)tlv;
1920671985baSMeiChia Chiu bcn->enable = true;
1921671985baSMeiChia Chiu
1922869f0646SMeiChia Chiu if (changed & BSS_CHANGED_FILS_DISCOVERY &&
1923869f0646SMeiChia Chiu vif->bss_conf.fils_discovery.max_interval) {
1924869f0646SMeiChia Chiu interval = vif->bss_conf.fils_discovery.max_interval;
1925869f0646SMeiChia Chiu skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
1926869f0646SMeiChia Chiu } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
1927869f0646SMeiChia Chiu vif->bss_conf.unsol_bcast_probe_resp_interval) {
1928869f0646SMeiChia Chiu interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
1929869f0646SMeiChia Chiu skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
1930869f0646SMeiChia Chiu }
1931869f0646SMeiChia Chiu
19323d691558SBo Jiao if (!skb) {
19333d691558SBo Jiao dev_kfree_skb(rskb);
1934671985baSMeiChia Chiu return -EINVAL;
19353d691558SBo Jiao }
1936869f0646SMeiChia Chiu
1937869f0646SMeiChia Chiu info = IEEE80211_SKB_CB(skb);
1938869f0646SMeiChia Chiu info->control.vif = vif;
1939869f0646SMeiChia Chiu info->band = band;
1940a062f001SLorenzo Bianconi info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
1941869f0646SMeiChia Chiu
1942869f0646SMeiChia Chiu len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
1943869f0646SMeiChia Chiu len = (len & 0x3) ? ((len | 0x3) + 1) : len;
1944869f0646SMeiChia Chiu
1945671985baSMeiChia Chiu if (skb->len > MT7915_MAX_BEACON_SIZE) {
194618fced20SMeiChia Chiu dev_err(dev->mt76.dev, "inband discovery size limit exceed\n");
19473d691558SBo Jiao dev_kfree_skb(rskb);
194818fced20SMeiChia Chiu dev_kfree_skb(skb);
1949671985baSMeiChia Chiu return -EINVAL;
195018fced20SMeiChia Chiu }
195118fced20SMeiChia Chiu
1952671985baSMeiChia Chiu sub_tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
1953869f0646SMeiChia Chiu len, &bcn->sub_ntlv, &bcn->len);
1954671985baSMeiChia Chiu discov = (struct bss_info_inband_discovery *)sub_tlv;
1955869f0646SMeiChia Chiu discov->tx_mode = OFFLOAD_TX_MODE_SU;
1956869f0646SMeiChia Chiu /* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
1957869f0646SMeiChia Chiu discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
1958869f0646SMeiChia Chiu discov->tx_interval = interval;
1959869f0646SMeiChia Chiu discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1960869f0646SMeiChia Chiu discov->enable = true;
1961869f0646SMeiChia Chiu
1962671985baSMeiChia Chiu buf = (u8 *)sub_tlv + sizeof(*discov);
1963869f0646SMeiChia Chiu
1964d502e300SLorenzo Bianconi mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
19651d5af0acSFelix Fietkau 0, changed);
1966869f0646SMeiChia Chiu memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
1967869f0646SMeiChia Chiu
1968869f0646SMeiChia Chiu dev_kfree_skb(skb);
1969671985baSMeiChia Chiu
1970671985baSMeiChia Chiu return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
1971671985baSMeiChia Chiu MCU_EXT_CMD(BSS_INFO_UPDATE), true);
1972869f0646SMeiChia Chiu }
1973869f0646SMeiChia Chiu
mt7915_mcu_add_beacon(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int en,u32 changed)1974869f0646SMeiChia Chiu int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1975869f0646SMeiChia Chiu int en, u32 changed)
1976e57b7901SRyder Lee {
1977e57b7901SRyder Lee struct mt7915_dev *dev = mt7915_hw_dev(hw);
1978e57b7901SRyder Lee struct mt7915_phy *phy = mt7915_hw_phy(hw);
1979e57b7901SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1980e57b7901SRyder Lee struct ieee80211_mutable_offsets offs;
1981e57b7901SRyder Lee struct ieee80211_tx_info *info;
1982e57b7901SRyder Lee struct sk_buff *skb, *rskb;
1983e57b7901SRyder Lee struct tlv *tlv;
1984e57b7901SRyder Lee struct bss_info_bcn *bcn;
198518fced20SMeiChia Chiu int len = MT7915_MAX_BSS_OFFLOAD_SIZE;
1986006b9d4aSBo Jiao bool ext_phy = phy != &dev->phy;
1987e57b7901SRyder Lee
19886b7f9affSLorenzo Bianconi if (vif->bss_conf.nontransmitted)
19896b7f9affSLorenzo Bianconi return 0;
19906b7f9affSLorenzo Bianconi
1991e2c93b68SLorenzo Bianconi rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1992e2c93b68SLorenzo Bianconi NULL, len);
1993ac15f9b6SRyder Lee if (IS_ERR(rskb))
1994ac15f9b6SRyder Lee return PTR_ERR(rskb);
1995ac15f9b6SRyder Lee
1996069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
1997ac15f9b6SRyder Lee bcn = (struct bss_info_bcn *)tlv;
1998ac15f9b6SRyder Lee bcn->enable = en;
1999ac15f9b6SRyder Lee
2000ac15f9b6SRyder Lee if (!en)
2001ac15f9b6SRyder Lee goto out;
2002ac15f9b6SRyder Lee
20036e8912a5SShaul Triebitz skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
20043d691558SBo Jiao if (!skb) {
20053d691558SBo Jiao dev_kfree_skb(rskb);
2006e57b7901SRyder Lee return -EINVAL;
20073d691558SBo Jiao }
2008e57b7901SRyder Lee
2009671985baSMeiChia Chiu if (skb->len > MT7915_MAX_BEACON_SIZE) {
2010e57b7901SRyder Lee dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
20113d691558SBo Jiao dev_kfree_skb(rskb);
2012e57b7901SRyder Lee dev_kfree_skb(skb);
2013e57b7901SRyder Lee return -EINVAL;
2014e57b7901SRyder Lee }
2015e57b7901SRyder Lee
2016e57b7901SRyder Lee info = IEEE80211_SKB_CB(skb);
2017a062f001SLorenzo Bianconi info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
2018e57b7901SRyder Lee
2019b4b9f0a3SLorenzo Bianconi mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
20206b7f9affSLorenzo Bianconi mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
2021b4b9f0a3SLorenzo Bianconi mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
2022e57b7901SRyder Lee dev_kfree_skb(skb);
2023e57b7901SRyder Lee
2024ac15f9b6SRyder Lee out:
2025fa62d0e0SFelix Fietkau return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
2026c203dd62SFelix Fietkau MCU_EXT_CMD(BSS_INFO_UPDATE), true);
2027e57b7901SRyder Lee }
2028e57b7901SRyder Lee
mt7915_driver_own(struct mt7915_dev * dev,u8 band)20291c7393e6SBo Jiao static int mt7915_driver_own(struct mt7915_dev *dev, u8 band)
2030e57b7901SRyder Lee {
20311c7393e6SBo Jiao mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN);
20321c7393e6SBo Jiao if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band),
203371bb496cSFelix Fietkau MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) {
2034e57b7901SRyder Lee dev_err(dev->mt76.dev, "Timeout for driver own\n");
2035e57b7901SRyder Lee return -EIO;
2036e57b7901SRyder Lee }
2037e57b7901SRyder Lee
20381c7393e6SBo Jiao /* clear irq when the driver own success */
20391c7393e6SBo Jiao mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band),
20401c7393e6SBo Jiao MT_TOP_LPCR_HOST_BAND_STAT);
20411c7393e6SBo Jiao
2042e57b7901SRyder Lee return 0;
2043e57b7901SRyder Lee }
2044e57b7901SRyder Lee
2045e57b7901SRyder Lee static int
mt7915_firmware_state(struct mt7915_dev * dev,bool wa)20461c7393e6SBo Jiao mt7915_firmware_state(struct mt7915_dev *dev, bool wa)
20471c7393e6SBo Jiao {
20481c7393e6SBo Jiao u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE,
20491c7393e6SBo Jiao wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD);
20501c7393e6SBo Jiao
20511c7393e6SBo Jiao if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,
20521c7393e6SBo Jiao state, 1000)) {
20531c7393e6SBo Jiao dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
20541c7393e6SBo Jiao return -EIO;
20551c7393e6SBo Jiao }
20561c7393e6SBo Jiao return 0;
20571c7393e6SBo Jiao }
20581c7393e6SBo Jiao
mt7915_load_firmware(struct mt7915_dev * dev)2059e57b7901SRyder Lee static int mt7915_load_firmware(struct mt7915_dev *dev)
2060e57b7901SRyder Lee {
2061e57b7901SRyder Lee int ret;
2062e57b7901SRyder Lee
20631c7393e6SBo Jiao /* make sure fw is download state */
20641c7393e6SBo Jiao if (mt7915_firmware_state(dev, false)) {
20651c7393e6SBo Jiao /* restart firmware once */
2066f535ccdfSLorenzo Bianconi mt76_connac_mcu_restart(&dev->mt76);
20671c7393e6SBo Jiao ret = mt7915_firmware_state(dev, false);
20681c7393e6SBo Jiao if (ret) {
20691c7393e6SBo Jiao dev_err(dev->mt76.dev,
20701c7393e6SBo Jiao "Firmware is not ready for download\n");
20711c7393e6SBo Jiao return ret;
20721c7393e6SBo Jiao }
20731c7393e6SBo Jiao }
20741c7393e6SBo Jiao
207528fec923SLorenzo Bianconi ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH));
2076e57b7901SRyder Lee if (ret)
2077e57b7901SRyder Lee return ret;
2078e57b7901SRyder Lee
2079b9ec2710SLorenzo Bianconi ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM),
2080b9ec2710SLorenzo Bianconi fw_name(dev, FIRMWARE_WA));
2081e57b7901SRyder Lee if (ret)
2082e57b7901SRyder Lee return ret;
2083e57b7901SRyder Lee
20841c7393e6SBo Jiao ret = mt7915_firmware_state(dev, true);
20851c7393e6SBo Jiao if (ret)
20861c7393e6SBo Jiao return ret;
2087e57b7901SRyder Lee
2088e637763bSLorenzo Bianconi mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
2089e57b7901SRyder Lee
2090e57b7901SRyder Lee dev_dbg(dev->mt76.dev, "Firmware init done\n");
2091e57b7901SRyder Lee
2092e57b7901SRyder Lee return 0;
2093e57b7901SRyder Lee }
2094e57b7901SRyder Lee
mt7915_mcu_fw_log_2_host(struct mt7915_dev * dev,u8 type,u8 ctrl)20959b121acdSShayne Chen int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl)
20965517f78bSRyder Lee {
20975517f78bSRyder Lee struct {
20985517f78bSRyder Lee u8 ctrl_val;
20995517f78bSRyder Lee u8 pad[3];
21005517f78bSRyder Lee } data = {
21015517f78bSRyder Lee .ctrl_val = ctrl
21025517f78bSRyder Lee };
21035517f78bSRyder Lee
21049b121acdSShayne Chen if (type == MCU_FW_LOG_WA)
21059b121acdSShayne Chen return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(FW_LOG_2_HOST),
21069b121acdSShayne Chen &data, sizeof(data), true);
21079b121acdSShayne Chen
2108c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data,
2109cb5cdd4cSFelix Fietkau sizeof(data), true);
21105517f78bSRyder Lee }
21115517f78bSRyder Lee
mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev * dev,u32 module,u8 level)21125517f78bSRyder Lee int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
21135517f78bSRyder Lee {
21145517f78bSRyder Lee struct {
21155517f78bSRyder Lee u8 ver;
21165517f78bSRyder Lee u8 pad;
2117cee236e1SFelix Fietkau __le16 len;
21185517f78bSRyder Lee u8 level;
21195517f78bSRyder Lee u8 rsv[3];
212019e29c69SRyder Lee __le32 module_idx;
21215517f78bSRyder Lee } data = {
21225517f78bSRyder Lee .module_idx = cpu_to_le32(module),
21235517f78bSRyder Lee .level = level,
21245517f78bSRyder Lee };
21255517f78bSRyder Lee
2126c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data,
2127cb5cdd4cSFelix Fietkau sizeof(data), false);
21285517f78bSRyder Lee }
21295517f78bSRyder Lee
mt7915_mcu_muru_debug_set(struct mt7915_dev * dev,bool enabled)21301966a507SMeiChia Chiu int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled)
21311966a507SMeiChia Chiu {
21321966a507SMeiChia Chiu struct {
21331966a507SMeiChia Chiu __le32 cmd;
21341966a507SMeiChia Chiu u8 enable;
21351966a507SMeiChia Chiu } data = {
21361966a507SMeiChia Chiu .cmd = cpu_to_le32(MURU_SET_TXC_TX_STATS_EN),
21371966a507SMeiChia Chiu .enable = enabled,
21381966a507SMeiChia Chiu };
21391966a507SMeiChia Chiu
21401966a507SMeiChia Chiu return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &data,
21411966a507SMeiChia Chiu sizeof(data), false);
21421966a507SMeiChia Chiu }
21431966a507SMeiChia Chiu
mt7915_mcu_muru_debug_get(struct mt7915_phy * phy)21441258c156SRyder Lee int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy)
21451966a507SMeiChia Chiu {
21461966a507SMeiChia Chiu struct mt7915_dev *dev = phy->dev;
21471966a507SMeiChia Chiu struct sk_buff *skb;
21481258c156SRyder Lee struct mt7915_mcu_muru_stats *mu_stats;
21491966a507SMeiChia Chiu int ret;
21501966a507SMeiChia Chiu
21511966a507SMeiChia Chiu struct {
21521966a507SMeiChia Chiu __le32 cmd;
21531966a507SMeiChia Chiu u8 band_idx;
21541966a507SMeiChia Chiu } req = {
21551966a507SMeiChia Chiu .cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS),
21563eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
21571966a507SMeiChia Chiu };
21581966a507SMeiChia Chiu
21591966a507SMeiChia Chiu ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL),
21601966a507SMeiChia Chiu &req, sizeof(req), true, &skb);
21611966a507SMeiChia Chiu if (ret)
21621966a507SMeiChia Chiu return ret;
21631966a507SMeiChia Chiu
21641258c156SRyder Lee mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data);
21651258c156SRyder Lee
21661258c156SRyder Lee /* accumulate stats, these are clear-on-read */
21671258c156SRyder Lee #define __dl_u32(s) phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s)
21681258c156SRyder Lee #define __ul_u32(s) phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s)
21691258c156SRyder Lee __dl_u32(cck_cnt);
21701258c156SRyder Lee __dl_u32(ofdm_cnt);
21711258c156SRyder Lee __dl_u32(htmix_cnt);
21721258c156SRyder Lee __dl_u32(htgf_cnt);
21731258c156SRyder Lee __dl_u32(vht_su_cnt);
21741258c156SRyder Lee __dl_u32(vht_2mu_cnt);
21751258c156SRyder Lee __dl_u32(vht_3mu_cnt);
21761258c156SRyder Lee __dl_u32(vht_4mu_cnt);
21771258c156SRyder Lee __dl_u32(he_su_cnt);
21781258c156SRyder Lee __dl_u32(he_2ru_cnt);
21791258c156SRyder Lee __dl_u32(he_2mu_cnt);
21801258c156SRyder Lee __dl_u32(he_3ru_cnt);
21811258c156SRyder Lee __dl_u32(he_3mu_cnt);
21821258c156SRyder Lee __dl_u32(he_4ru_cnt);
21831258c156SRyder Lee __dl_u32(he_4mu_cnt);
21841258c156SRyder Lee __dl_u32(he_5to8ru_cnt);
21851258c156SRyder Lee __dl_u32(he_9to16ru_cnt);
21861258c156SRyder Lee __dl_u32(he_gtr16ru_cnt);
21871258c156SRyder Lee
21881258c156SRyder Lee __ul_u32(hetrig_su_cnt);
21891258c156SRyder Lee __ul_u32(hetrig_2ru_cnt);
21901258c156SRyder Lee __ul_u32(hetrig_3ru_cnt);
21911258c156SRyder Lee __ul_u32(hetrig_4ru_cnt);
21921258c156SRyder Lee __ul_u32(hetrig_5to8ru_cnt);
21931258c156SRyder Lee __ul_u32(hetrig_9to16ru_cnt);
21941258c156SRyder Lee __ul_u32(hetrig_gtr16ru_cnt);
21951258c156SRyder Lee __ul_u32(hetrig_2mu_cnt);
21961258c156SRyder Lee __ul_u32(hetrig_3mu_cnt);
21971258c156SRyder Lee __ul_u32(hetrig_4mu_cnt);
21981258c156SRyder Lee #undef __dl_u32
21991258c156SRyder Lee #undef __ul_u32
22001258c156SRyder Lee
22011966a507SMeiChia Chiu dev_kfree_skb(skb);
22021966a507SMeiChia Chiu
22031966a507SMeiChia Chiu return 0;
22041966a507SMeiChia Chiu }
22051966a507SMeiChia Chiu
mt7915_mcu_set_mwds(struct mt7915_dev * dev,bool enabled)2206e151d71eSFelix Fietkau static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled)
2207e151d71eSFelix Fietkau {
2208e151d71eSFelix Fietkau struct {
2209e151d71eSFelix Fietkau u8 enable;
2210e151d71eSFelix Fietkau u8 _rsv[3];
2211e151d71eSFelix Fietkau } __packed req = {
2212e151d71eSFelix Fietkau .enable = enabled
2213e151d71eSFelix Fietkau };
2214e151d71eSFelix Fietkau
2215c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req,
2216cb5cdd4cSFelix Fietkau sizeof(req), false);
2217e151d71eSFelix Fietkau }
2218e151d71eSFelix Fietkau
mt7915_mcu_set_muru_ctrl(struct mt7915_dev * dev,u32 cmd,u32 val)2219e5a9f383SShayne Chen int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val)
2220e5a9f383SShayne Chen {
2221e5a9f383SShayne Chen struct {
2222e5a9f383SShayne Chen __le32 cmd;
2223e5a9f383SShayne Chen u8 val[4];
2224e5a9f383SShayne Chen } __packed req = {
2225e5a9f383SShayne Chen .cmd = cpu_to_le32(cmd),
2226e5a9f383SShayne Chen };
2227e5a9f383SShayne Chen
2228e5a9f383SShayne Chen put_unaligned_le32(val, req.val);
2229e5a9f383SShayne Chen
2230e5a9f383SShayne Chen return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req,
2231e5a9f383SShayne Chen sizeof(req), false);
2232e5a9f383SShayne Chen }
2233e5a9f383SShayne Chen
2234bbf77f6cSShayne Chen static int
mt7915_mcu_init_rx_airtime(struct mt7915_dev * dev)2235bbf77f6cSShayne Chen mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
2236bbf77f6cSShayne Chen {
2237bbf77f6cSShayne Chen #define RX_AIRTIME_FEATURE_CTRL 1
2238bbf77f6cSShayne Chen #define RX_AIRTIME_BITWISE_CTRL 2
2239bbf77f6cSShayne Chen #define RX_AIRTIME_CLEAR_EN 1
2240bbf77f6cSShayne Chen struct {
2241bbf77f6cSShayne Chen __le16 field;
2242bbf77f6cSShayne Chen __le16 sub_field;
2243bbf77f6cSShayne Chen __le32 set_status;
2244bbf77f6cSShayne Chen __le32 get_status;
2245bbf77f6cSShayne Chen u8 _rsv[12];
2246bbf77f6cSShayne Chen
2247bbf77f6cSShayne Chen bool airtime_en;
2248bbf77f6cSShayne Chen bool mibtime_en;
2249bbf77f6cSShayne Chen bool earlyend_en;
2250bbf77f6cSShayne Chen u8 _rsv1[9];
2251bbf77f6cSShayne Chen
2252bbf77f6cSShayne Chen bool airtime_clear;
2253bbf77f6cSShayne Chen bool mibtime_clear;
2254bbf77f6cSShayne Chen u8 _rsv2[98];
2255bbf77f6cSShayne Chen } __packed req = {
2256bbf77f6cSShayne Chen .field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL),
2257bbf77f6cSShayne Chen .sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN),
2258bbf77f6cSShayne Chen .airtime_clear = true,
2259bbf77f6cSShayne Chen };
2260bbf77f6cSShayne Chen int ret;
2261bbf77f6cSShayne Chen
2262bbf77f6cSShayne Chen ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
2263bbf77f6cSShayne Chen sizeof(req), true);
2264bbf77f6cSShayne Chen if (ret)
2265bbf77f6cSShayne Chen return ret;
2266bbf77f6cSShayne Chen
2267bbf77f6cSShayne Chen req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL);
2268bbf77f6cSShayne Chen req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN);
2269bbf77f6cSShayne Chen req.airtime_en = true;
2270bbf77f6cSShayne Chen
2271bbf77f6cSShayne Chen return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
2272bbf77f6cSShayne Chen sizeof(req), true);
2273bbf77f6cSShayne Chen }
2274bbf77f6cSShayne Chen
mt7915_red_set_watermark(struct mt7915_dev * dev)22757576a1c4SPeter Chiu static int mt7915_red_set_watermark(struct mt7915_dev *dev)
22767576a1c4SPeter Chiu {
22777576a1c4SPeter Chiu #define RED_GLOBAL_TOKEN_WATERMARK 2
22787576a1c4SPeter Chiu struct {
22797576a1c4SPeter Chiu __le32 args[3];
22807576a1c4SPeter Chiu u8 cmd;
22817576a1c4SPeter Chiu u8 version;
22827576a1c4SPeter Chiu u8 __rsv1[4];
22837576a1c4SPeter Chiu __le16 len;
22847576a1c4SPeter Chiu __le16 high_mark;
22857576a1c4SPeter Chiu __le16 low_mark;
22867576a1c4SPeter Chiu u8 __rsv2[12];
22877576a1c4SPeter Chiu } __packed req = {
22887576a1c4SPeter Chiu .args[0] = cpu_to_le32(MCU_WA_PARAM_RED_SETTING),
22897576a1c4SPeter Chiu .cmd = RED_GLOBAL_TOKEN_WATERMARK,
22907576a1c4SPeter Chiu .len = cpu_to_le16(sizeof(req) - sizeof(req.args)),
22917576a1c4SPeter Chiu .high_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256),
22927576a1c4SPeter Chiu .low_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256 - 1536),
22937576a1c4SPeter Chiu };
22947576a1c4SPeter Chiu
22957576a1c4SPeter Chiu return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET), &req,
22967576a1c4SPeter Chiu sizeof(req), false);
22977576a1c4SPeter Chiu }
22987576a1c4SPeter Chiu
mt7915_mcu_set_red(struct mt7915_dev * dev,bool enabled)22997576a1c4SPeter Chiu static int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
23007576a1c4SPeter Chiu {
23017576a1c4SPeter Chiu #define RED_DISABLE 0
23027576a1c4SPeter Chiu #define RED_BY_WA_ENABLE 2
23037576a1c4SPeter Chiu int ret;
23047576a1c4SPeter Chiu u32 red_type = enabled ? RED_BY_WA_ENABLE : RED_DISABLE;
23057576a1c4SPeter Chiu __le32 req = cpu_to_le32(red_type);
23067576a1c4SPeter Chiu
23077576a1c4SPeter Chiu if (enabled) {
23087576a1c4SPeter Chiu ret = mt7915_red_set_watermark(dev);
23097576a1c4SPeter Chiu if (ret < 0)
23107576a1c4SPeter Chiu return ret;
23117576a1c4SPeter Chiu }
23127576a1c4SPeter Chiu
23137576a1c4SPeter Chiu ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RED_ENABLE), &req,
23147576a1c4SPeter Chiu sizeof(req), false);
23157576a1c4SPeter Chiu if (ret < 0)
23167576a1c4SPeter Chiu return ret;
23177576a1c4SPeter Chiu
23187576a1c4SPeter Chiu return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
23197576a1c4SPeter Chiu MCU_WA_PARAM_RED, enabled, 0);
23207576a1c4SPeter Chiu }
23217576a1c4SPeter Chiu
mt7915_mcu_init_firmware(struct mt7915_dev * dev)23228a55712dSBo Jiao int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
2323e57b7901SRyder Lee {
2324e57b7901SRyder Lee int ret;
2325e57b7901SRyder Lee
23261c7393e6SBo Jiao /* force firmware operation mode into normal state,
23271c7393e6SBo Jiao * which should be set before firmware download stage.
23281c7393e6SBo Jiao */
23291c7393e6SBo Jiao mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
23301c7393e6SBo Jiao
23311c7393e6SBo Jiao ret = mt7915_driver_own(dev, 0);
2332e57b7901SRyder Lee if (ret)
2333e57b7901SRyder Lee return ret;
23341c7393e6SBo Jiao /* set driver own for band1 when two hif exist */
23351c7393e6SBo Jiao if (dev->hif2) {
23361c7393e6SBo Jiao ret = mt7915_driver_own(dev, 1);
23371c7393e6SBo Jiao if (ret)
23381c7393e6SBo Jiao return ret;
23391c7393e6SBo Jiao }
2340e57b7901SRyder Lee
2341e57b7901SRyder Lee ret = mt7915_load_firmware(dev);
2342e57b7901SRyder Lee if (ret)
2343e57b7901SRyder Lee return ret;
2344e57b7901SRyder Lee
2345e57b7901SRyder Lee set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
23469b121acdSShayne Chen ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0);
23479b121acdSShayne Chen if (ret)
23489b121acdSShayne Chen return ret;
23499b121acdSShayne Chen
23509b121acdSShayne Chen ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
2351706dc08cSLorenzo Bianconi if (ret)
2352706dc08cSLorenzo Bianconi return ret;
2353e57b7901SRyder Lee
2354*c71d2db2SFelix Fietkau mt76_connac_mcu_del_wtbl_all(&dev->mt76);
2355*c71d2db2SFelix Fietkau
2356db1a5a6cSSujuan Chen if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
2357db1a5a6cSSujuan Chen is_mt7915(&dev->mt76)) ||
2358db1a5a6cSSujuan Chen !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
2359f68d6762SFelix Fietkau mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
2360f68d6762SFelix Fietkau
2361706dc08cSLorenzo Bianconi ret = mt7915_mcu_set_mwds(dev, 1);
2362706dc08cSLorenzo Bianconi if (ret)
2363706dc08cSLorenzo Bianconi return ret;
2364706dc08cSLorenzo Bianconi
2365e5a9f383SShayne Chen ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE,
2366e5a9f383SShayne Chen MURU_PLATFORM_TYPE_PERF_LEVEL_2);
2367e5a9f383SShayne Chen if (ret)
2368e5a9f383SShayne Chen return ret;
2369e5a9f383SShayne Chen
2370bbf77f6cSShayne Chen ret = mt7915_mcu_init_rx_airtime(dev);
2371bbf77f6cSShayne Chen if (ret)
2372bbf77f6cSShayne Chen return ret;
2373bbf77f6cSShayne Chen
23747576a1c4SPeter Chiu return mt7915_mcu_set_red(dev, mtk_wed_device_active(&dev->mt76.mmio.wed));
2375e57b7901SRyder Lee }
2376e57b7901SRyder Lee
mt7915_mcu_init(struct mt7915_dev * dev)23778a55712dSBo Jiao int mt7915_mcu_init(struct mt7915_dev *dev)
23788a55712dSBo Jiao {
23798a55712dSBo Jiao static const struct mt76_mcu_ops mt7915_mcu_ops = {
23808a55712dSBo Jiao .headroom = sizeof(struct mt76_connac2_mcu_txd),
23818a55712dSBo Jiao .mcu_skb_send_msg = mt7915_mcu_send_message,
23828a55712dSBo Jiao .mcu_parse_response = mt7915_mcu_parse_response,
23838a55712dSBo Jiao };
23848a55712dSBo Jiao
23858a55712dSBo Jiao dev->mt76.mcu_ops = &mt7915_mcu_ops;
23868a55712dSBo Jiao
23878a55712dSBo Jiao return mt7915_mcu_init_firmware(dev);
23888a55712dSBo Jiao }
23898a55712dSBo Jiao
mt7915_mcu_exit(struct mt7915_dev * dev)2390e57b7901SRyder Lee void mt7915_mcu_exit(struct mt7915_dev *dev)
2391e57b7901SRyder Lee {
2392f535ccdfSLorenzo Bianconi mt76_connac_mcu_restart(&dev->mt76);
23931c7393e6SBo Jiao if (mt7915_firmware_state(dev, false)) {
2394e57b7901SRyder Lee dev_err(dev->mt76.dev, "Failed to exit mcu\n");
239549bd7828SLorenzo Bianconi goto out;
2396e57b7901SRyder Lee }
2397e57b7901SRyder Lee
23981c7393e6SBo Jiao mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
23991c7393e6SBo Jiao if (dev->hif2)
24001c7393e6SBo Jiao mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
24011c7393e6SBo Jiao MT_TOP_LPCR_HOST_FW_OWN);
240249bd7828SLorenzo Bianconi out:
2403e57b7901SRyder Lee skb_queue_purge(&dev->mt76.mcu.res_q);
2404e57b7901SRyder Lee }
2405e57b7901SRyder Lee
240690e3abf0SFelix Fietkau static int
mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev * dev,int band)240790e3abf0SFelix Fietkau mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band)
240890e3abf0SFelix Fietkau {
240990e3abf0SFelix Fietkau struct {
241090e3abf0SFelix Fietkau u8 operation;
241190e3abf0SFelix Fietkau u8 count;
241290e3abf0SFelix Fietkau u8 _rsv[2];
241390e3abf0SFelix Fietkau u8 index;
241490e3abf0SFelix Fietkau u8 enable;
241590e3abf0SFelix Fietkau __le16 etype;
241690e3abf0SFelix Fietkau } req = {
241790e3abf0SFelix Fietkau .operation = 1,
241890e3abf0SFelix Fietkau .count = 1,
241990e3abf0SFelix Fietkau .enable = 1,
242090e3abf0SFelix Fietkau .etype = cpu_to_le16(ETH_P_PAE),
242190e3abf0SFelix Fietkau };
242290e3abf0SFelix Fietkau
242390e3abf0SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
242490e3abf0SFelix Fietkau &req, sizeof(req), false);
242590e3abf0SFelix Fietkau }
242690e3abf0SFelix Fietkau
mt7915_mcu_set_mac(struct mt7915_dev * dev,int band,bool enable,bool hdr_trans)2427e57b7901SRyder Lee int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
2428e57b7901SRyder Lee bool enable, bool hdr_trans)
2429e57b7901SRyder Lee {
2430e57b7901SRyder Lee struct {
2431e57b7901SRyder Lee u8 operation;
2432e57b7901SRyder Lee u8 enable;
2433e57b7901SRyder Lee u8 check_bssid;
2434e57b7901SRyder Lee u8 insert_vlan;
2435e57b7901SRyder Lee u8 remove_vlan;
2436e57b7901SRyder Lee u8 tid;
2437e57b7901SRyder Lee u8 mode;
2438e57b7901SRyder Lee u8 rsv;
2439e57b7901SRyder Lee } __packed req_trans = {
2440e57b7901SRyder Lee .enable = hdr_trans,
2441e57b7901SRyder Lee };
2442e57b7901SRyder Lee struct {
2443e57b7901SRyder Lee u8 enable;
2444e57b7901SRyder Lee u8 band;
2445e57b7901SRyder Lee u8 rsv[2];
2446e57b7901SRyder Lee } __packed req_mac = {
2447e57b7901SRyder Lee .enable = enable,
2448e57b7901SRyder Lee .band = band,
2449e57b7901SRyder Lee };
2450e57b7901SRyder Lee int ret;
2451e57b7901SRyder Lee
2452c203dd62SFelix Fietkau ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
2453e57b7901SRyder Lee &req_trans, sizeof(req_trans), false);
2454e57b7901SRyder Lee if (ret)
2455e57b7901SRyder Lee return ret;
2456e57b7901SRyder Lee
245790e3abf0SFelix Fietkau if (hdr_trans)
245890e3abf0SFelix Fietkau mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band);
245990e3abf0SFelix Fietkau
2460c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL),
2461e57b7901SRyder Lee &req_mac, sizeof(req_mac), true);
2462e57b7901SRyder Lee }
2463e57b7901SRyder Lee
mt7915_mcu_update_edca(struct mt7915_dev * dev,void * param)24647ff903bcSShayne Chen int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param)
24657ff903bcSShayne Chen {
24667ff903bcSShayne Chen struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param;
24677ff903bcSShayne Chen u8 num = req->total;
24687ff903bcSShayne Chen size_t len = sizeof(*req) -
24697ff903bcSShayne Chen (IEEE80211_NUM_ACS - num) * sizeof(struct edca);
24707ff903bcSShayne Chen
2471c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req,
24727ff903bcSShayne Chen len, true);
24737ff903bcSShayne Chen }
24747ff903bcSShayne Chen
mt7915_mcu_set_tx(struct mt7915_dev * dev,struct ieee80211_vif * vif)2475e57b7901SRyder Lee int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
2476e57b7901SRyder Lee {
2477e57b7901SRyder Lee #define TX_CMD_MODE 1
24787ff903bcSShayne Chen struct mt7915_mcu_tx req = {
2479e57b7901SRyder Lee .valid = true,
2480e57b7901SRyder Lee .mode = TX_CMD_MODE,
2481e57b7901SRyder Lee .total = IEEE80211_NUM_ACS,
2482e57b7901SRyder Lee };
2483e57b7901SRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
2484e57b7901SRyder Lee int ac;
2485e57b7901SRyder Lee
2486e57b7901SRyder Lee for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
248780c99340SRyder Lee struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
2488e57b7901SRyder Lee struct edca *e = &req.edca[ac];
2489e57b7901SRyder Lee
24902a341206SFelix Fietkau e->set = WMM_PARAM_SET;
2491182071cdSLorenzo Bianconi e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
249280c99340SRyder Lee e->aifs = q->aifs;
249380c99340SRyder Lee e->txop = cpu_to_le16(q->txop);
2494e57b7901SRyder Lee
249580c99340SRyder Lee if (q->cw_min)
249680c99340SRyder Lee e->cw_min = fls(q->cw_min);
2497e57b7901SRyder Lee else
2498e57b7901SRyder Lee e->cw_min = 5;
2499e57b7901SRyder Lee
250080c99340SRyder Lee if (q->cw_max)
250180c99340SRyder Lee e->cw_max = cpu_to_le16(fls(q->cw_max));
2502e57b7901SRyder Lee else
2503e57b7901SRyder Lee e->cw_max = cpu_to_le16(10);
2504e57b7901SRyder Lee }
25057ff903bcSShayne Chen
25067ff903bcSShayne Chen return mt7915_mcu_update_edca(dev, &req);
2507e57b7901SRyder Lee }
2508e57b7901SRyder Lee
mt7915_mcu_set_fcc5_lpn(struct mt7915_dev * dev,int val)2509e57b7901SRyder Lee int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val)
2510e57b7901SRyder Lee {
2511e57b7901SRyder Lee struct {
2512cee236e1SFelix Fietkau __le32 tag;
2513cee236e1SFelix Fietkau __le16 min_lpn;
2514e57b7901SRyder Lee u8 rsv[2];
2515e57b7901SRyder Lee } __packed req = {
2516cee236e1SFelix Fietkau .tag = cpu_to_le32(0x1),
2517cee236e1SFelix Fietkau .min_lpn = cpu_to_le16(val),
2518e57b7901SRyder Lee };
2519e57b7901SRyder Lee
2520c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
2521cb5cdd4cSFelix Fietkau sizeof(req), true);
2522e57b7901SRyder Lee }
2523e57b7901SRyder Lee
mt7915_mcu_set_pulse_th(struct mt7915_dev * dev,const struct mt7915_dfs_pulse * pulse)2524e57b7901SRyder Lee int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
2525e57b7901SRyder Lee const struct mt7915_dfs_pulse *pulse)
2526e57b7901SRyder Lee {
2527e57b7901SRyder Lee struct {
2528cee236e1SFelix Fietkau __le32 tag;
2529e57b7901SRyder Lee
2530cee236e1SFelix Fietkau __le32 max_width; /* us */
2531cee236e1SFelix Fietkau __le32 max_pwr; /* dbm */
2532cee236e1SFelix Fietkau __le32 min_pwr; /* dbm */
2533cee236e1SFelix Fietkau __le32 min_stgr_pri; /* us */
2534cee236e1SFelix Fietkau __le32 max_stgr_pri; /* us */
2535cee236e1SFelix Fietkau __le32 min_cr_pri; /* us */
2536cee236e1SFelix Fietkau __le32 max_cr_pri; /* us */
2537cee236e1SFelix Fietkau } __packed req = {
2538cee236e1SFelix Fietkau .tag = cpu_to_le32(0x3),
2539cee236e1SFelix Fietkau
2540cee236e1SFelix Fietkau #define __req_field(field) .field = cpu_to_le32(pulse->field)
2541cee236e1SFelix Fietkau __req_field(max_width),
2542cee236e1SFelix Fietkau __req_field(max_pwr),
2543cee236e1SFelix Fietkau __req_field(min_pwr),
2544cee236e1SFelix Fietkau __req_field(min_stgr_pri),
2545cee236e1SFelix Fietkau __req_field(max_stgr_pri),
2546cee236e1SFelix Fietkau __req_field(min_cr_pri),
2547cee236e1SFelix Fietkau __req_field(max_cr_pri),
2548cee236e1SFelix Fietkau #undef __req_field
2549cee236e1SFelix Fietkau };
2550e57b7901SRyder Lee
2551c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
2552cb5cdd4cSFelix Fietkau sizeof(req), true);
2553e57b7901SRyder Lee }
2554e57b7901SRyder Lee
mt7915_mcu_set_radar_th(struct mt7915_dev * dev,int index,const struct mt7915_dfs_pattern * pattern)2555e57b7901SRyder Lee int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
2556e57b7901SRyder Lee const struct mt7915_dfs_pattern *pattern)
2557e57b7901SRyder Lee {
2558e57b7901SRyder Lee struct {
2559cee236e1SFelix Fietkau __le32 tag;
2560cee236e1SFelix Fietkau __le16 radar_type;
2561e57b7901SRyder Lee
2562cee236e1SFelix Fietkau u8 enb;
2563cee236e1SFelix Fietkau u8 stgr;
2564cee236e1SFelix Fietkau u8 min_crpn;
2565cee236e1SFelix Fietkau u8 max_crpn;
2566cee236e1SFelix Fietkau u8 min_crpr;
2567cee236e1SFelix Fietkau u8 min_pw;
2568bb251794SLorenzo Bianconi __le32 min_pri;
2569bb251794SLorenzo Bianconi __le32 max_pri;
2570cee236e1SFelix Fietkau u8 max_pw;
2571cee236e1SFelix Fietkau u8 min_crbn;
2572cee236e1SFelix Fietkau u8 max_crbn;
2573cee236e1SFelix Fietkau u8 min_stgpn;
2574cee236e1SFelix Fietkau u8 max_stgpn;
2575cee236e1SFelix Fietkau u8 min_stgpr;
2576cee236e1SFelix Fietkau u8 rsv[2];
2577bb251794SLorenzo Bianconi __le32 min_stgpr_diff;
2578cee236e1SFelix Fietkau } __packed req = {
2579cee236e1SFelix Fietkau .tag = cpu_to_le32(0x2),
2580cee236e1SFelix Fietkau .radar_type = cpu_to_le16(index),
2581cee236e1SFelix Fietkau
2582cee236e1SFelix Fietkau #define __req_field_u8(field) .field = pattern->field
2583cee236e1SFelix Fietkau #define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
2584cee236e1SFelix Fietkau __req_field_u8(enb),
2585cee236e1SFelix Fietkau __req_field_u8(stgr),
2586cee236e1SFelix Fietkau __req_field_u8(min_crpn),
2587cee236e1SFelix Fietkau __req_field_u8(max_crpn),
2588cee236e1SFelix Fietkau __req_field_u8(min_crpr),
2589cee236e1SFelix Fietkau __req_field_u8(min_pw),
2590cee236e1SFelix Fietkau __req_field_u32(min_pri),
2591cee236e1SFelix Fietkau __req_field_u32(max_pri),
2592cee236e1SFelix Fietkau __req_field_u8(max_pw),
2593cee236e1SFelix Fietkau __req_field_u8(min_crbn),
2594cee236e1SFelix Fietkau __req_field_u8(max_crbn),
2595cee236e1SFelix Fietkau __req_field_u8(min_stgpn),
2596cee236e1SFelix Fietkau __req_field_u8(max_stgpn),
2597cee236e1SFelix Fietkau __req_field_u8(min_stgpr),
2598cee236e1SFelix Fietkau __req_field_u32(min_stgpr_diff),
2599cee236e1SFelix Fietkau #undef __req_field_u8
2600cee236e1SFelix Fietkau #undef __req_field_u32
2601cee236e1SFelix Fietkau };
2602e57b7901SRyder Lee
2603c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
2604cb5cdd4cSFelix Fietkau sizeof(req), true);
2605e57b7901SRyder Lee }
2606e57b7901SRyder Lee
260739cdf080SLorenzo Bianconi static int
mt7915_mcu_background_chain_ctrl(struct mt7915_phy * phy,struct cfg80211_chan_def * chandef,int cmd)260839cdf080SLorenzo Bianconi mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
260939cdf080SLorenzo Bianconi struct cfg80211_chan_def *chandef,
261039cdf080SLorenzo Bianconi int cmd)
261139cdf080SLorenzo Bianconi {
261239cdf080SLorenzo Bianconi struct mt7915_dev *dev = phy->dev;
261339cdf080SLorenzo Bianconi struct mt76_phy *mphy = phy->mt76;
261439cdf080SLorenzo Bianconi struct ieee80211_channel *chan = mphy->chandef.chan;
261539cdf080SLorenzo Bianconi int freq = mphy->chandef.center_freq1;
261639cdf080SLorenzo Bianconi struct mt7915_mcu_background_chain_ctrl req = {
261739cdf080SLorenzo Bianconi .monitor_scan_type = 2, /* simple rx */
261839cdf080SLorenzo Bianconi };
261939cdf080SLorenzo Bianconi
262039cdf080SLorenzo Bianconi if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP)
262139cdf080SLorenzo Bianconi return -EINVAL;
262239cdf080SLorenzo Bianconi
262339cdf080SLorenzo Bianconi if (!cfg80211_chandef_valid(&mphy->chandef))
262439cdf080SLorenzo Bianconi return -EINVAL;
262539cdf080SLorenzo Bianconi
262639cdf080SLorenzo Bianconi switch (cmd) {
262739cdf080SLorenzo Bianconi case CH_SWITCH_BACKGROUND_SCAN_START: {
262839cdf080SLorenzo Bianconi req.chan = chan->hw_value;
262939cdf080SLorenzo Bianconi req.central_chan = ieee80211_frequency_to_channel(freq);
263039cdf080SLorenzo Bianconi req.bw = mt76_connac_chan_bw(&mphy->chandef);
263139cdf080SLorenzo Bianconi req.monitor_chan = chandef->chan->hw_value;
263239cdf080SLorenzo Bianconi req.monitor_central_chan =
263339cdf080SLorenzo Bianconi ieee80211_frequency_to_channel(chandef->center_freq1);
263439cdf080SLorenzo Bianconi req.monitor_bw = mt76_connac_chan_bw(chandef);
26353eb50cc9SRyder Lee req.band_idx = phy->mt76->band_idx;
263639cdf080SLorenzo Bianconi req.scan_mode = 1;
263739cdf080SLorenzo Bianconi break;
263839cdf080SLorenzo Bianconi }
263939cdf080SLorenzo Bianconi case CH_SWITCH_BACKGROUND_SCAN_RUNNING:
264039cdf080SLorenzo Bianconi req.monitor_chan = chandef->chan->hw_value;
264139cdf080SLorenzo Bianconi req.monitor_central_chan =
264239cdf080SLorenzo Bianconi ieee80211_frequency_to_channel(chandef->center_freq1);
26433eb50cc9SRyder Lee req.band_idx = phy->mt76->band_idx;
264439cdf080SLorenzo Bianconi req.scan_mode = 2;
264539cdf080SLorenzo Bianconi break;
264639cdf080SLorenzo Bianconi case CH_SWITCH_BACKGROUND_SCAN_STOP:
264739cdf080SLorenzo Bianconi req.chan = chan->hw_value;
264839cdf080SLorenzo Bianconi req.central_chan = ieee80211_frequency_to_channel(freq);
264939cdf080SLorenzo Bianconi req.bw = mt76_connac_chan_bw(&mphy->chandef);
265039cdf080SLorenzo Bianconi req.tx_stream = hweight8(mphy->antenna_mask);
265139cdf080SLorenzo Bianconi req.rx_stream = mphy->antenna_mask;
265239cdf080SLorenzo Bianconi break;
265339cdf080SLorenzo Bianconi default:
265439cdf080SLorenzo Bianconi return -EINVAL;
265539cdf080SLorenzo Bianconi }
265639cdf080SLorenzo Bianconi req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1;
265739cdf080SLorenzo Bianconi
265839cdf080SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL),
265939cdf080SLorenzo Bianconi &req, sizeof(req), false);
266039cdf080SLorenzo Bianconi }
266139cdf080SLorenzo Bianconi
mt7915_mcu_rdd_background_enable(struct mt7915_phy * phy,struct cfg80211_chan_def * chandef)266239cdf080SLorenzo Bianconi int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
266339cdf080SLorenzo Bianconi struct cfg80211_chan_def *chandef)
266439cdf080SLorenzo Bianconi {
266539cdf080SLorenzo Bianconi struct mt7915_dev *dev = phy->dev;
266639cdf080SLorenzo Bianconi int err, region;
266739cdf080SLorenzo Bianconi
266839cdf080SLorenzo Bianconi if (!chandef) { /* disable offchain */
266939cdf080SLorenzo Bianconi err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2,
267039cdf080SLorenzo Bianconi 0, 0);
267139cdf080SLorenzo Bianconi if (err)
267239cdf080SLorenzo Bianconi return err;
267339cdf080SLorenzo Bianconi
267439cdf080SLorenzo Bianconi return mt7915_mcu_background_chain_ctrl(phy, NULL,
267539cdf080SLorenzo Bianconi CH_SWITCH_BACKGROUND_SCAN_STOP);
267639cdf080SLorenzo Bianconi }
267739cdf080SLorenzo Bianconi
267839cdf080SLorenzo Bianconi err = mt7915_mcu_background_chain_ctrl(phy, chandef,
267939cdf080SLorenzo Bianconi CH_SWITCH_BACKGROUND_SCAN_START);
268039cdf080SLorenzo Bianconi if (err)
268139cdf080SLorenzo Bianconi return err;
268239cdf080SLorenzo Bianconi
268339cdf080SLorenzo Bianconi switch (dev->mt76.region) {
268439cdf080SLorenzo Bianconi case NL80211_DFS_ETSI:
268539cdf080SLorenzo Bianconi region = 0;
268639cdf080SLorenzo Bianconi break;
268739cdf080SLorenzo Bianconi case NL80211_DFS_JP:
268839cdf080SLorenzo Bianconi region = 2;
268939cdf080SLorenzo Bianconi break;
269039cdf080SLorenzo Bianconi case NL80211_DFS_FCC:
269139cdf080SLorenzo Bianconi default:
269239cdf080SLorenzo Bianconi region = 1;
269339cdf080SLorenzo Bianconi break;
269439cdf080SLorenzo Bianconi }
269539cdf080SLorenzo Bianconi
269639cdf080SLorenzo Bianconi return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2,
269739cdf080SLorenzo Bianconi 0, region);
269839cdf080SLorenzo Bianconi }
269939cdf080SLorenzo Bianconi
mt7915_mcu_set_chan_info(struct mt7915_phy * phy,int cmd)2700e57b7901SRyder Lee int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
2701e57b7901SRyder Lee {
2702b4d093e3SMeiChia Chiu static const u8 ch_band[] = {
2703b4d093e3SMeiChia Chiu [NL80211_BAND_2GHZ] = 0,
2704b4d093e3SMeiChia Chiu [NL80211_BAND_5GHZ] = 1,
2705b4d093e3SMeiChia Chiu [NL80211_BAND_6GHZ] = 2,
2706b4d093e3SMeiChia Chiu };
2707e57b7901SRyder Lee struct mt7915_dev *dev = phy->dev;
2708e57b7901SRyder Lee struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2709e57b7901SRyder Lee int freq1 = chandef->center_freq1;
27103eb50cc9SRyder Lee u8 band = phy->mt76->band_idx;
2711e57b7901SRyder Lee struct {
2712e57b7901SRyder Lee u8 control_ch;
2713e57b7901SRyder Lee u8 center_ch;
2714e57b7901SRyder Lee u8 bw;
2715ee0863aeSPeter Chiu u8 tx_path_num;
2716ee0863aeSPeter Chiu u8 rx_path; /* mask or num */
2717e57b7901SRyder Lee u8 switch_reason;
2718e57b7901SRyder Lee u8 band_idx;
2719e57b7901SRyder Lee u8 center_ch2; /* for 80+80 only */
2720e57b7901SRyder Lee __le16 cac_case;
2721e57b7901SRyder Lee u8 channel_band;
2722e57b7901SRyder Lee u8 rsv0;
2723e57b7901SRyder Lee __le32 outband_freq;
2724e57b7901SRyder Lee u8 txpower_drop;
2725e57b7901SRyder Lee u8 ap_bw;
2726e57b7901SRyder Lee u8 ap_center_ch;
2727e57b7901SRyder Lee u8 rsv1[57];
2728e57b7901SRyder Lee } __packed req = {
2729e57b7901SRyder Lee .control_ch = chandef->chan->hw_value,
2730e57b7901SRyder Lee .center_ch = ieee80211_frequency_to_channel(freq1),
273144c73d17SLorenzo Bianconi .bw = mt76_connac_chan_bw(chandef),
2732ee0863aeSPeter Chiu .tx_path_num = hweight16(phy->mt76->chainmask),
27333eb50cc9SRyder Lee .rx_path = phy->mt76->chainmask >> (dev->chainshift * band),
27343eb50cc9SRyder Lee .band_idx = band,
2735b4d093e3SMeiChia Chiu .channel_band = ch_band[chandef->chan->band],
2736e57b7901SRyder Lee };
2737e57b7901SRyder Lee
2738aadf0953SShayne Chen #ifdef CONFIG_NL80211_TESTMODE
2739c918c74dSShayne Chen if (phy->mt76->test.tx_antenna_mask &&
2740b61699d2SShayne Chen mt76_testmode_enabled(phy->mt76)) {
2741ee0863aeSPeter Chiu req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask);
2742ee0863aeSPeter Chiu req.rx_path = phy->mt76->test.tx_antenna_mask;
2743aadf0953SShayne Chen }
2744aadf0953SShayne Chen #endif
2745aadf0953SShayne Chen
27467a9a957bSShayne Chen if (mt76_connac_spe_idx(phy->mt76->antenna_mask))
27477a9a957bSShayne Chen req.tx_path_num = fls(phy->mt76->antenna_mask);
27487a9a957bSShayne Chen
274994ed41a7SShayne Chen if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
275000a883e6SFelix Fietkau req.switch_reason = CH_SWITCH_NORMAL;
2751e70f6ad7SStanleyYP Wang else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
2752e70f6ad7SStanleyYP Wang phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
2753062d62e3SShayne Chen req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
275400a883e6SFelix Fietkau else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
275500a883e6SFelix Fietkau NL80211_IFTYPE_AP))
2756e57b7901SRyder Lee req.switch_reason = CH_SWITCH_DFS;
2757e57b7901SRyder Lee else
2758e57b7901SRyder Lee req.switch_reason = CH_SWITCH_NORMAL;
2759e57b7901SRyder Lee
2760c203dd62SFelix Fietkau if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
2761ee0863aeSPeter Chiu req.rx_path = hweight8(req.rx_path);
2762e57b7901SRyder Lee
2763e57b7901SRyder Lee if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
2764e57b7901SRyder Lee int freq2 = chandef->center_freq2;
2765e57b7901SRyder Lee
2766e57b7901SRyder Lee req.center_ch2 = ieee80211_frequency_to_channel(freq2);
2767e57b7901SRyder Lee }
2768e57b7901SRyder Lee
2769cb5cdd4cSFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
2770e57b7901SRyder Lee }
2771e57b7901SRyder Lee
mt7915_mcu_set_eeprom_flash(struct mt7915_dev * dev)277226f18380SShayne Chen static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
277326f18380SShayne Chen {
277482a980f8SShayne Chen #define MAX_PAGE_IDX_MASK GENMASK(7, 5)
277526f18380SShayne Chen #define PAGE_IDX_MASK GENMASK(4, 2)
277626f18380SShayne Chen #define PER_PAGE_SIZE 0x400
277726f18380SShayne Chen struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER };
2778beed8beaSBo Jiao u16 eeprom_size = mt7915_eeprom_size(dev);
2779beed8beaSBo Jiao u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE);
278026f18380SShayne Chen u8 *eep = (u8 *)dev->mt76.eeprom.data;
278126f18380SShayne Chen int eep_len;
278226f18380SShayne Chen int i;
278326f18380SShayne Chen
278482a980f8SShayne Chen for (i = 0; i < total; i++, eep += eep_len) {
278526f18380SShayne Chen struct sk_buff *skb;
278626f18380SShayne Chen int ret;
278726f18380SShayne Chen
2788beed8beaSBo Jiao if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE))
2789beed8beaSBo Jiao eep_len = eeprom_size % PER_PAGE_SIZE;
279026f18380SShayne Chen else
279126f18380SShayne Chen eep_len = PER_PAGE_SIZE;
279226f18380SShayne Chen
279326f18380SShayne Chen skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
279426f18380SShayne Chen sizeof(req) + eep_len);
279526f18380SShayne Chen if (!skb)
279626f18380SShayne Chen return -ENOMEM;
279726f18380SShayne Chen
279882a980f8SShayne Chen req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
279926f18380SShayne Chen FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
280026f18380SShayne Chen req.len = cpu_to_le16(eep_len);
280126f18380SShayne Chen
280226f18380SShayne Chen skb_put_data(skb, &req, sizeof(req));
280326f18380SShayne Chen skb_put_data(skb, eep, eep_len);
280426f18380SShayne Chen
280526f18380SShayne Chen ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
2806c203dd62SFelix Fietkau MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
280726f18380SShayne Chen if (ret)
280826f18380SShayne Chen return ret;
280926f18380SShayne Chen }
281026f18380SShayne Chen
281126f18380SShayne Chen return 0;
281226f18380SShayne Chen }
281326f18380SShayne Chen
mt7915_mcu_set_eeprom(struct mt7915_dev * dev)2814e57b7901SRyder Lee int mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
2815e57b7901SRyder Lee {
281626f18380SShayne Chen struct mt7915_mcu_eeprom req = {
2817e57b7901SRyder Lee .buffer_mode = EE_MODE_EFUSE,
2818e57b7901SRyder Lee .format = EE_FORMAT_WHOLE,
2819e57b7901SRyder Lee };
2820e57b7901SRyder Lee
282126f18380SShayne Chen if (dev->flash_mode)
282226f18380SShayne Chen return mt7915_mcu_set_eeprom_flash(dev);
282326f18380SShayne Chen
2824c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
2825e57b7901SRyder Lee &req, sizeof(req), true);
2826e57b7901SRyder Lee }
2827e57b7901SRyder Lee
mt7915_mcu_get_eeprom(struct mt7915_dev * dev,u32 offset)2828e57b7901SRyder Lee int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
2829e57b7901SRyder Lee {
2830e57b7901SRyder Lee struct mt7915_mcu_eeprom_info req = {
283183d229d2SShayne Chen .addr = cpu_to_le32(round_down(offset,
283283d229d2SShayne Chen MT7915_EEPROM_BLOCK_SIZE)),
2833e57b7901SRyder Lee };
283499de49fcSFelix Fietkau struct mt7915_mcu_eeprom_info *res;
283599de49fcSFelix Fietkau struct sk_buff *skb;
283699de49fcSFelix Fietkau int ret;
283799de49fcSFelix Fietkau u8 *buf;
2838e57b7901SRyder Lee
283959b27a7dSRyder Lee ret = mt76_mcu_send_and_get_msg(&dev->mt76,
284059b27a7dSRyder Lee MCU_EXT_QUERY(EFUSE_ACCESS),
284159b27a7dSRyder Lee &req, sizeof(req), true, &skb);
284299de49fcSFelix Fietkau if (ret)
284399de49fcSFelix Fietkau return ret;
284499de49fcSFelix Fietkau
284599de49fcSFelix Fietkau res = (struct mt7915_mcu_eeprom_info *)skb->data;
284699de49fcSFelix Fietkau buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
284783d229d2SShayne Chen memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
284899de49fcSFelix Fietkau dev_kfree_skb(skb);
284999de49fcSFelix Fietkau
285099de49fcSFelix Fietkau return 0;
2851e57b7901SRyder Lee }
2852e57b7901SRyder Lee
mt7915_mcu_get_eeprom_free_block(struct mt7915_dev * dev,u8 * block_num)2853bbc1d415SShayne Chen int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num)
2854bbc1d415SShayne Chen {
2855bbc1d415SShayne Chen struct {
2856bbc1d415SShayne Chen u8 _rsv;
2857bbc1d415SShayne Chen u8 version;
2858bbc1d415SShayne Chen u8 die_idx;
2859bbc1d415SShayne Chen u8 _rsv2;
2860bbc1d415SShayne Chen } __packed req = {
2861bbc1d415SShayne Chen .version = 1,
2862bbc1d415SShayne Chen };
2863bbc1d415SShayne Chen struct sk_buff *skb;
2864bbc1d415SShayne Chen int ret;
2865bbc1d415SShayne Chen
286659b27a7dSRyder Lee ret = mt76_mcu_send_and_get_msg(&dev->mt76,
286759b27a7dSRyder Lee MCU_EXT_QUERY(EFUSE_FREE_BLOCK),
286859b27a7dSRyder Lee &req, sizeof(req), true, &skb);
2869bbc1d415SShayne Chen if (ret)
2870bbc1d415SShayne Chen return ret;
2871bbc1d415SShayne Chen
2872bbc1d415SShayne Chen *block_num = *(u8 *)skb->data;
2873bbc1d415SShayne Chen dev_kfree_skb(skb);
2874bbc1d415SShayne Chen
2875bbc1d415SShayne Chen return 0;
2876bbc1d415SShayne Chen }
2877bbc1d415SShayne Chen
mt7915_mcu_set_pre_cal(struct mt7915_dev * dev,u8 idx,u8 * data,u32 len,int cmd)2878495184acSRyder Lee static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
2879495184acSRyder Lee u8 *data, u32 len, int cmd)
2880495184acSRyder Lee {
2881495184acSRyder Lee struct {
2882495184acSRyder Lee u8 dir;
2883495184acSRyder Lee u8 valid;
2884495184acSRyder Lee __le16 bitmap;
2885495184acSRyder Lee s8 precal;
2886495184acSRyder Lee u8 action;
2887495184acSRyder Lee u8 band;
2888495184acSRyder Lee u8 idx;
2889495184acSRyder Lee u8 rsv[4];
2890495184acSRyder Lee __le32 len;
28913924715fSDan Carpenter } req = {};
2892495184acSRyder Lee struct sk_buff *skb;
2893495184acSRyder Lee
2894495184acSRyder Lee skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
2895495184acSRyder Lee if (!skb)
2896495184acSRyder Lee return -ENOMEM;
2897495184acSRyder Lee
2898495184acSRyder Lee req.idx = idx;
2899495184acSRyder Lee req.len = cpu_to_le32(len);
2900495184acSRyder Lee skb_put_data(skb, &req, sizeof(req));
2901495184acSRyder Lee skb_put_data(skb, data, len);
2902495184acSRyder Lee
2903495184acSRyder Lee return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false);
2904495184acSRyder Lee }
2905495184acSRyder Lee
mt7915_mcu_apply_group_cal(struct mt7915_dev * dev)2906495184acSRyder Lee int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
2907495184acSRyder Lee {
2908495184acSRyder Lee u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
2909495184acSRyder Lee u32 total = MT_EE_CAL_GROUP_SIZE;
2910495184acSRyder Lee
2911495184acSRyder Lee if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP))
2912495184acSRyder Lee return 0;
2913495184acSRyder Lee
2914495184acSRyder Lee /*
2915495184acSRyder Lee * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG
2916495184acSRyder Lee * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC
2917495184acSRyder Lee */
2918495184acSRyder Lee while (total > 0) {
2919495184acSRyder Lee int ret, len;
2920495184acSRyder Lee
2921495184acSRyder Lee len = min_t(u32, total, MT_EE_CAL_UNIT);
2922495184acSRyder Lee
2923495184acSRyder Lee ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len,
2924495184acSRyder Lee MCU_EXT_CMD(GROUP_PRE_CAL_INFO));
2925495184acSRyder Lee if (ret)
2926495184acSRyder Lee return ret;
2927495184acSRyder Lee
2928495184acSRyder Lee total -= len;
2929495184acSRyder Lee cal += len;
2930495184acSRyder Lee idx++;
2931495184acSRyder Lee }
2932495184acSRyder Lee
2933495184acSRyder Lee return 0;
2934495184acSRyder Lee }
2935495184acSRyder Lee
mt7915_find_freq_idx(const u16 * freqs,int n_freqs,u16 cur)2936495184acSRyder Lee static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
2937495184acSRyder Lee {
2938495184acSRyder Lee int i;
2939495184acSRyder Lee
2940495184acSRyder Lee for (i = 0; i < n_freqs; i++)
2941495184acSRyder Lee if (cur == freqs[i])
2942495184acSRyder Lee return i;
2943495184acSRyder Lee
2944495184acSRyder Lee return -1;
2945495184acSRyder Lee }
2946495184acSRyder Lee
mt7915_dpd_freq_idx(u16 freq,u8 bw)2947495184acSRyder Lee static int mt7915_dpd_freq_idx(u16 freq, u8 bw)
2948495184acSRyder Lee {
2949495184acSRyder Lee static const u16 freq_list[] = {
2950495184acSRyder Lee 5180, 5200, 5220, 5240,
2951495184acSRyder Lee 5260, 5280, 5300, 5320,
2952495184acSRyder Lee 5500, 5520, 5540, 5560,
2953495184acSRyder Lee 5580, 5600, 5620, 5640,
2954495184acSRyder Lee 5660, 5680, 5700, 5745,
2955495184acSRyder Lee 5765, 5785, 5805, 5825
2956495184acSRyder Lee };
2957495184acSRyder Lee int offset_2g = ARRAY_SIZE(freq_list);
2958495184acSRyder Lee int idx;
2959495184acSRyder Lee
2960495184acSRyder Lee if (freq < 4000) {
2961495184acSRyder Lee if (freq < 2432)
2962495184acSRyder Lee return offset_2g;
2963495184acSRyder Lee if (freq < 2457)
2964495184acSRyder Lee return offset_2g + 1;
2965495184acSRyder Lee
2966495184acSRyder Lee return offset_2g + 2;
2967495184acSRyder Lee }
2968495184acSRyder Lee
2969495184acSRyder Lee if (bw == NL80211_CHAN_WIDTH_80P80 || bw == NL80211_CHAN_WIDTH_160)
2970495184acSRyder Lee return -1;
2971495184acSRyder Lee
2972495184acSRyder Lee if (bw != NL80211_CHAN_WIDTH_20) {
2973495184acSRyder Lee idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2974495184acSRyder Lee freq + 10);
2975495184acSRyder Lee if (idx >= 0)
2976495184acSRyder Lee return idx;
2977495184acSRyder Lee
2978495184acSRyder Lee idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2979495184acSRyder Lee freq - 10);
2980495184acSRyder Lee if (idx >= 0)
2981495184acSRyder Lee return idx;
2982495184acSRyder Lee }
2983495184acSRyder Lee
2984495184acSRyder Lee return mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
2985495184acSRyder Lee }
2986495184acSRyder Lee
mt7915_mcu_apply_tx_dpd(struct mt7915_phy * phy)2987495184acSRyder Lee int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
2988495184acSRyder Lee {
2989495184acSRyder Lee struct mt7915_dev *dev = phy->dev;
2990495184acSRyder Lee struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2991861fad47SDan Carpenter u16 total = 2, center_freq = chandef->center_freq1;
2992495184acSRyder Lee u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
2993861fad47SDan Carpenter int idx;
2994495184acSRyder Lee
2995495184acSRyder Lee if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD))
2996495184acSRyder Lee return 0;
2997495184acSRyder Lee
2998495184acSRyder Lee idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
2999495184acSRyder Lee if (idx < 0)
3000495184acSRyder Lee return -EINVAL;
3001495184acSRyder Lee
3002495184acSRyder Lee /* Items: Tx DPD, Tx Flatness */
3003495184acSRyder Lee idx = idx * 2;
3004495184acSRyder Lee cal += MT_EE_CAL_GROUP_SIZE;
3005495184acSRyder Lee
3006495184acSRyder Lee while (total--) {
3007495184acSRyder Lee int ret;
3008495184acSRyder Lee
3009495184acSRyder Lee cal += (idx * MT_EE_CAL_UNIT);
3010495184acSRyder Lee ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT,
3011495184acSRyder Lee MCU_EXT_CMD(DPD_PRE_CAL_INFO));
3012495184acSRyder Lee if (ret)
3013495184acSRyder Lee return ret;
3014495184acSRyder Lee
3015495184acSRyder Lee idx++;
3016495184acSRyder Lee }
3017495184acSRyder Lee
3018495184acSRyder Lee return 0;
3019495184acSRyder Lee }
3020495184acSRyder Lee
mt7915_mcu_get_chan_mib_info(struct mt7915_phy * phy,bool chan_switch)302165430028SRyder Lee int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch)
302265430028SRyder Lee {
302365430028SRyder Lee struct mt76_channel_state *state = phy->mt76->chan_state;
302465430028SRyder Lee struct mt76_channel_state *state_ts = &phy->state_ts;
302565430028SRyder Lee struct mt7915_dev *dev = phy->dev;
3026b0bfa005SRyder Lee struct mt7915_mcu_mib *res, req[5];
302765430028SRyder Lee struct sk_buff *skb;
30283fc36de8SRyder Lee static const u32 *offs;
30293fc36de8SRyder Lee int i, ret, len, offs_cc;
3030b0bfa005SRyder Lee u64 cc_tx;
3031417a4534SBo Jiao
30323fc36de8SRyder Lee /* strict order */
30333fc36de8SRyder Lee if (is_mt7915(&dev->mt76)) {
30343fc36de8SRyder Lee static const u32 chip_offs[] = {
30353fc36de8SRyder Lee MIB_NON_WIFI_TIME,
30363fc36de8SRyder Lee MIB_TX_TIME,
30373fc36de8SRyder Lee MIB_RX_TIME,
30383fc36de8SRyder Lee MIB_OBSS_AIRTIME,
30393fc36de8SRyder Lee MIB_TXOP_INIT_COUNT,
30403fc36de8SRyder Lee };
30413fc36de8SRyder Lee len = ARRAY_SIZE(chip_offs);
30423fc36de8SRyder Lee offs = chip_offs;
30433fc36de8SRyder Lee offs_cc = 20;
30443fc36de8SRyder Lee } else {
30453fc36de8SRyder Lee static const u32 chip_offs[] = {
30463fc36de8SRyder Lee MIB_NON_WIFI_TIME_V2,
30473fc36de8SRyder Lee MIB_TX_TIME_V2,
30483fc36de8SRyder Lee MIB_RX_TIME_V2,
30493fc36de8SRyder Lee MIB_OBSS_AIRTIME_V2
30503fc36de8SRyder Lee };
30513fc36de8SRyder Lee len = ARRAY_SIZE(chip_offs);
30523fc36de8SRyder Lee offs = chip_offs;
30533fc36de8SRyder Lee offs_cc = 0;
3054cef37c78SBo Jiao }
305565430028SRyder Lee
30563fc36de8SRyder Lee for (i = 0; i < len; i++) {
30573eb50cc9SRyder Lee req[i].band = cpu_to_le32(phy->mt76->band_idx);
30583fc36de8SRyder Lee req[i].offs = cpu_to_le32(offs[i]);
305965430028SRyder Lee }
306065430028SRyder Lee
306165430028SRyder Lee ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO),
30624f1875c2SRyder Lee req, len * sizeof(req[0]), true, &skb);
306365430028SRyder Lee if (ret)
306465430028SRyder Lee return ret;
306565430028SRyder Lee
30663fc36de8SRyder Lee res = (struct mt7915_mcu_mib *)(skb->data + offs_cc);
306765430028SRyder Lee
3068b0bfa005SRyder Lee #define __res_u64(s) le64_to_cpu(res[s].data)
3069b0bfa005SRyder Lee /* subtract Tx backoff time from Tx duration */
3070b0bfa005SRyder Lee cc_tx = is_mt7915(&dev->mt76) ? __res_u64(1) - __res_u64(4) : __res_u64(1);
3071b0bfa005SRyder Lee
307265430028SRyder Lee if (chan_switch)
307365430028SRyder Lee goto out;
307465430028SRyder Lee
3075b0bfa005SRyder Lee state->cc_tx += cc_tx - state_ts->cc_tx;
307665430028SRyder Lee state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx;
307765430028SRyder Lee state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx;
3078b0bfa005SRyder Lee state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) -
3079b0bfa005SRyder Lee state_ts->cc_busy;
308065430028SRyder Lee
308165430028SRyder Lee out:
3082b0bfa005SRyder Lee state_ts->cc_tx = cc_tx;
308365430028SRyder Lee state_ts->cc_bss_rx = __res_u64(2);
308465430028SRyder Lee state_ts->cc_rx = __res_u64(2) + __res_u64(3);
3085b0bfa005SRyder Lee state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3);
308665430028SRyder Lee #undef __res_u64
308765430028SRyder Lee
308865430028SRyder Lee dev_kfree_skb(skb);
308965430028SRyder Lee
309065430028SRyder Lee return 0;
309165430028SRyder Lee }
309265430028SRyder Lee
mt7915_mcu_get_temperature(struct mt7915_phy * phy)309333fe9c63SRyder Lee int mt7915_mcu_get_temperature(struct mt7915_phy *phy)
3094e57b7901SRyder Lee {
309533fe9c63SRyder Lee struct mt7915_dev *dev = phy->dev;
3096e57b7901SRyder Lee struct {
3097e57b7901SRyder Lee u8 ctrl_id;
3098e57b7901SRyder Lee u8 action;
30996f917bbaSRyder Lee u8 band_idx;
3100e57b7901SRyder Lee u8 rsv[5];
3101e57b7901SRyder Lee } req = {
3102e57b7901SRyder Lee .ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
31033eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
3104e57b7901SRyder Lee };
3105e57b7901SRyder Lee
3106c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
3107e57b7901SRyder Lee sizeof(req), true);
3108e57b7901SRyder Lee }
3109e57b7901SRyder Lee
mt7915_mcu_set_thermal_throttling(struct mt7915_phy * phy,u8 state)311034b877d9SRyder Lee int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
311134b877d9SRyder Lee {
311234b877d9SRyder Lee struct mt7915_dev *dev = phy->dev;
31135ad42d19SHoward Hsu struct mt7915_mcu_thermal_ctrl req = {
31145ad42d19SHoward Hsu .band_idx = phy->mt76->band_idx,
31155ad42d19SHoward Hsu .ctrl_id = THERMAL_PROTECT_DUTY_CONFIG,
31165ad42d19SHoward Hsu };
31175ad42d19SHoward Hsu int level, ret;
31185ad42d19SHoward Hsu
31195ad42d19SHoward Hsu /* set duty cycle and level */
31205ad42d19SHoward Hsu for (level = 0; level < 4; level++) {
31215ad42d19SHoward Hsu req.duty.duty_level = level;
31225ad42d19SHoward Hsu req.duty.duty_cycle = state;
31235ad42d19SHoward Hsu state /= 2;
31245ad42d19SHoward Hsu
31255ad42d19SHoward Hsu ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
31265ad42d19SHoward Hsu &req, sizeof(req), false);
31275ad42d19SHoward Hsu if (ret)
31285ad42d19SHoward Hsu return ret;
31295ad42d19SHoward Hsu }
31305ad42d19SHoward Hsu return 0;
31315ad42d19SHoward Hsu }
31325ad42d19SHoward Hsu
mt7915_mcu_set_thermal_protect(struct mt7915_phy * phy)31335ad42d19SHoward Hsu int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy)
31345ad42d19SHoward Hsu {
31355ad42d19SHoward Hsu struct mt7915_dev *dev = phy->dev;
313634b877d9SRyder Lee struct {
313734b877d9SRyder Lee struct mt7915_mcu_thermal_ctrl ctrl;
313834b877d9SRyder Lee
313934b877d9SRyder Lee __le32 trigger_temp;
314034b877d9SRyder Lee __le32 restore_temp;
314134b877d9SRyder Lee __le16 sustain_time;
314234b877d9SRyder Lee u8 rsv[2];
314334b877d9SRyder Lee } __packed req = {
314434b877d9SRyder Lee .ctrl = {
31453eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
31465ad42d19SHoward Hsu .type.protect_type = 1,
31475ad42d19SHoward Hsu .type.trigger_type = 1,
314834b877d9SRyder Lee },
314934b877d9SRyder Lee };
315034b877d9SRyder Lee int ret;
315134b877d9SRyder Lee
31525ad42d19SHoward Hsu req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
315334b877d9SRyder Lee ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
315434b877d9SRyder Lee &req, sizeof(req.ctrl), false);
31555ad42d19SHoward Hsu
315634b877d9SRyder Lee if (ret)
315734b877d9SRyder Lee return ret;
315834b877d9SRyder Lee
315934b877d9SRyder Lee /* set high-temperature trigger threshold */
316034b877d9SRyder Lee req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
316102ee68b9SRyder Lee /* add a safety margin ~10 */
316202ee68b9SRyder Lee req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
316302ee68b9SRyder Lee req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
316402ee68b9SRyder Lee req.sustain_time = cpu_to_le16(10);
316534b877d9SRyder Lee
316634b877d9SRyder Lee return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
316734b877d9SRyder Lee &req, sizeof(req), false);
316834b877d9SRyder Lee }
316934b877d9SRyder Lee
mt7915_mcu_set_txpower_frame_min(struct mt7915_phy * phy,s8 txpower)317066b181b8SRyder Lee int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower)
317166b181b8SRyder Lee {
317266b181b8SRyder Lee struct mt7915_dev *dev = phy->dev;
317366b181b8SRyder Lee struct {
317466b181b8SRyder Lee u8 format_id;
317566b181b8SRyder Lee u8 rsv;
317666b181b8SRyder Lee u8 band_idx;
317766b181b8SRyder Lee s8 txpower_min;
317866b181b8SRyder Lee } __packed req = {
317966b181b8SRyder Lee .format_id = TX_POWER_LIMIT_FRAME_MIN,
31803eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
318166b181b8SRyder Lee .txpower_min = txpower * 2, /* 0.5db */
318266b181b8SRyder Lee };
318366b181b8SRyder Lee
318466b181b8SRyder Lee return mt76_mcu_send_msg(&dev->mt76,
318566b181b8SRyder Lee MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
318666b181b8SRyder Lee sizeof(req), true);
318766b181b8SRyder Lee }
318866b181b8SRyder Lee
mt7915_mcu_set_txpower_frame(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,s8 txpower)318966b181b8SRyder Lee int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
319066b181b8SRyder Lee struct ieee80211_vif *vif,
319166b181b8SRyder Lee struct ieee80211_sta *sta, s8 txpower)
319266b181b8SRyder Lee {
319366b181b8SRyder Lee struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
319466b181b8SRyder Lee struct mt7915_dev *dev = phy->dev;
319566b181b8SRyder Lee struct mt76_phy *mphy = phy->mt76;
319666b181b8SRyder Lee struct {
319766b181b8SRyder Lee u8 format_id;
319866b181b8SRyder Lee u8 rsv[3];
319966b181b8SRyder Lee u8 band_idx;
320066b181b8SRyder Lee s8 txpower_max;
320166b181b8SRyder Lee __le16 wcid;
320266b181b8SRyder Lee s8 txpower_offs[48];
320366b181b8SRyder Lee } __packed req = {
320466b181b8SRyder Lee .format_id = TX_POWER_LIMIT_FRAME,
32053eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
320666b181b8SRyder Lee .txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2),
320766b181b8SRyder Lee .wcid = cpu_to_le16(msta->wcid.idx),
320866b181b8SRyder Lee };
320954dd1dc7SRyder Lee int ret;
321066b181b8SRyder Lee s8 txpower_sku[MT7915_SKU_RATE_NUM];
321166b181b8SRyder Lee
321266b181b8SRyder Lee ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku));
321366b181b8SRyder Lee if (ret)
321466b181b8SRyder Lee return ret;
321566b181b8SRyder Lee
321654dd1dc7SRyder Lee txpower = mt7915_get_power_bound(phy, txpower);
321766b181b8SRyder Lee if (txpower > mphy->txpower_cur || txpower < 0)
321866b181b8SRyder Lee return -EINVAL;
321966b181b8SRyder Lee
322066b181b8SRyder Lee if (txpower) {
322166b181b8SRyder Lee u32 offs, len, i;
322266b181b8SRyder Lee
322366b181b8SRyder Lee if (sta->deflink.ht_cap.ht_supported) {
322466b181b8SRyder Lee const u8 *sku_len = mt7915_sku_group_len;
322566b181b8SRyder Lee
322666b181b8SRyder Lee offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM];
322766b181b8SRyder Lee len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40];
322866b181b8SRyder Lee
322966b181b8SRyder Lee if (sta->deflink.vht_cap.vht_supported) {
323066b181b8SRyder Lee offs += len;
323166b181b8SRyder Lee len = sku_len[SKU_VHT_BW20] * 4;
323266b181b8SRyder Lee
323366b181b8SRyder Lee if (sta->deflink.he_cap.has_he) {
323466b181b8SRyder Lee offs += len + sku_len[SKU_HE_RU26] * 3;
323566b181b8SRyder Lee len = sku_len[SKU_HE_RU242] * 4;
323666b181b8SRyder Lee }
323766b181b8SRyder Lee }
323866b181b8SRyder Lee } else {
323966b181b8SRyder Lee return -EINVAL;
324066b181b8SRyder Lee }
324166b181b8SRyder Lee
324266b181b8SRyder Lee for (i = 0; i < len; i++, offs++)
324366b181b8SRyder Lee req.txpower_offs[i] =
324466b181b8SRyder Lee DIV_ROUND_UP(txpower - txpower_sku[offs], 2);
324566b181b8SRyder Lee }
324666b181b8SRyder Lee
324766b181b8SRyder Lee return mt76_mcu_send_msg(&dev->mt76,
324866b181b8SRyder Lee MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
324966b181b8SRyder Lee sizeof(req), true);
325066b181b8SRyder Lee }
325166b181b8SRyder Lee
mt7915_mcu_set_txpower_sku(struct mt7915_phy * phy)3252ecb187a7SShayne Chen int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
3253f1d96236SRyder Lee {
3254f1d96236SRyder Lee struct mt7915_dev *dev = phy->dev;
3255f1d96236SRyder Lee struct mt76_phy *mphy = phy->mt76;
3256f1d96236SRyder Lee struct ieee80211_hw *hw = mphy->hw;
3257e3296759SRyder Lee struct mt7915_mcu_txpower_sku req = {
325866b181b8SRyder Lee .format_id = TX_POWER_LIMIT_TABLE,
32593eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
3260f1d96236SRyder Lee };
3261790d228aSShayne Chen struct mt76_power_limits limits_array;
3262ecb187a7SShayne Chen s8 *la = (s8 *)&limits_array;
326354dd1dc7SRyder Lee int i, idx;
326454dd1dc7SRyder Lee int tx_power;
3265f1d96236SRyder Lee
326654dd1dc7SRyder Lee tx_power = mt7915_get_power_bound(phy, hw->conf.power_level);
3267790d228aSShayne Chen tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
3268790d228aSShayne Chen &limits_array, tx_power);
3269790d228aSShayne Chen mphy->txpower_cur = tx_power;
3270790d228aSShayne Chen
3271ecb187a7SShayne Chen for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
3272ecb187a7SShayne Chen u8 mcs_num, len = mt7915_sku_group_len[i];
3273790d228aSShayne Chen int j;
3274790d228aSShayne Chen
3275790d228aSShayne Chen if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) {
3276790d228aSShayne Chen mcs_num = 10;
3277790d228aSShayne Chen
3278790d228aSShayne Chen if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
3279790d228aSShayne Chen la = (s8 *)&limits_array + 12;
3280ecb187a7SShayne Chen } else {
3281ecb187a7SShayne Chen mcs_num = len;
3282790d228aSShayne Chen }
3283790d228aSShayne Chen
3284ecb187a7SShayne Chen for (j = 0; j < min_t(u8, mcs_num, len); j++)
3285e3296759SRyder Lee req.txpower_sku[idx + j] = la[j];
3286ecb187a7SShayne Chen
3287790d228aSShayne Chen la += mcs_num;
3288ecb187a7SShayne Chen idx += len;
3289790d228aSShayne Chen }
3290f1d96236SRyder Lee
3291cb5cdd4cSFelix Fietkau return mt76_mcu_send_msg(&dev->mt76,
3292c203dd62SFelix Fietkau MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
3293cb5cdd4cSFelix Fietkau sizeof(req), true);
3294f1d96236SRyder Lee }
3295f1d96236SRyder Lee
mt7915_mcu_get_txpower_sku(struct mt7915_phy * phy,s8 * txpower,int len)3296ae130bb8SShayne Chen int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
3297ae130bb8SShayne Chen {
3298ae130bb8SShayne Chen #define RATE_POWER_INFO 2
3299ae130bb8SShayne Chen struct mt7915_dev *dev = phy->dev;
3300ae130bb8SShayne Chen struct {
3301ae130bb8SShayne Chen u8 format_id;
3302ae130bb8SShayne Chen u8 category;
33036f917bbaSRyder Lee u8 band_idx;
3304ae130bb8SShayne Chen u8 _rsv;
3305ae130bb8SShayne Chen } __packed req = {
330666b181b8SRyder Lee .format_id = TX_POWER_LIMIT_INFO,
3307ae130bb8SShayne Chen .category = RATE_POWER_INFO,
33083eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
3309ae130bb8SShayne Chen };
331066b181b8SRyder Lee s8 txpower_sku[MT7915_SKU_RATE_NUM][2];
3311ae130bb8SShayne Chen struct sk_buff *skb;
3312ae130bb8SShayne Chen int ret, i;
3313ae130bb8SShayne Chen
3314ae130bb8SShayne Chen ret = mt76_mcu_send_and_get_msg(&dev->mt76,
3315ae130bb8SShayne Chen MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
3316ae130bb8SShayne Chen &req, sizeof(req), true, &skb);
3317ae130bb8SShayne Chen if (ret)
3318ae130bb8SShayne Chen return ret;
3319ae130bb8SShayne Chen
332066b181b8SRyder Lee memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku));
3321ae130bb8SShayne Chen for (i = 0; i < len; i++)
332266b181b8SRyder Lee txpower[i] = txpower_sku[i][req.band_idx];
3323ae130bb8SShayne Chen
3324ae130bb8SShayne Chen dev_kfree_skb(skb);
3325ae130bb8SShayne Chen
3326ae130bb8SShayne Chen return 0;
3327ae130bb8SShayne Chen }
3328ae130bb8SShayne Chen
mt7915_mcu_set_test_param(struct mt7915_dev * dev,u8 param,bool test_mode,u8 en)3329aadf0953SShayne Chen int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
3330aadf0953SShayne Chen u8 en)
3331aadf0953SShayne Chen {
3332aadf0953SShayne Chen struct {
3333aadf0953SShayne Chen u8 test_mode_en;
3334aadf0953SShayne Chen u8 param_idx;
3335aadf0953SShayne Chen u8 _rsv[2];
3336aadf0953SShayne Chen
3337aadf0953SShayne Chen u8 enable;
3338aadf0953SShayne Chen u8 _rsv2[3];
3339aadf0953SShayne Chen
3340aadf0953SShayne Chen u8 pad[8];
3341aadf0953SShayne Chen } __packed req = {
3342aadf0953SShayne Chen .test_mode_en = test_mode,
3343aadf0953SShayne Chen .param_idx = param,
3344aadf0953SShayne Chen .enable = en,
3345aadf0953SShayne Chen };
3346aadf0953SShayne Chen
3347c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req,
3348aadf0953SShayne Chen sizeof(req), false);
3349aadf0953SShayne Chen }
3350aadf0953SShayne Chen
mt7915_mcu_set_sku_en(struct mt7915_phy * phy,bool enable)3351f1d96236SRyder Lee int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
3352f1d96236SRyder Lee {
3353f1d96236SRyder Lee struct mt7915_dev *dev = phy->dev;
3354f1d96236SRyder Lee struct mt7915_sku {
3355f1d96236SRyder Lee u8 format_id;
3356f1d96236SRyder Lee u8 sku_enable;
33576f917bbaSRyder Lee u8 band_idx;
3358f1d96236SRyder Lee u8 rsv;
3359f1d96236SRyder Lee } __packed req = {
336066b181b8SRyder Lee .format_id = TX_POWER_LIMIT_ENABLE,
33613eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
3362f1d96236SRyder Lee .sku_enable = enable,
3363f1d96236SRyder Lee };
3364f1d96236SRyder Lee
3365cb5cdd4cSFelix Fietkau return mt76_mcu_send_msg(&dev->mt76,
3366c203dd62SFelix Fietkau MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
3367cb5cdd4cSFelix Fietkau sizeof(req), true);
3368f1d96236SRyder Lee }
3369f1d96236SRyder Lee
mt7915_mcu_set_ser(struct mt7915_dev * dev,u8 action,u8 set,u8 band)3370e57b7901SRyder Lee int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
3371e57b7901SRyder Lee {
3372e57b7901SRyder Lee struct {
3373e57b7901SRyder Lee u8 action;
3374e57b7901SRyder Lee u8 set;
3375e57b7901SRyder Lee u8 band;
3376e57b7901SRyder Lee u8 rsv;
3377e57b7901SRyder Lee } req = {
3378e57b7901SRyder Lee .action = action,
3379e57b7901SRyder Lee .set = set,
3380e57b7901SRyder Lee .band = band,
3381e57b7901SRyder Lee };
3382e57b7901SRyder Lee
3383c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER),
3384e57b7901SRyder Lee &req, sizeof(req), false);
3385e57b7901SRyder Lee }
338689029a85SRyder Lee
mt7915_mcu_set_txbf(struct mt7915_dev * dev,u8 action)3387fd843822SRyder Lee int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
338807c0d001SRyder Lee {
338907c0d001SRyder Lee struct {
339007c0d001SRyder Lee u8 action;
3391fd843822SRyder Lee union {
339289029a85SRyder Lee struct {
339389029a85SRyder Lee u8 snd_mode;
339489029a85SRyder Lee u8 sta_num;
339589029a85SRyder Lee u8 rsv;
339689029a85SRyder Lee u8 wlan_idx[4];
339789029a85SRyder Lee __le32 snd_period; /* ms */
3398fd843822SRyder Lee } __packed snd;
3399fd843822SRyder Lee struct {
3400fd843822SRyder Lee bool ebf;
3401fd843822SRyder Lee bool ibf;
3402fd843822SRyder Lee u8 rsv;
3403fd843822SRyder Lee } __packed type;
3404fd843822SRyder Lee struct {
3405fd843822SRyder Lee u8 bf_num;
3406fd843822SRyder Lee u8 bf_bitmap;
3407fd843822SRyder Lee u8 bf_sel[8];
3408fd843822SRyder Lee u8 rsv[5];
3409fd843822SRyder Lee } __packed mod;
341089029a85SRyder Lee };
3411fd843822SRyder Lee } __packed req = {
3412fd843822SRyder Lee .action = action,
3413fd843822SRyder Lee };
3414fd843822SRyder Lee
3415fd843822SRyder Lee #define MT_BF_PROCESSING 4
3416fd843822SRyder Lee switch (action) {
3417fd843822SRyder Lee case MT_BF_SOUNDING_ON:
3418fd843822SRyder Lee req.snd.snd_mode = MT_BF_PROCESSING;
3419fd843822SRyder Lee break;
3420fd843822SRyder Lee case MT_BF_TYPE_UPDATE:
3421fd843822SRyder Lee req.type.ebf = true;
3422fd843822SRyder Lee req.type.ibf = dev->ibf;
3423fd843822SRyder Lee break;
3424fd843822SRyder Lee case MT_BF_MODULE_UPDATE:
3425fd843822SRyder Lee req.mod.bf_num = 2;
3426fd843822SRyder Lee req.mod.bf_bitmap = GENMASK(1, 0);
3427fd843822SRyder Lee break;
3428fd843822SRyder Lee default:
3429fd843822SRyder Lee return -EINVAL;
3430fd843822SRyder Lee }
343189029a85SRyder Lee
3432c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
3433cb5cdd4cSFelix Fietkau sizeof(req), true);
343489029a85SRyder Lee }
343506acdd38SRyder Lee
34363dc00ecfSRyder Lee static int
mt7915_mcu_enable_obss_spr(struct mt7915_phy * phy,u8 action,u8 val)34373dc00ecfSRyder Lee mt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val)
343806acdd38SRyder Lee {
34393dc00ecfSRyder Lee struct mt7915_dev *dev = phy->dev;
34403dc00ecfSRyder Lee struct mt7915_mcu_sr_ctrl req = {
34413dc00ecfSRyder Lee .action = action,
34423dc00ecfSRyder Lee .argnum = 1,
34433eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
34443dc00ecfSRyder Lee .val = cpu_to_le32(val),
344506acdd38SRyder Lee };
344606acdd38SRyder Lee
3447c203dd62SFelix Fietkau return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
3448cb5cdd4cSFelix Fietkau sizeof(req), true);
344906acdd38SRyder Lee }
345011553d88SFelix Fietkau
34513dc00ecfSRyder Lee static int
mt7915_mcu_set_obss_spr_pd(struct mt7915_phy * phy,struct ieee80211_he_obss_pd * he_obss_pd)34523dc00ecfSRyder Lee mt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy,
34533dc00ecfSRyder Lee struct ieee80211_he_obss_pd *he_obss_pd)
34543dc00ecfSRyder Lee {
34553dc00ecfSRyder Lee struct mt7915_dev *dev = phy->dev;
34563dc00ecfSRyder Lee struct {
34573dc00ecfSRyder Lee struct mt7915_mcu_sr_ctrl ctrl;
34583dc00ecfSRyder Lee struct {
34593dc00ecfSRyder Lee u8 pd_th_non_srg;
34603dc00ecfSRyder Lee u8 pd_th_srg;
34613dc00ecfSRyder Lee u8 period_offs;
34623dc00ecfSRyder Lee u8 rcpi_src;
34633dc00ecfSRyder Lee __le16 obss_pd_min;
34643dc00ecfSRyder Lee __le16 obss_pd_min_srg;
34653dc00ecfSRyder Lee u8 resp_txpwr_mode;
34663dc00ecfSRyder Lee u8 txpwr_restrict_mode;
34673dc00ecfSRyder Lee u8 txpwr_ref;
34683dc00ecfSRyder Lee u8 rsv[3];
34693dc00ecfSRyder Lee } __packed param;
34703dc00ecfSRyder Lee } __packed req = {
34713dc00ecfSRyder Lee .ctrl = {
34723dc00ecfSRyder Lee .action = SPR_SET_PARAM,
34733dc00ecfSRyder Lee .argnum = 9,
34743eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
34753dc00ecfSRyder Lee },
34763dc00ecfSRyder Lee };
34773dc00ecfSRyder Lee int ret;
34783dc00ecfSRyder Lee u8 max_th = 82, non_srg_max_th = 62;
34793dc00ecfSRyder Lee
34803dc00ecfSRyder Lee /* disable firmware dynamical PD asjustment */
34813dc00ecfSRyder Lee ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false);
34823dc00ecfSRyder Lee if (ret)
34833dc00ecfSRyder Lee return ret;
34843dc00ecfSRyder Lee
34853dc00ecfSRyder Lee if (he_obss_pd->sr_ctrl &
34863dc00ecfSRyder Lee IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)
34873dc00ecfSRyder Lee req.param.pd_th_non_srg = max_th;
34883dc00ecfSRyder Lee else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
34893dc00ecfSRyder Lee req.param.pd_th_non_srg = max_th - he_obss_pd->non_srg_max_offset;
34903dc00ecfSRyder Lee else
34913dc00ecfSRyder Lee req.param.pd_th_non_srg = non_srg_max_th;
34923dc00ecfSRyder Lee
34933dc00ecfSRyder Lee if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
34943dc00ecfSRyder Lee req.param.pd_th_srg = max_th - he_obss_pd->max_offset;
34953dc00ecfSRyder Lee
34963dc00ecfSRyder Lee req.param.obss_pd_min = cpu_to_le16(82);
34973dc00ecfSRyder Lee req.param.obss_pd_min_srg = cpu_to_le16(82);
34983dc00ecfSRyder Lee req.param.txpwr_restrict_mode = 2;
34993dc00ecfSRyder Lee req.param.txpwr_ref = 21;
35003dc00ecfSRyder Lee
35013dc00ecfSRyder Lee return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35023dc00ecfSRyder Lee sizeof(req), true);
35033dc00ecfSRyder Lee }
35043dc00ecfSRyder Lee
35053dc00ecfSRyder Lee static int
mt7915_mcu_set_obss_spr_siga(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_he_obss_pd * he_obss_pd)35063dc00ecfSRyder Lee mt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif,
35073dc00ecfSRyder Lee struct ieee80211_he_obss_pd *he_obss_pd)
35083dc00ecfSRyder Lee {
35093dc00ecfSRyder Lee struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
35103dc00ecfSRyder Lee struct mt7915_dev *dev = phy->dev;
35113dc00ecfSRyder Lee u8 omac = mvif->mt76.omac_idx;
35123dc00ecfSRyder Lee struct {
35133dc00ecfSRyder Lee struct mt7915_mcu_sr_ctrl ctrl;
35143dc00ecfSRyder Lee struct {
35153dc00ecfSRyder Lee u8 omac;
35163dc00ecfSRyder Lee u8 rsv[3];
35173dc00ecfSRyder Lee u8 flag[20];
35183dc00ecfSRyder Lee } __packed siga;
35193dc00ecfSRyder Lee } __packed req = {
35203dc00ecfSRyder Lee .ctrl = {
35213dc00ecfSRyder Lee .action = SPR_SET_SIGA,
35223dc00ecfSRyder Lee .argnum = 1,
35233eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
35243dc00ecfSRyder Lee },
35253dc00ecfSRyder Lee .siga = {
35263dc00ecfSRyder Lee .omac = omac > HW_BSSID_MAX ? omac - 12 : omac,
35273dc00ecfSRyder Lee },
35283dc00ecfSRyder Lee };
35293dc00ecfSRyder Lee int ret;
35303dc00ecfSRyder Lee
35313dc00ecfSRyder Lee if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED)
35323dc00ecfSRyder Lee req.siga.flag[req.siga.omac] = 0xf;
35333dc00ecfSRyder Lee else
35343dc00ecfSRyder Lee return 0;
35353dc00ecfSRyder Lee
35363dc00ecfSRyder Lee /* switch to normal AP mode */
35373dc00ecfSRyder Lee ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0);
35383dc00ecfSRyder Lee if (ret)
35393dc00ecfSRyder Lee return ret;
35403dc00ecfSRyder Lee
35413dc00ecfSRyder Lee return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35423dc00ecfSRyder Lee sizeof(req), true);
35433dc00ecfSRyder Lee }
35443dc00ecfSRyder Lee
35453dc00ecfSRyder Lee static int
mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy * phy,struct ieee80211_he_obss_pd * he_obss_pd)35463dc00ecfSRyder Lee mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy,
35473dc00ecfSRyder Lee struct ieee80211_he_obss_pd *he_obss_pd)
35483dc00ecfSRyder Lee {
35493dc00ecfSRyder Lee struct mt7915_dev *dev = phy->dev;
35503dc00ecfSRyder Lee struct {
35513dc00ecfSRyder Lee struct mt7915_mcu_sr_ctrl ctrl;
35523dc00ecfSRyder Lee struct {
35533dc00ecfSRyder Lee __le32 color_l[2];
35543dc00ecfSRyder Lee __le32 color_h[2];
35553dc00ecfSRyder Lee __le32 bssid_l[2];
35563dc00ecfSRyder Lee __le32 bssid_h[2];
35573dc00ecfSRyder Lee } __packed bitmap;
35583dc00ecfSRyder Lee } __packed req = {
35593dc00ecfSRyder Lee .ctrl = {
35603dc00ecfSRyder Lee .action = SPR_SET_SRG_BITMAP,
35613dc00ecfSRyder Lee .argnum = 4,
35623eb50cc9SRyder Lee .band_idx = phy->mt76->band_idx,
35633dc00ecfSRyder Lee },
35643dc00ecfSRyder Lee };
35653dc00ecfSRyder Lee u32 bitmap;
35663dc00ecfSRyder Lee
35673dc00ecfSRyder Lee memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap));
35683dc00ecfSRyder Lee req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35693dc00ecfSRyder Lee
35703dc00ecfSRyder Lee memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap));
35713dc00ecfSRyder Lee req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35723dc00ecfSRyder Lee
35733dc00ecfSRyder Lee memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap));
35743dc00ecfSRyder Lee req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35753dc00ecfSRyder Lee
35763dc00ecfSRyder Lee memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap));
35773dc00ecfSRyder Lee req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35783dc00ecfSRyder Lee
35793dc00ecfSRyder Lee return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35803dc00ecfSRyder Lee sizeof(req), true);
35813dc00ecfSRyder Lee }
35823dc00ecfSRyder Lee
mt7915_mcu_add_obss_spr(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_he_obss_pd * he_obss_pd)35833dc00ecfSRyder Lee int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
35843dc00ecfSRyder Lee struct ieee80211_he_obss_pd *he_obss_pd)
35853dc00ecfSRyder Lee {
35863dc00ecfSRyder Lee int ret;
35873dc00ecfSRyder Lee
35883dc00ecfSRyder Lee /* enable firmware scene detection algorithms */
35893dc00ecfSRyder Lee ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect);
35903dc00ecfSRyder Lee if (ret)
35913dc00ecfSRyder Lee return ret;
35923dc00ecfSRyder Lee
35933dc00ecfSRyder Lee /* firmware dynamically adjusts PD threshold so skip manual control */
35943dc00ecfSRyder Lee if (sr_scene_detect && !he_obss_pd->enable)
35953dc00ecfSRyder Lee return 0;
35963dc00ecfSRyder Lee
35973dc00ecfSRyder Lee /* enable spatial reuse */
35983dc00ecfSRyder Lee ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable);
35993dc00ecfSRyder Lee if (ret)
36003dc00ecfSRyder Lee return ret;
36013dc00ecfSRyder Lee
36023dc00ecfSRyder Lee if (sr_scene_detect || !he_obss_pd->enable)
36033dc00ecfSRyder Lee return 0;
36043dc00ecfSRyder Lee
36053dc00ecfSRyder Lee ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true);
36063dc00ecfSRyder Lee if (ret)
36073dc00ecfSRyder Lee return ret;
36083dc00ecfSRyder Lee
36093dc00ecfSRyder Lee /* set SRG/non-SRG OBSS PD threshold */
36103dc00ecfSRyder Lee ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd);
36113dc00ecfSRyder Lee if (ret)
36123dc00ecfSRyder Lee return ret;
36133dc00ecfSRyder Lee
36143dc00ecfSRyder Lee /* Set SR prohibit */
36153dc00ecfSRyder Lee ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd);
36163dc00ecfSRyder Lee if (ret)
36173dc00ecfSRyder Lee return ret;
36183dc00ecfSRyder Lee
36193dc00ecfSRyder Lee /* set SRG BSS color/BSSID bitmap */
36203dc00ecfSRyder Lee return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd);
36213dc00ecfSRyder Lee }
36223dc00ecfSRyder Lee
mt7915_mcu_get_rx_rate(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct rate_info * rate)362311553d88SFelix Fietkau int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
362411553d88SFelix Fietkau struct ieee80211_sta *sta, struct rate_info *rate)
362511553d88SFelix Fietkau {
362611553d88SFelix Fietkau struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
362711553d88SFelix Fietkau struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
362811553d88SFelix Fietkau struct mt7915_dev *dev = phy->dev;
362911553d88SFelix Fietkau struct mt76_phy *mphy = phy->mt76;
363011553d88SFelix Fietkau struct {
363111553d88SFelix Fietkau u8 category;
363211553d88SFelix Fietkau u8 band;
363311553d88SFelix Fietkau __le16 wcid;
363411553d88SFelix Fietkau } __packed req = {
363511553d88SFelix Fietkau .category = MCU_PHY_STATE_CONTENTION_RX_RATE,
36366cf4392fSLorenzo Bianconi .band = mvif->mt76.band_idx,
363711553d88SFelix Fietkau .wcid = cpu_to_le16(msta->wcid.idx),
363811553d88SFelix Fietkau };
363911553d88SFelix Fietkau struct ieee80211_supported_band *sband;
364011553d88SFelix Fietkau struct mt7915_mcu_phy_rx_info *res;
364111553d88SFelix Fietkau struct sk_buff *skb;
364211553d88SFelix Fietkau int ret;
36437883906dSRyder Lee bool cck = false;
364411553d88SFelix Fietkau
3645c203dd62SFelix Fietkau ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO),
364611553d88SFelix Fietkau &req, sizeof(req), true, &skb);
364711553d88SFelix Fietkau if (ret)
364811553d88SFelix Fietkau return ret;
364911553d88SFelix Fietkau
365011553d88SFelix Fietkau res = (struct mt7915_mcu_phy_rx_info *)skb->data;
365111553d88SFelix Fietkau
365211553d88SFelix Fietkau rate->mcs = res->rate;
365311553d88SFelix Fietkau rate->nss = res->nsts + 1;
365411553d88SFelix Fietkau
365511553d88SFelix Fietkau switch (res->mode) {
365611553d88SFelix Fietkau case MT_PHY_TYPE_CCK:
36577883906dSRyder Lee cck = true;
36587883906dSRyder Lee fallthrough;
365911553d88SFelix Fietkau case MT_PHY_TYPE_OFDM:
366011553d88SFelix Fietkau if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
366111553d88SFelix Fietkau sband = &mphy->sband_5g.sband;
3662b4d093e3SMeiChia Chiu else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
3663b4d093e3SMeiChia Chiu sband = &mphy->sband_6g.sband;
366411553d88SFelix Fietkau else
366511553d88SFelix Fietkau sband = &mphy->sband_2g.sband;
366611553d88SFelix Fietkau
36677883906dSRyder Lee rate->mcs = mt76_get_rate(&dev->mt76, sband, rate->mcs, cck);
36687883906dSRyder Lee rate->legacy = sband->bitrates[rate->mcs].bitrate;
366911553d88SFelix Fietkau break;
367011553d88SFelix Fietkau case MT_PHY_TYPE_HT:
367111553d88SFelix Fietkau case MT_PHY_TYPE_HT_GF:
36727883906dSRyder Lee if (rate->mcs > 31) {
36737883906dSRyder Lee ret = -EINVAL;
36747883906dSRyder Lee goto out;
36757883906dSRyder Lee }
3676bacf5047SShayne Chen
36777883906dSRyder Lee rate->flags = RATE_INFO_FLAGS_MCS;
367811553d88SFelix Fietkau if (res->gi)
36797883906dSRyder Lee rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
368011553d88SFelix Fietkau break;
368111553d88SFelix Fietkau case MT_PHY_TYPE_VHT:
36827883906dSRyder Lee if (rate->mcs > 9) {
36837883906dSRyder Lee ret = -EINVAL;
36847883906dSRyder Lee goto out;
36857883906dSRyder Lee }
368611553d88SFelix Fietkau
36877883906dSRyder Lee rate->flags = RATE_INFO_FLAGS_VHT_MCS;
368811553d88SFelix Fietkau if (res->gi)
36897883906dSRyder Lee rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
369011553d88SFelix Fietkau break;
369111553d88SFelix Fietkau case MT_PHY_TYPE_HE_SU:
369211553d88SFelix Fietkau case MT_PHY_TYPE_HE_EXT_SU:
369311553d88SFelix Fietkau case MT_PHY_TYPE_HE_TB:
369411553d88SFelix Fietkau case MT_PHY_TYPE_HE_MU:
36957883906dSRyder Lee if (res->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) {
36967883906dSRyder Lee ret = -EINVAL;
36977883906dSRyder Lee goto out;
36987883906dSRyder Lee }
369911553d88SFelix Fietkau rate->he_gi = res->gi;
37007883906dSRyder Lee rate->flags = RATE_INFO_FLAGS_HE_MCS;
370111553d88SFelix Fietkau break;
370211553d88SFelix Fietkau default:
37037883906dSRyder Lee ret = -EINVAL;
37047883906dSRyder Lee goto out;
370511553d88SFelix Fietkau }
370611553d88SFelix Fietkau
370711553d88SFelix Fietkau switch (res->bw) {
370811553d88SFelix Fietkau case IEEE80211_STA_RX_BW_160:
370911553d88SFelix Fietkau rate->bw = RATE_INFO_BW_160;
371011553d88SFelix Fietkau break;
371111553d88SFelix Fietkau case IEEE80211_STA_RX_BW_80:
371211553d88SFelix Fietkau rate->bw = RATE_INFO_BW_80;
371311553d88SFelix Fietkau break;
371411553d88SFelix Fietkau case IEEE80211_STA_RX_BW_40:
371511553d88SFelix Fietkau rate->bw = RATE_INFO_BW_40;
371611553d88SFelix Fietkau break;
371711553d88SFelix Fietkau default:
371811553d88SFelix Fietkau rate->bw = RATE_INFO_BW_20;
371911553d88SFelix Fietkau break;
372011553d88SFelix Fietkau }
372111553d88SFelix Fietkau
37227883906dSRyder Lee out:
3723d211c003SShayne Chen dev_kfree_skb(skb);
3724d211c003SShayne Chen
37257883906dSRyder Lee return ret;
372611553d88SFelix Fietkau }
3727b4b9f0a3SLorenzo Bianconi
mt7915_mcu_update_bss_color(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct cfg80211_he_bss_color * he_bss_color)3728b4b9f0a3SLorenzo Bianconi int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
3729b4b9f0a3SLorenzo Bianconi struct cfg80211_he_bss_color *he_bss_color)
3730b4b9f0a3SLorenzo Bianconi {
3731b4b9f0a3SLorenzo Bianconi int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color);
3732b4b9f0a3SLorenzo Bianconi struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
3733b4b9f0a3SLorenzo Bianconi struct bss_info_color *bss_color;
3734b4b9f0a3SLorenzo Bianconi struct sk_buff *skb;
3735b4b9f0a3SLorenzo Bianconi struct tlv *tlv;
3736b4b9f0a3SLorenzo Bianconi
3737e2c93b68SLorenzo Bianconi skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
3738e2c93b68SLorenzo Bianconi NULL, len);
3739b4b9f0a3SLorenzo Bianconi if (IS_ERR(skb))
3740b4b9f0a3SLorenzo Bianconi return PTR_ERR(skb);
3741b4b9f0a3SLorenzo Bianconi
3742069c8e34SLorenzo Bianconi tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR,
3743069c8e34SLorenzo Bianconi sizeof(*bss_color));
3744b4b9f0a3SLorenzo Bianconi bss_color = (struct bss_info_color *)tlv;
3745b4b9f0a3SLorenzo Bianconi bss_color->disable = !he_bss_color->enabled;
3746b4b9f0a3SLorenzo Bianconi bss_color->color = he_bss_color->color;
3747b4b9f0a3SLorenzo Bianconi
3748b4b9f0a3SLorenzo Bianconi return mt76_mcu_skb_send_msg(&dev->mt76, skb,
3749b4b9f0a3SLorenzo Bianconi MCU_EXT_CMD(BSS_INFO_UPDATE), true);
3750b4b9f0a3SLorenzo Bianconi }
3751179090a5SLorenzo Bianconi
3752179090a5SLorenzo Bianconi #define TWT_AGRT_TRIGGER BIT(0)
3753179090a5SLorenzo Bianconi #define TWT_AGRT_ANNOUNCE BIT(1)
3754179090a5SLorenzo Bianconi #define TWT_AGRT_PROTECT BIT(2)
3755179090a5SLorenzo Bianconi
mt7915_mcu_twt_agrt_update(struct mt7915_dev * dev,struct mt7915_vif * mvif,struct mt7915_twt_flow * flow,int cmd)3756179090a5SLorenzo Bianconi int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
3757179090a5SLorenzo Bianconi struct mt7915_vif *mvif,
3758179090a5SLorenzo Bianconi struct mt7915_twt_flow *flow,
3759179090a5SLorenzo Bianconi int cmd)
3760179090a5SLorenzo Bianconi {
3761179090a5SLorenzo Bianconi struct {
3762179090a5SLorenzo Bianconi u8 tbl_idx;
3763179090a5SLorenzo Bianconi u8 cmd;
3764179090a5SLorenzo Bianconi u8 own_mac_idx;
3765179090a5SLorenzo Bianconi u8 flowid; /* 0xff for group id */
3766179090a5SLorenzo Bianconi __le16 peer_id; /* specify the peer_id (msb=0)
3767179090a5SLorenzo Bianconi * or group_id (msb=1)
3768179090a5SLorenzo Bianconi */
3769179090a5SLorenzo Bianconi u8 duration; /* 256 us */
3770179090a5SLorenzo Bianconi u8 bss_idx;
3771179090a5SLorenzo Bianconi __le64 start_tsf;
3772179090a5SLorenzo Bianconi __le16 mantissa;
3773179090a5SLorenzo Bianconi u8 exponent;
3774179090a5SLorenzo Bianconi u8 is_ap;
3775179090a5SLorenzo Bianconi u8 agrt_params;
3776179090a5SLorenzo Bianconi u8 rsv[23];
3777179090a5SLorenzo Bianconi } __packed req = {
3778179090a5SLorenzo Bianconi .tbl_idx = flow->table_id,
3779179090a5SLorenzo Bianconi .cmd = cmd,
37806cf4392fSLorenzo Bianconi .own_mac_idx = mvif->mt76.omac_idx,
3781179090a5SLorenzo Bianconi .flowid = flow->id,
3782179090a5SLorenzo Bianconi .peer_id = cpu_to_le16(flow->wcid),
3783179090a5SLorenzo Bianconi .duration = flow->duration,
37846cf4392fSLorenzo Bianconi .bss_idx = mvif->mt76.idx,
3785179090a5SLorenzo Bianconi .start_tsf = cpu_to_le64(flow->tsf),
3786179090a5SLorenzo Bianconi .mantissa = flow->mantissa,
3787179090a5SLorenzo Bianconi .exponent = flow->exp,
3788179090a5SLorenzo Bianconi .is_ap = true,
3789179090a5SLorenzo Bianconi };
3790179090a5SLorenzo Bianconi
3791179090a5SLorenzo Bianconi if (flow->protection)
3792179090a5SLorenzo Bianconi req.agrt_params |= TWT_AGRT_PROTECT;
3793179090a5SLorenzo Bianconi if (!flow->flowtype)
3794179090a5SLorenzo Bianconi req.agrt_params |= TWT_AGRT_ANNOUNCE;
3795179090a5SLorenzo Bianconi if (flow->trigger)
3796179090a5SLorenzo Bianconi req.agrt_params |= TWT_AGRT_TRIGGER;
3797179090a5SLorenzo Bianconi
3798179090a5SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE),
3799179090a5SLorenzo Bianconi &req, sizeof(req), true);
3800179090a5SLorenzo Bianconi }
38010a17329aSShayne Chen
mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev * dev,u16 wlan_idx)3802161a7528SPeter Chiu int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
3803161a7528SPeter Chiu {
3804161a7528SPeter Chiu struct {
3805161a7528SPeter Chiu __le32 cmd;
3806161a7528SPeter Chiu __le32 num;
3807161a7528SPeter Chiu __le32 __rsv;
3808161a7528SPeter Chiu __le16 wlan_idx;
3809161a7528SPeter Chiu } req = {
3810161a7528SPeter Chiu .cmd = cpu_to_le32(0x15),
3811161a7528SPeter Chiu .num = cpu_to_le32(1),
3812161a7528SPeter Chiu .wlan_idx = cpu_to_le16(wlan_idx),
3813161a7528SPeter Chiu };
3814161a7528SPeter Chiu struct mt7915_mcu_wa_tx_stat {
3815161a7528SPeter Chiu __le16 wlan_idx;
3816161a7528SPeter Chiu u8 __rsv[2];
3817161a7528SPeter Chiu
3818161a7528SPeter Chiu /* tx_bytes is deprecated since WA byte counter uses u32,
3819161a7528SPeter Chiu * which easily leads to overflow.
3820161a7528SPeter Chiu */
3821161a7528SPeter Chiu __le32 tx_bytes;
3822161a7528SPeter Chiu __le32 tx_packets;
3823161a7528SPeter Chiu } *res;
3824161a7528SPeter Chiu struct mt76_wcid *wcid;
3825161a7528SPeter Chiu struct sk_buff *skb;
3826161a7528SPeter Chiu int ret;
3827161a7528SPeter Chiu
3828161a7528SPeter Chiu ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY),
3829161a7528SPeter Chiu &req, sizeof(req), true, &skb);
3830161a7528SPeter Chiu if (ret)
3831161a7528SPeter Chiu return ret;
3832161a7528SPeter Chiu
3833161a7528SPeter Chiu if (!is_mt7915(&dev->mt76))
3834161a7528SPeter Chiu skb_pull(skb, 4);
3835161a7528SPeter Chiu
3836161a7528SPeter Chiu res = (struct mt7915_mcu_wa_tx_stat *)skb->data;
3837161a7528SPeter Chiu
3838161a7528SPeter Chiu if (le16_to_cpu(res->wlan_idx) != wlan_idx) {
3839161a7528SPeter Chiu ret = -EINVAL;
3840161a7528SPeter Chiu goto out;
3841161a7528SPeter Chiu }
3842161a7528SPeter Chiu
3843161a7528SPeter Chiu rcu_read_lock();
3844161a7528SPeter Chiu
3845161a7528SPeter Chiu wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
3846161a7528SPeter Chiu if (wcid)
3847161a7528SPeter Chiu wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
3848161a7528SPeter Chiu else
3849161a7528SPeter Chiu ret = -EINVAL;
3850161a7528SPeter Chiu
3851161a7528SPeter Chiu rcu_read_unlock();
3852161a7528SPeter Chiu out:
3853161a7528SPeter Chiu dev_kfree_skb(skb);
3854161a7528SPeter Chiu
3855161a7528SPeter Chiu return ret;
3856161a7528SPeter Chiu }
3857161a7528SPeter Chiu
mt7915_mcu_rf_regval(struct mt7915_dev * dev,u32 regidx,u32 * val,bool set)38580a17329aSShayne Chen int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
38590a17329aSShayne Chen {
38600a17329aSShayne Chen struct {
38610a17329aSShayne Chen __le32 idx;
38620a17329aSShayne Chen __le32 ofs;
38630a17329aSShayne Chen __le32 data;
38640a17329aSShayne Chen } __packed req = {
38657624ffcdSEvelyn Tsai .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))),
38667624ffcdSEvelyn Tsai .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))),
38670a17329aSShayne Chen .data = set ? cpu_to_le32(*val) : 0,
38680a17329aSShayne Chen };
38690a17329aSShayne Chen struct sk_buff *skb;
38700a17329aSShayne Chen int ret;
38710a17329aSShayne Chen
38720a17329aSShayne Chen if (set)
38730a17329aSShayne Chen return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
38740a17329aSShayne Chen &req, sizeof(req), false);
38750a17329aSShayne Chen
38760a17329aSShayne Chen ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
38770a17329aSShayne Chen &req, sizeof(req), true, &skb);
38780a17329aSShayne Chen if (ret)
38790a17329aSShayne Chen return ret;
38800a17329aSShayne Chen
38810a17329aSShayne Chen *val = le32_to_cpu(*(__le32 *)(skb->data + 8));
38820a17329aSShayne Chen dev_kfree_skb(skb);
38830a17329aSShayne Chen
38840a17329aSShayne Chen return 0;
38850a17329aSShayne Chen }
3886