1*6c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC 2*6c92544dSBjoern A. Zeeb /* Copyright (C) 2020 MediaTek Inc. */ 3*6c92544dSBjoern A. Zeeb 4*6c92544dSBjoern A. Zeeb #include <linux/fs.h> 5*6c92544dSBjoern A. Zeeb #include "mt7915.h" 6*6c92544dSBjoern A. Zeeb #include "mcu.h" 7*6c92544dSBjoern A. Zeeb #include "mac.h" 8*6c92544dSBjoern A. Zeeb #include "eeprom.h" 9*6c92544dSBjoern A. Zeeb 10*6c92544dSBjoern A. Zeeb #define fw_name(_dev, name, ...) ({ \ 11*6c92544dSBjoern A. Zeeb char *_fw; \ 12*6c92544dSBjoern A. Zeeb switch (mt76_chip(&(_dev)->mt76)) { \ 13*6c92544dSBjoern A. Zeeb case 0x7915: \ 14*6c92544dSBjoern A. Zeeb _fw = MT7915_##name; \ 15*6c92544dSBjoern A. Zeeb break; \ 16*6c92544dSBjoern A. Zeeb case 0x7986: \ 17*6c92544dSBjoern A. Zeeb _fw = MT7986_##name##__VA_ARGS__; \ 18*6c92544dSBjoern A. Zeeb break; \ 19*6c92544dSBjoern A. Zeeb default: \ 20*6c92544dSBjoern A. Zeeb _fw = MT7916_##name; \ 21*6c92544dSBjoern A. Zeeb break; \ 22*6c92544dSBjoern A. Zeeb } \ 23*6c92544dSBjoern A. Zeeb _fw; \ 24*6c92544dSBjoern A. Zeeb }) 25*6c92544dSBjoern A. Zeeb 26*6c92544dSBjoern A. Zeeb #define fw_name_var(_dev, name) (mt7915_check_adie(dev, false) ? \ 27*6c92544dSBjoern A. Zeeb fw_name(_dev, name) : \ 28*6c92544dSBjoern A. Zeeb fw_name(_dev, name, _MT7975)) 29*6c92544dSBjoern A. Zeeb 30*6c92544dSBjoern A. Zeeb #define MCU_PATCH_ADDRESS 0x200000 31*6c92544dSBjoern A. Zeeb 32*6c92544dSBjoern A. Zeeb #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) 33*6c92544dSBjoern A. Zeeb #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) 34*6c92544dSBjoern A. Zeeb 35*6c92544dSBjoern A. Zeeb static u8 36*6c92544dSBjoern A. Zeeb mt7915_mcu_get_sta_nss(u16 mcs_map) 37*6c92544dSBjoern A. Zeeb { 38*6c92544dSBjoern A. Zeeb u8 nss; 39*6c92544dSBjoern A. Zeeb 40*6c92544dSBjoern A. Zeeb for (nss = 8; nss > 0; nss--) { 41*6c92544dSBjoern A. Zeeb u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3; 42*6c92544dSBjoern A. Zeeb 43*6c92544dSBjoern A. Zeeb if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) 44*6c92544dSBjoern A. Zeeb break; 45*6c92544dSBjoern A. Zeeb } 46*6c92544dSBjoern A. Zeeb 47*6c92544dSBjoern A. Zeeb return nss - 1; 48*6c92544dSBjoern A. Zeeb } 49*6c92544dSBjoern A. Zeeb 50*6c92544dSBjoern A. Zeeb static void 51*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, 52*6c92544dSBjoern A. Zeeb u16 mcs_map) 53*6c92544dSBjoern A. Zeeb { 54*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 55*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = msta->vif->phy->dev; 56*6c92544dSBjoern A. Zeeb enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; 57*6c92544dSBjoern A. Zeeb const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs; 58*6c92544dSBjoern A. Zeeb int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; 59*6c92544dSBjoern A. Zeeb 60*6c92544dSBjoern A. Zeeb for (nss = 0; nss < max_nss; nss++) { 61*6c92544dSBjoern A. Zeeb int mcs; 62*6c92544dSBjoern A. Zeeb 63*6c92544dSBjoern A. Zeeb switch ((mcs_map >> (2 * nss)) & 0x3) { 64*6c92544dSBjoern A. Zeeb case IEEE80211_HE_MCS_SUPPORT_0_11: 65*6c92544dSBjoern A. Zeeb mcs = GENMASK(11, 0); 66*6c92544dSBjoern A. Zeeb break; 67*6c92544dSBjoern A. Zeeb case IEEE80211_HE_MCS_SUPPORT_0_9: 68*6c92544dSBjoern A. Zeeb mcs = GENMASK(9, 0); 69*6c92544dSBjoern A. Zeeb break; 70*6c92544dSBjoern A. Zeeb case IEEE80211_HE_MCS_SUPPORT_0_7: 71*6c92544dSBjoern A. Zeeb mcs = GENMASK(7, 0); 72*6c92544dSBjoern A. Zeeb break; 73*6c92544dSBjoern A. Zeeb default: 74*6c92544dSBjoern A. Zeeb mcs = 0; 75*6c92544dSBjoern A. Zeeb } 76*6c92544dSBjoern A. Zeeb 77*6c92544dSBjoern A. Zeeb mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1; 78*6c92544dSBjoern A. Zeeb 79*6c92544dSBjoern A. Zeeb switch (mcs) { 80*6c92544dSBjoern A. Zeeb case 0 ... 7: 81*6c92544dSBjoern A. Zeeb mcs = IEEE80211_HE_MCS_SUPPORT_0_7; 82*6c92544dSBjoern A. Zeeb break; 83*6c92544dSBjoern A. Zeeb case 8 ... 9: 84*6c92544dSBjoern A. Zeeb mcs = IEEE80211_HE_MCS_SUPPORT_0_9; 85*6c92544dSBjoern A. Zeeb break; 86*6c92544dSBjoern A. Zeeb case 10 ... 11: 87*6c92544dSBjoern A. Zeeb mcs = IEEE80211_HE_MCS_SUPPORT_0_11; 88*6c92544dSBjoern A. Zeeb break; 89*6c92544dSBjoern A. Zeeb default: 90*6c92544dSBjoern A. Zeeb mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; 91*6c92544dSBjoern A. Zeeb break; 92*6c92544dSBjoern A. Zeeb } 93*6c92544dSBjoern A. Zeeb mcs_map &= ~(0x3 << (nss * 2)); 94*6c92544dSBjoern A. Zeeb mcs_map |= mcs << (nss * 2); 95*6c92544dSBjoern A. Zeeb 96*6c92544dSBjoern A. Zeeb /* only support 2ss on 160MHz for mt7915 */ 97*6c92544dSBjoern A. Zeeb if (is_mt7915(&dev->mt76) && nss > 1 && 98*6c92544dSBjoern A. Zeeb sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) 99*6c92544dSBjoern A. Zeeb break; 100*6c92544dSBjoern A. Zeeb } 101*6c92544dSBjoern A. Zeeb 102*6c92544dSBjoern A. Zeeb *he_mcs = cpu_to_le16(mcs_map); 103*6c92544dSBjoern A. Zeeb } 104*6c92544dSBjoern A. Zeeb 105*6c92544dSBjoern A. Zeeb static void 106*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs, 107*6c92544dSBjoern A. Zeeb const u16 *mask) 108*6c92544dSBjoern A. Zeeb { 109*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 110*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = msta->vif->phy->dev; 111*6c92544dSBjoern A. Zeeb u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); 112*6c92544dSBjoern A. Zeeb int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; 113*6c92544dSBjoern A. Zeeb u16 mcs; 114*6c92544dSBjoern A. Zeeb 115*6c92544dSBjoern A. Zeeb for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) { 116*6c92544dSBjoern A. Zeeb switch (mcs_map & 0x3) { 117*6c92544dSBjoern A. Zeeb case IEEE80211_VHT_MCS_SUPPORT_0_9: 118*6c92544dSBjoern A. Zeeb mcs = GENMASK(9, 0); 119*6c92544dSBjoern A. Zeeb break; 120*6c92544dSBjoern A. Zeeb case IEEE80211_VHT_MCS_SUPPORT_0_8: 121*6c92544dSBjoern A. Zeeb mcs = GENMASK(8, 0); 122*6c92544dSBjoern A. Zeeb break; 123*6c92544dSBjoern A. Zeeb case IEEE80211_VHT_MCS_SUPPORT_0_7: 124*6c92544dSBjoern A. Zeeb mcs = GENMASK(7, 0); 125*6c92544dSBjoern A. Zeeb break; 126*6c92544dSBjoern A. Zeeb default: 127*6c92544dSBjoern A. Zeeb mcs = 0; 128*6c92544dSBjoern A. Zeeb } 129*6c92544dSBjoern A. Zeeb 130*6c92544dSBjoern A. Zeeb vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]); 131*6c92544dSBjoern A. Zeeb 132*6c92544dSBjoern A. Zeeb /* only support 2ss on 160MHz for mt7915 */ 133*6c92544dSBjoern A. Zeeb if (is_mt7915(&dev->mt76) && nss > 1 && 134*6c92544dSBjoern A. Zeeb sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) 135*6c92544dSBjoern A. Zeeb break; 136*6c92544dSBjoern A. Zeeb } 137*6c92544dSBjoern A. Zeeb } 138*6c92544dSBjoern A. Zeeb 139*6c92544dSBjoern A. Zeeb static void 140*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs, 141*6c92544dSBjoern A. Zeeb const u8 *mask) 142*6c92544dSBjoern A. Zeeb { 143*6c92544dSBjoern A. Zeeb int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; 144*6c92544dSBjoern A. Zeeb 145*6c92544dSBjoern A. Zeeb for (nss = 0; nss < max_nss; nss++) 146*6c92544dSBjoern A. Zeeb ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss]; 147*6c92544dSBjoern A. Zeeb } 148*6c92544dSBjoern A. Zeeb 149*6c92544dSBjoern A. Zeeb static int 150*6c92544dSBjoern A. Zeeb mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, 151*6c92544dSBjoern A. Zeeb struct sk_buff *skb, int seq) 152*6c92544dSBjoern A. Zeeb { 153*6c92544dSBjoern A. Zeeb struct mt76_connac2_mcu_rxd *rxd; 154*6c92544dSBjoern A. Zeeb int ret = 0; 155*6c92544dSBjoern A. Zeeb 156*6c92544dSBjoern A. Zeeb if (!skb) { 157*6c92544dSBjoern A. Zeeb dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", 158*6c92544dSBjoern A. Zeeb cmd, seq); 159*6c92544dSBjoern A. Zeeb return -ETIMEDOUT; 160*6c92544dSBjoern A. Zeeb } 161*6c92544dSBjoern A. Zeeb 162*6c92544dSBjoern A. Zeeb rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 163*6c92544dSBjoern A. Zeeb if (seq != rxd->seq) 164*6c92544dSBjoern A. Zeeb return -EAGAIN; 165*6c92544dSBjoern A. Zeeb 166*6c92544dSBjoern A. Zeeb if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { 167*6c92544dSBjoern A. Zeeb skb_pull(skb, sizeof(*rxd) - 4); 168*6c92544dSBjoern A. Zeeb ret = *skb->data; 169*6c92544dSBjoern A. Zeeb } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { 170*6c92544dSBjoern A. Zeeb skb_pull(skb, sizeof(*rxd) + 4); 171*6c92544dSBjoern A. Zeeb ret = le32_to_cpu(*(__le32 *)skb->data); 172*6c92544dSBjoern A. Zeeb } else { 173*6c92544dSBjoern A. Zeeb skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); 174*6c92544dSBjoern A. Zeeb } 175*6c92544dSBjoern A. Zeeb 176*6c92544dSBjoern A. Zeeb return ret; 177*6c92544dSBjoern A. Zeeb } 178*6c92544dSBjoern A. Zeeb 179*6c92544dSBjoern A. Zeeb static int 180*6c92544dSBjoern A. Zeeb mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 181*6c92544dSBjoern A. Zeeb int cmd, int *wait_seq) 182*6c92544dSBjoern A. Zeeb { 183*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 184*6c92544dSBjoern A. Zeeb enum mt76_mcuq_id qid; 185*6c92544dSBjoern A. Zeeb int ret; 186*6c92544dSBjoern A. Zeeb 187*6c92544dSBjoern A. Zeeb ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, wait_seq); 188*6c92544dSBjoern A. Zeeb if (ret) 189*6c92544dSBjoern A. Zeeb return ret; 190*6c92544dSBjoern A. Zeeb 191*6c92544dSBjoern A. Zeeb if (cmd == MCU_CMD(FW_SCATTER)) 192*6c92544dSBjoern A. Zeeb qid = MT_MCUQ_FWDL; 193*6c92544dSBjoern A. Zeeb else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) 194*6c92544dSBjoern A. Zeeb qid = MT_MCUQ_WA; 195*6c92544dSBjoern A. Zeeb else 196*6c92544dSBjoern A. Zeeb qid = MT_MCUQ_WM; 197*6c92544dSBjoern A. Zeeb 198*6c92544dSBjoern A. Zeeb return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0); 199*6c92544dSBjoern A. Zeeb } 200*6c92544dSBjoern A. Zeeb 201*6c92544dSBjoern A. Zeeb int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) 202*6c92544dSBjoern A. Zeeb { 203*6c92544dSBjoern A. Zeeb struct { 204*6c92544dSBjoern A. Zeeb __le32 args[3]; 205*6c92544dSBjoern A. Zeeb } req = { 206*6c92544dSBjoern A. Zeeb .args = { 207*6c92544dSBjoern A. Zeeb cpu_to_le32(a1), 208*6c92544dSBjoern A. Zeeb cpu_to_le32(a2), 209*6c92544dSBjoern A. Zeeb cpu_to_le32(a3), 210*6c92544dSBjoern A. Zeeb }, 211*6c92544dSBjoern A. Zeeb }; 212*6c92544dSBjoern A. Zeeb 213*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false); 214*6c92544dSBjoern A. Zeeb } 215*6c92544dSBjoern A. Zeeb 216*6c92544dSBjoern A. Zeeb static void 217*6c92544dSBjoern A. Zeeb mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 218*6c92544dSBjoern A. Zeeb { 219*6c92544dSBjoern A. Zeeb if (vif->bss_conf.csa_active) 220*6c92544dSBjoern A. Zeeb ieee80211_csa_finish(vif); 221*6c92544dSBjoern A. Zeeb } 222*6c92544dSBjoern A. Zeeb 223*6c92544dSBjoern A. Zeeb static void 224*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) 225*6c92544dSBjoern A. Zeeb { 226*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = &dev->mt76.phy; 227*6c92544dSBjoern A. Zeeb struct mt7915_mcu_csa_notify *c; 228*6c92544dSBjoern A. Zeeb 229*6c92544dSBjoern A. Zeeb c = (struct mt7915_mcu_csa_notify *)skb->data; 230*6c92544dSBjoern A. Zeeb 231*6c92544dSBjoern A. Zeeb if ((c->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) 232*6c92544dSBjoern A. Zeeb mphy = dev->mt76.phys[MT_BAND1]; 233*6c92544dSBjoern A. Zeeb 234*6c92544dSBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(mphy->hw, 235*6c92544dSBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL, 236*6c92544dSBjoern A. Zeeb mt7915_mcu_csa_finish, mphy->hw); 237*6c92544dSBjoern A. Zeeb } 238*6c92544dSBjoern A. Zeeb 239*6c92544dSBjoern A. Zeeb static void 240*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) 241*6c92544dSBjoern A. Zeeb { 242*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = &dev->mt76.phy; 243*6c92544dSBjoern A. Zeeb struct mt7915_mcu_thermal_notify *t; 244*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy; 245*6c92544dSBjoern A. Zeeb 246*6c92544dSBjoern A. Zeeb t = (struct mt7915_mcu_thermal_notify *)skb->data; 247*6c92544dSBjoern A. Zeeb if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) 248*6c92544dSBjoern A. Zeeb return; 249*6c92544dSBjoern A. Zeeb 250*6c92544dSBjoern A. Zeeb if ((t->ctrl.band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) 251*6c92544dSBjoern A. Zeeb mphy = dev->mt76.phys[MT_BAND1]; 252*6c92544dSBjoern A. Zeeb 253*6c92544dSBjoern A. Zeeb phy = (struct mt7915_phy *)mphy->priv; 254*6c92544dSBjoern A. Zeeb phy->throttle_state = t->ctrl.duty.duty_cycle; 255*6c92544dSBjoern A. Zeeb } 256*6c92544dSBjoern A. Zeeb 257*6c92544dSBjoern A. Zeeb static void 258*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) 259*6c92544dSBjoern A. Zeeb { 260*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = &dev->mt76.phy; 261*6c92544dSBjoern A. Zeeb struct mt7915_mcu_rdd_report *r; 262*6c92544dSBjoern A. Zeeb 263*6c92544dSBjoern A. Zeeb r = (struct mt7915_mcu_rdd_report *)skb->data; 264*6c92544dSBjoern A. Zeeb 265*6c92544dSBjoern A. Zeeb if ((r->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) 266*6c92544dSBjoern A. Zeeb mphy = dev->mt76.phys[MT_BAND1]; 267*6c92544dSBjoern A. Zeeb 268*6c92544dSBjoern A. Zeeb if (r->band_idx == MT_RX_SEL2) 269*6c92544dSBjoern A. Zeeb cfg80211_background_radar_event(mphy->hw->wiphy, 270*6c92544dSBjoern A. Zeeb &dev->rdd2_chandef, 271*6c92544dSBjoern A. Zeeb GFP_ATOMIC); 272*6c92544dSBjoern A. Zeeb else 273*6c92544dSBjoern A. Zeeb ieee80211_radar_detected(mphy->hw); 274*6c92544dSBjoern A. Zeeb dev->hw_pattern++; 275*6c92544dSBjoern A. Zeeb } 276*6c92544dSBjoern A. Zeeb 277*6c92544dSBjoern A. Zeeb static void 278*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) 279*6c92544dSBjoern A. Zeeb { 280*6c92544dSBjoern A. Zeeb struct mt76_connac2_mcu_rxd *rxd; 281*6c92544dSBjoern A. Zeeb int len = skb->len - sizeof(*rxd); 282*6c92544dSBjoern A. Zeeb const char *data, *type; 283*6c92544dSBjoern A. Zeeb 284*6c92544dSBjoern A. Zeeb rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 285*6c92544dSBjoern A. Zeeb data = (char *)&rxd[1]; 286*6c92544dSBjoern A. Zeeb 287*6c92544dSBjoern A. Zeeb switch (rxd->s2d_index) { 288*6c92544dSBjoern A. Zeeb case 0: 289*6c92544dSBjoern A. Zeeb #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) 290*6c92544dSBjoern A. Zeeb if (mt7915_debugfs_rx_log(dev, data, len)) 291*6c92544dSBjoern A. Zeeb return; 292*6c92544dSBjoern A. Zeeb #endif 293*6c92544dSBjoern A. Zeeb 294*6c92544dSBjoern A. Zeeb type = "WM"; 295*6c92544dSBjoern A. Zeeb break; 296*6c92544dSBjoern A. Zeeb case 2: 297*6c92544dSBjoern A. Zeeb type = "WA"; 298*6c92544dSBjoern A. Zeeb break; 299*6c92544dSBjoern A. Zeeb default: 300*6c92544dSBjoern A. Zeeb type = "unknown"; 301*6c92544dSBjoern A. Zeeb break; 302*6c92544dSBjoern A. Zeeb } 303*6c92544dSBjoern A. Zeeb 304*6c92544dSBjoern A. Zeeb wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data); 305*6c92544dSBjoern A. Zeeb } 306*6c92544dSBjoern A. Zeeb 307*6c92544dSBjoern A. Zeeb static void 308*6c92544dSBjoern A. Zeeb mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 309*6c92544dSBjoern A. Zeeb { 310*6c92544dSBjoern A. Zeeb if (!vif->bss_conf.color_change_active) 311*6c92544dSBjoern A. Zeeb return; 312*6c92544dSBjoern A. Zeeb 313*6c92544dSBjoern A. Zeeb ieee80211_color_change_finish(vif); 314*6c92544dSBjoern A. Zeeb } 315*6c92544dSBjoern A. Zeeb 316*6c92544dSBjoern A. Zeeb static void 317*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) 318*6c92544dSBjoern A. Zeeb { 319*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = &dev->mt76.phy; 320*6c92544dSBjoern A. Zeeb struct mt7915_mcu_bcc_notify *b; 321*6c92544dSBjoern A. Zeeb 322*6c92544dSBjoern A. Zeeb b = (struct mt7915_mcu_bcc_notify *)skb->data; 323*6c92544dSBjoern A. Zeeb 324*6c92544dSBjoern A. Zeeb if ((b->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) 325*6c92544dSBjoern A. Zeeb mphy = dev->mt76.phys[MT_BAND1]; 326*6c92544dSBjoern A. Zeeb 327*6c92544dSBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(mphy->hw, 328*6c92544dSBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL, 329*6c92544dSBjoern A. Zeeb mt7915_mcu_cca_finish, mphy->hw); 330*6c92544dSBjoern A. Zeeb } 331*6c92544dSBjoern A. Zeeb 332*6c92544dSBjoern A. Zeeb static void 333*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) 334*6c92544dSBjoern A. Zeeb { 335*6c92544dSBjoern A. Zeeb struct mt76_connac2_mcu_rxd *rxd; 336*6c92544dSBjoern A. Zeeb 337*6c92544dSBjoern A. Zeeb rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 338*6c92544dSBjoern A. Zeeb switch (rxd->ext_eid) { 339*6c92544dSBjoern A. Zeeb case MCU_EXT_EVENT_THERMAL_PROTECT: 340*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_thermal_notify(dev, skb); 341*6c92544dSBjoern A. Zeeb break; 342*6c92544dSBjoern A. Zeeb case MCU_EXT_EVENT_RDD_REPORT: 343*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_radar_detected(dev, skb); 344*6c92544dSBjoern A. Zeeb break; 345*6c92544dSBjoern A. Zeeb case MCU_EXT_EVENT_CSA_NOTIFY: 346*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_csa_notify(dev, skb); 347*6c92544dSBjoern A. Zeeb break; 348*6c92544dSBjoern A. Zeeb case MCU_EXT_EVENT_FW_LOG_2_HOST: 349*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_log_message(dev, skb); 350*6c92544dSBjoern A. Zeeb break; 351*6c92544dSBjoern A. Zeeb case MCU_EXT_EVENT_BCC_NOTIFY: 352*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_bcc_notify(dev, skb); 353*6c92544dSBjoern A. Zeeb break; 354*6c92544dSBjoern A. Zeeb default: 355*6c92544dSBjoern A. Zeeb break; 356*6c92544dSBjoern A. Zeeb } 357*6c92544dSBjoern A. Zeeb } 358*6c92544dSBjoern A. Zeeb 359*6c92544dSBjoern A. Zeeb static void 360*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) 361*6c92544dSBjoern A. Zeeb { 362*6c92544dSBjoern A. Zeeb struct mt76_connac2_mcu_rxd *rxd; 363*6c92544dSBjoern A. Zeeb 364*6c92544dSBjoern A. Zeeb rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 365*6c92544dSBjoern A. Zeeb switch (rxd->eid) { 366*6c92544dSBjoern A. Zeeb case MCU_EVENT_EXT: 367*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_ext_event(dev, skb); 368*6c92544dSBjoern A. Zeeb break; 369*6c92544dSBjoern A. Zeeb default: 370*6c92544dSBjoern A. Zeeb break; 371*6c92544dSBjoern A. Zeeb } 372*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 373*6c92544dSBjoern A. Zeeb } 374*6c92544dSBjoern A. Zeeb 375*6c92544dSBjoern A. Zeeb void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) 376*6c92544dSBjoern A. Zeeb { 377*6c92544dSBjoern A. Zeeb struct mt76_connac2_mcu_rxd *rxd; 378*6c92544dSBjoern A. Zeeb 379*6c92544dSBjoern A. Zeeb rxd = (struct mt76_connac2_mcu_rxd *)skb->data; 380*6c92544dSBjoern A. Zeeb if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || 381*6c92544dSBjoern A. Zeeb rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || 382*6c92544dSBjoern A. Zeeb rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || 383*6c92544dSBjoern A. Zeeb rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || 384*6c92544dSBjoern A. Zeeb rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY || 385*6c92544dSBjoern A. Zeeb !rxd->seq) 386*6c92544dSBjoern A. Zeeb mt7915_mcu_rx_unsolicited_event(dev, skb); 387*6c92544dSBjoern A. Zeeb else 388*6c92544dSBjoern A. Zeeb mt76_mcu_rx_event(&dev->mt76, skb); 389*6c92544dSBjoern A. Zeeb } 390*6c92544dSBjoern A. Zeeb 391*6c92544dSBjoern A. Zeeb static struct tlv * 392*6c92544dSBjoern A. Zeeb mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len, 393*6c92544dSBjoern A. Zeeb __le16 *sub_ntlv, __le16 *len) 394*6c92544dSBjoern A. Zeeb { 395*6c92544dSBjoern A. Zeeb struct tlv *ptlv, tlv = { 396*6c92544dSBjoern A. Zeeb .tag = cpu_to_le16(sub_tag), 397*6c92544dSBjoern A. Zeeb .len = cpu_to_le16(sub_len), 398*6c92544dSBjoern A. Zeeb }; 399*6c92544dSBjoern A. Zeeb 400*6c92544dSBjoern A. Zeeb ptlv = skb_put(skb, sub_len); 401*6c92544dSBjoern A. Zeeb memcpy(ptlv, &tlv, sizeof(tlv)); 402*6c92544dSBjoern A. Zeeb 403*6c92544dSBjoern A. Zeeb le16_add_cpu(sub_ntlv, 1); 404*6c92544dSBjoern A. Zeeb le16_add_cpu(len, sub_len); 405*6c92544dSBjoern A. Zeeb 406*6c92544dSBjoern A. Zeeb return ptlv; 407*6c92544dSBjoern A. Zeeb } 408*6c92544dSBjoern A. Zeeb 409*6c92544dSBjoern A. Zeeb /** bss info **/ 410*6c92544dSBjoern A. Zeeb struct mt7915_he_obss_narrow_bw_ru_data { 411*6c92544dSBjoern A. Zeeb bool tolerated; 412*6c92544dSBjoern A. Zeeb }; 413*6c92544dSBjoern A. Zeeb 414*6c92544dSBjoern A. Zeeb static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, 415*6c92544dSBjoern A. Zeeb struct cfg80211_bss *bss, 416*6c92544dSBjoern A. Zeeb void *_data) 417*6c92544dSBjoern A. Zeeb { 418*6c92544dSBjoern A. Zeeb struct mt7915_he_obss_narrow_bw_ru_data *data = _data; 419*6c92544dSBjoern A. Zeeb const struct element *elem; 420*6c92544dSBjoern A. Zeeb 421*6c92544dSBjoern A. Zeeb rcu_read_lock(); 422*6c92544dSBjoern A. Zeeb elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY); 423*6c92544dSBjoern A. Zeeb 424*6c92544dSBjoern A. Zeeb if (!elem || elem->datalen <= 10 || 425*6c92544dSBjoern A. Zeeb !(elem->data[10] & 426*6c92544dSBjoern A. Zeeb WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) 427*6c92544dSBjoern A. Zeeb data->tolerated = false; 428*6c92544dSBjoern A. Zeeb 429*6c92544dSBjoern A. Zeeb rcu_read_unlock(); 430*6c92544dSBjoern A. Zeeb } 431*6c92544dSBjoern A. Zeeb 432*6c92544dSBjoern A. Zeeb static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, 433*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif) 434*6c92544dSBjoern A. Zeeb { 435*6c92544dSBjoern A. Zeeb struct mt7915_he_obss_narrow_bw_ru_data iter_data = { 436*6c92544dSBjoern A. Zeeb .tolerated = true, 437*6c92544dSBjoern A. Zeeb }; 438*6c92544dSBjoern A. Zeeb 439*6c92544dSBjoern A. Zeeb if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) 440*6c92544dSBjoern A. Zeeb return false; 441*6c92544dSBjoern A. Zeeb 442*6c92544dSBjoern A. Zeeb cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, 443*6c92544dSBjoern A. Zeeb mt7915_check_he_obss_narrow_bw_ru_iter, 444*6c92544dSBjoern A. Zeeb &iter_data); 445*6c92544dSBjoern A. Zeeb 446*6c92544dSBjoern A. Zeeb /* 447*6c92544dSBjoern A. Zeeb * If there is at least one AP on radar channel that cannot 448*6c92544dSBjoern A. Zeeb * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU. 449*6c92544dSBjoern A. Zeeb */ 450*6c92544dSBjoern A. Zeeb return !iter_data.tolerated; 451*6c92544dSBjoern A. Zeeb } 452*6c92544dSBjoern A. Zeeb 453*6c92544dSBjoern A. Zeeb static void 454*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 455*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy) 456*6c92544dSBjoern A. Zeeb { 457*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 458*6c92544dSBjoern A. Zeeb struct bss_info_rf_ch *ch; 459*6c92544dSBjoern A. Zeeb struct tlv *tlv; 460*6c92544dSBjoern A. Zeeb int freq1 = chandef->center_freq1; 461*6c92544dSBjoern A. Zeeb 462*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch)); 463*6c92544dSBjoern A. Zeeb 464*6c92544dSBjoern A. Zeeb ch = (struct bss_info_rf_ch *)tlv; 465*6c92544dSBjoern A. Zeeb ch->pri_ch = chandef->chan->hw_value; 466*6c92544dSBjoern A. Zeeb ch->center_ch0 = ieee80211_frequency_to_channel(freq1); 467*6c92544dSBjoern A. Zeeb ch->bw = mt76_connac_chan_bw(chandef); 468*6c92544dSBjoern A. Zeeb 469*6c92544dSBjoern A. Zeeb if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 470*6c92544dSBjoern A. Zeeb int freq2 = chandef->center_freq2; 471*6c92544dSBjoern A. Zeeb 472*6c92544dSBjoern A. Zeeb ch->center_ch1 = ieee80211_frequency_to_channel(freq2); 473*6c92544dSBjoern A. Zeeb } 474*6c92544dSBjoern A. Zeeb 475*6c92544dSBjoern A. Zeeb if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) { 476*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = phy->mt76; 477*6c92544dSBjoern A. Zeeb 478*6c92544dSBjoern A. Zeeb ch->he_ru26_block = 479*6c92544dSBjoern A. Zeeb mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif); 480*6c92544dSBjoern A. Zeeb ch->he_all_disable = false; 481*6c92544dSBjoern A. Zeeb } else { 482*6c92544dSBjoern A. Zeeb ch->he_all_disable = true; 483*6c92544dSBjoern A. Zeeb } 484*6c92544dSBjoern A. Zeeb } 485*6c92544dSBjoern A. Zeeb 486*6c92544dSBjoern A. Zeeb static void 487*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 488*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy) 489*6c92544dSBjoern A. Zeeb { 490*6c92544dSBjoern A. Zeeb int max_nss = hweight8(phy->mt76->chainmask); 491*6c92544dSBjoern A. Zeeb struct bss_info_ra *ra; 492*6c92544dSBjoern A. Zeeb struct tlv *tlv; 493*6c92544dSBjoern A. Zeeb 494*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra)); 495*6c92544dSBjoern A. Zeeb 496*6c92544dSBjoern A. Zeeb ra = (struct bss_info_ra *)tlv; 497*6c92544dSBjoern A. Zeeb ra->op_mode = vif->type == NL80211_IFTYPE_AP; 498*6c92544dSBjoern A. Zeeb ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC; 499*6c92544dSBjoern A. Zeeb ra->short_preamble = true; 500*6c92544dSBjoern A. Zeeb ra->tx_streams = max_nss; 501*6c92544dSBjoern A. Zeeb ra->rx_streams = max_nss; 502*6c92544dSBjoern A. Zeeb ra->algo = 4; 503*6c92544dSBjoern A. Zeeb ra->train_up_rule = 2; 504*6c92544dSBjoern A. Zeeb ra->train_up_high_thres = 110; 505*6c92544dSBjoern A. Zeeb ra->train_up_rule_rssi = -70; 506*6c92544dSBjoern A. Zeeb ra->low_traffic_thres = 2; 507*6c92544dSBjoern A. Zeeb ra->phy_cap = cpu_to_le32(0xfdf); 508*6c92544dSBjoern A. Zeeb ra->interval = cpu_to_le32(500); 509*6c92544dSBjoern A. Zeeb ra->fast_interval = cpu_to_le32(100); 510*6c92544dSBjoern A. Zeeb } 511*6c92544dSBjoern A. Zeeb 512*6c92544dSBjoern A. Zeeb static void 513*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, 514*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy) 515*6c92544dSBjoern A. Zeeb { 516*6c92544dSBjoern A. Zeeb #define DEFAULT_HE_PE_DURATION 4 517*6c92544dSBjoern A. Zeeb #define DEFAULT_HE_DURATION_RTS_THRES 1023 518*6c92544dSBjoern A. Zeeb const struct ieee80211_sta_he_cap *cap; 519*6c92544dSBjoern A. Zeeb struct bss_info_he *he; 520*6c92544dSBjoern A. Zeeb struct tlv *tlv; 521*6c92544dSBjoern A. Zeeb 522*6c92544dSBjoern A. Zeeb cap = mt76_connac_get_he_phy_cap(phy->mt76, vif); 523*6c92544dSBjoern A. Zeeb 524*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); 525*6c92544dSBjoern A. Zeeb 526*6c92544dSBjoern A. Zeeb he = (struct bss_info_he *)tlv; 527*6c92544dSBjoern A. Zeeb he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; 528*6c92544dSBjoern A. Zeeb if (!he->he_pe_duration) 529*6c92544dSBjoern A. Zeeb he->he_pe_duration = DEFAULT_HE_PE_DURATION; 530*6c92544dSBjoern A. Zeeb 531*6c92544dSBjoern A. Zeeb he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); 532*6c92544dSBjoern A. Zeeb if (!he->he_rts_thres) 533*6c92544dSBjoern A. Zeeb he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); 534*6c92544dSBjoern A. Zeeb 535*6c92544dSBjoern A. Zeeb he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; 536*6c92544dSBjoern A. Zeeb he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; 537*6c92544dSBjoern A. Zeeb he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; 538*6c92544dSBjoern A. Zeeb } 539*6c92544dSBjoern A. Zeeb 540*6c92544dSBjoern A. Zeeb static void 541*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb) 542*6c92544dSBjoern A. Zeeb { 543*6c92544dSBjoern A. Zeeb #define TXD_CMP_MAP1 GENMASK(15, 0) 544*6c92544dSBjoern A. Zeeb #define TXD_CMP_MAP2 (GENMASK(31, 0) & ~BIT(23)) 545*6c92544dSBjoern A. Zeeb struct bss_info_hw_amsdu *amsdu; 546*6c92544dSBjoern A. Zeeb struct tlv *tlv; 547*6c92544dSBjoern A. Zeeb 548*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu)); 549*6c92544dSBjoern A. Zeeb 550*6c92544dSBjoern A. Zeeb amsdu = (struct bss_info_hw_amsdu *)tlv; 551*6c92544dSBjoern A. Zeeb amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1); 552*6c92544dSBjoern A. Zeeb amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2); 553*6c92544dSBjoern A. Zeeb amsdu->trig_thres = cpu_to_le16(2); 554*6c92544dSBjoern A. Zeeb amsdu->enable = true; 555*6c92544dSBjoern A. Zeeb } 556*6c92544dSBjoern A. Zeeb 557*6c92544dSBjoern A. Zeeb static void 558*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy) 559*6c92544dSBjoern A. Zeeb { 560*6c92544dSBjoern A. Zeeb struct bss_info_bmc_rate *bmc; 561*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 562*6c92544dSBjoern A. Zeeb enum nl80211_band band = chandef->chan->band; 563*6c92544dSBjoern A. Zeeb struct tlv *tlv; 564*6c92544dSBjoern A. Zeeb 565*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc)); 566*6c92544dSBjoern A. Zeeb 567*6c92544dSBjoern A. Zeeb bmc = (struct bss_info_bmc_rate *)tlv; 568*6c92544dSBjoern A. Zeeb if (band == NL80211_BAND_2GHZ) { 569*6c92544dSBjoern A. Zeeb bmc->short_preamble = true; 570*6c92544dSBjoern A. Zeeb } else { 571*6c92544dSBjoern A. Zeeb bmc->bc_trans = cpu_to_le16(0x2000); 572*6c92544dSBjoern A. Zeeb bmc->mc_trans = cpu_to_le16(0x2080); 573*6c92544dSBjoern A. Zeeb } 574*6c92544dSBjoern A. Zeeb } 575*6c92544dSBjoern A. Zeeb 576*6c92544dSBjoern A. Zeeb static int 577*6c92544dSBjoern A. Zeeb mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif, 578*6c92544dSBjoern A. Zeeb bool bssid, bool enable) 579*6c92544dSBjoern A. Zeeb { 580*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 581*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 582*6c92544dSBjoern A. Zeeb u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START; 583*6c92544dSBjoern A. Zeeb u32 mask = phy->omac_mask >> 32 & ~BIT(idx); 584*6c92544dSBjoern A. Zeeb const u8 *addr = vif->addr; 585*6c92544dSBjoern A. Zeeb struct { 586*6c92544dSBjoern A. Zeeb u8 mode; 587*6c92544dSBjoern A. Zeeb u8 force_clear; 588*6c92544dSBjoern A. Zeeb u8 clear_bitmap[8]; 589*6c92544dSBjoern A. Zeeb u8 entry_count; 590*6c92544dSBjoern A. Zeeb u8 write; 591*6c92544dSBjoern A. Zeeb u8 band; 592*6c92544dSBjoern A. Zeeb 593*6c92544dSBjoern A. Zeeb u8 index; 594*6c92544dSBjoern A. Zeeb u8 bssid; 595*6c92544dSBjoern A. Zeeb u8 addr[ETH_ALEN]; 596*6c92544dSBjoern A. Zeeb } __packed req = { 597*6c92544dSBjoern A. Zeeb .mode = !!mask || enable, 598*6c92544dSBjoern A. Zeeb .entry_count = 1, 599*6c92544dSBjoern A. Zeeb .write = 1, 600*6c92544dSBjoern A. Zeeb .band = phy != &dev->phy, 601*6c92544dSBjoern A. Zeeb .index = idx * 2 + bssid, 602*6c92544dSBjoern A. Zeeb }; 603*6c92544dSBjoern A. Zeeb 604*6c92544dSBjoern A. Zeeb if (bssid) 605*6c92544dSBjoern A. Zeeb addr = vif->bss_conf.bssid; 606*6c92544dSBjoern A. Zeeb 607*6c92544dSBjoern A. Zeeb if (enable) 608*6c92544dSBjoern A. Zeeb ether_addr_copy(req.addr, addr); 609*6c92544dSBjoern A. Zeeb 610*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req, 611*6c92544dSBjoern A. Zeeb sizeof(req), true); 612*6c92544dSBjoern A. Zeeb } 613*6c92544dSBjoern A. Zeeb 614*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, 615*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, int enable) 616*6c92544dSBjoern A. Zeeb { 617*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 618*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 619*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 620*6c92544dSBjoern A. Zeeb 621*6c92544dSBjoern A. Zeeb if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) { 622*6c92544dSBjoern A. Zeeb mt7915_mcu_muar_config(phy, vif, false, enable); 623*6c92544dSBjoern A. Zeeb mt7915_mcu_muar_config(phy, vif, true, enable); 624*6c92544dSBjoern A. Zeeb } 625*6c92544dSBjoern A. Zeeb 626*6c92544dSBjoern A. Zeeb skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL, 627*6c92544dSBjoern A. Zeeb MT7915_BSS_UPDATE_MAX_SIZE); 628*6c92544dSBjoern A. Zeeb if (IS_ERR(skb)) 629*6c92544dSBjoern A. Zeeb return PTR_ERR(skb); 630*6c92544dSBjoern A. Zeeb 631*6c92544dSBjoern A. Zeeb /* bss_omac must be first */ 632*6c92544dSBjoern A. Zeeb if (enable) 633*6c92544dSBjoern A. Zeeb mt76_connac_mcu_bss_omac_tlv(skb, vif); 634*6c92544dSBjoern A. Zeeb 635*6c92544dSBjoern A. Zeeb mt76_connac_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76, 636*6c92544dSBjoern A. Zeeb mvif->sta.wcid.idx, enable); 637*6c92544dSBjoern A. Zeeb 638*6c92544dSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_MONITOR) 639*6c92544dSBjoern A. Zeeb goto out; 640*6c92544dSBjoern A. Zeeb 641*6c92544dSBjoern A. Zeeb if (enable) { 642*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_rfch_tlv(skb, vif, phy); 643*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_bmc_tlv(skb, phy); 644*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_ra_tlv(skb, vif, phy); 645*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_hw_amsdu_tlv(skb); 646*6c92544dSBjoern A. Zeeb 647*6c92544dSBjoern A. Zeeb if (vif->bss_conf.he_support) 648*6c92544dSBjoern A. Zeeb mt7915_mcu_bss_he_tlv(skb, vif, phy); 649*6c92544dSBjoern A. Zeeb 650*6c92544dSBjoern A. Zeeb if (mvif->mt76.omac_idx >= EXT_BSSID_START && 651*6c92544dSBjoern A. Zeeb mvif->mt76.omac_idx < REPEATER_BSSID_START) 652*6c92544dSBjoern A. Zeeb mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76); 653*6c92544dSBjoern A. Zeeb } 654*6c92544dSBjoern A. Zeeb out: 655*6c92544dSBjoern A. Zeeb return mt76_mcu_skb_send_msg(&dev->mt76, skb, 656*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(BSS_INFO_UPDATE), true); 657*6c92544dSBjoern A. Zeeb } 658*6c92544dSBjoern A. Zeeb 659*6c92544dSBjoern A. Zeeb /** starec & wtbl **/ 660*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, 661*6c92544dSBjoern A. Zeeb struct ieee80211_ampdu_params *params, 662*6c92544dSBjoern A. Zeeb bool enable) 663*6c92544dSBjoern A. Zeeb { 664*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; 665*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = msta->vif; 666*6c92544dSBjoern A. Zeeb 667*6c92544dSBjoern A. Zeeb if (enable && !params->amsdu) 668*6c92544dSBjoern A. Zeeb msta->wcid.amsdu = false; 669*6c92544dSBjoern A. Zeeb 670*6c92544dSBjoern A. Zeeb return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, 671*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(STA_REC_UPDATE), 672*6c92544dSBjoern A. Zeeb enable, true); 673*6c92544dSBjoern A. Zeeb } 674*6c92544dSBjoern A. Zeeb 675*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, 676*6c92544dSBjoern A. Zeeb struct ieee80211_ampdu_params *params, 677*6c92544dSBjoern A. Zeeb bool enable) 678*6c92544dSBjoern A. Zeeb { 679*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; 680*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = msta->vif; 681*6c92544dSBjoern A. Zeeb 682*6c92544dSBjoern A. Zeeb return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, 683*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(STA_REC_UPDATE), 684*6c92544dSBjoern A. Zeeb enable, false); 685*6c92544dSBjoern A. Zeeb } 686*6c92544dSBjoern A. Zeeb 687*6c92544dSBjoern A. Zeeb static void 688*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 689*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif) 690*6c92544dSBjoern A. Zeeb { 691*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 692*6c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; 693*6c92544dSBjoern A. Zeeb struct ieee80211_he_mcs_nss_supp mcs_map; 694*6c92544dSBjoern A. Zeeb struct sta_rec_he *he; 695*6c92544dSBjoern A. Zeeb struct tlv *tlv; 696*6c92544dSBjoern A. Zeeb u32 cap = 0; 697*6c92544dSBjoern A. Zeeb 698*6c92544dSBjoern A. Zeeb if (!sta->deflink.he_cap.has_he) 699*6c92544dSBjoern A. Zeeb return; 700*6c92544dSBjoern A. Zeeb 701*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); 702*6c92544dSBjoern A. Zeeb 703*6c92544dSBjoern A. Zeeb he = (struct sta_rec_he *)tlv; 704*6c92544dSBjoern A. Zeeb 705*6c92544dSBjoern A. Zeeb if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) 706*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_HTC; 707*6c92544dSBjoern A. Zeeb 708*6c92544dSBjoern A. Zeeb if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) 709*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_BSR; 710*6c92544dSBjoern A. Zeeb 711*6c92544dSBjoern A. Zeeb if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) 712*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_OM; 713*6c92544dSBjoern A. Zeeb 714*6c92544dSBjoern A. Zeeb if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU) 715*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; 716*6c92544dSBjoern A. Zeeb 717*6c92544dSBjoern A. Zeeb if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) 718*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_BQR; 719*6c92544dSBjoern A. Zeeb 720*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[0] & 721*6c92544dSBjoern A. Zeeb (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | 722*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) 723*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; 724*6c92544dSBjoern A. Zeeb 725*6c92544dSBjoern A. Zeeb if (mvif->cap.he_ldpc && 726*6c92544dSBjoern A. Zeeb (elem->phy_cap_info[1] & 727*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) 728*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_LDPC; 729*6c92544dSBjoern A. Zeeb 730*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[1] & 731*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) 732*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; 733*6c92544dSBjoern A. Zeeb 734*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[2] & 735*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) 736*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; 737*6c92544dSBjoern A. Zeeb 738*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[2] & 739*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) 740*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; 741*6c92544dSBjoern A. Zeeb 742*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[2] & 743*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) 744*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; 745*6c92544dSBjoern A. Zeeb 746*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[6] & 747*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB) 748*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_TRIG_CQI_FK; 749*6c92544dSBjoern A. Zeeb 750*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[6] & 751*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) 752*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; 753*6c92544dSBjoern A. Zeeb 754*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[7] & 755*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) 756*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; 757*6c92544dSBjoern A. Zeeb 758*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[7] & 759*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) 760*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; 761*6c92544dSBjoern A. Zeeb 762*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[7] & 763*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) 764*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; 765*6c92544dSBjoern A. Zeeb 766*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[8] & 767*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) 768*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; 769*6c92544dSBjoern A. Zeeb 770*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[8] & 771*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) 772*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; 773*6c92544dSBjoern A. Zeeb 774*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[9] & 775*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) 776*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; 777*6c92544dSBjoern A. Zeeb 778*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[9] & 779*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) 780*6c92544dSBjoern A. Zeeb cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; 781*6c92544dSBjoern A. Zeeb 782*6c92544dSBjoern A. Zeeb he->he_cap = cpu_to_le32(cap); 783*6c92544dSBjoern A. Zeeb 784*6c92544dSBjoern A. Zeeb mcs_map = sta->deflink.he_cap.he_mcs_nss_supp; 785*6c92544dSBjoern A. Zeeb switch (sta->deflink.bandwidth) { 786*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_160: 787*6c92544dSBjoern A. Zeeb if (elem->phy_cap_info[0] & 788*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) 789*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_he_mcs(sta, 790*6c92544dSBjoern A. Zeeb &he->max_nss_mcs[CMD_HE_MCS_BW8080], 791*6c92544dSBjoern A. Zeeb le16_to_cpu(mcs_map.rx_mcs_80p80)); 792*6c92544dSBjoern A. Zeeb 793*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_he_mcs(sta, 794*6c92544dSBjoern A. Zeeb &he->max_nss_mcs[CMD_HE_MCS_BW160], 795*6c92544dSBjoern A. Zeeb le16_to_cpu(mcs_map.rx_mcs_160)); 796*6c92544dSBjoern A. Zeeb fallthrough; 797*6c92544dSBjoern A. Zeeb default: 798*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_he_mcs(sta, 799*6c92544dSBjoern A. Zeeb &he->max_nss_mcs[CMD_HE_MCS_BW80], 800*6c92544dSBjoern A. Zeeb le16_to_cpu(mcs_map.rx_mcs_80)); 801*6c92544dSBjoern A. Zeeb break; 802*6c92544dSBjoern A. Zeeb } 803*6c92544dSBjoern A. Zeeb 804*6c92544dSBjoern A. Zeeb he->t_frame_dur = 805*6c92544dSBjoern A. Zeeb HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); 806*6c92544dSBjoern A. Zeeb he->max_ampdu_exp = 807*6c92544dSBjoern A. Zeeb HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); 808*6c92544dSBjoern A. Zeeb 809*6c92544dSBjoern A. Zeeb he->bw_set = 810*6c92544dSBjoern A. Zeeb HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); 811*6c92544dSBjoern A. Zeeb he->device_class = 812*6c92544dSBjoern A. Zeeb HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); 813*6c92544dSBjoern A. Zeeb he->punc_pream_rx = 814*6c92544dSBjoern A. Zeeb HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); 815*6c92544dSBjoern A. Zeeb 816*6c92544dSBjoern A. Zeeb he->dcm_tx_mode = 817*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); 818*6c92544dSBjoern A. Zeeb he->dcm_tx_max_nss = 819*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); 820*6c92544dSBjoern A. Zeeb he->dcm_rx_mode = 821*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); 822*6c92544dSBjoern A. Zeeb he->dcm_rx_max_nss = 823*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); 824*6c92544dSBjoern A. Zeeb he->dcm_rx_max_nss = 825*6c92544dSBjoern A. Zeeb HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); 826*6c92544dSBjoern A. Zeeb 827*6c92544dSBjoern A. Zeeb he->pkt_ext = 2; 828*6c92544dSBjoern A. Zeeb } 829*6c92544dSBjoern A. Zeeb 830*6c92544dSBjoern A. Zeeb static void 831*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 832*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, struct ieee80211_vif *vif) 833*6c92544dSBjoern A. Zeeb { 834*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 835*6c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; 836*6c92544dSBjoern A. Zeeb struct sta_rec_muru *muru; 837*6c92544dSBjoern A. Zeeb struct tlv *tlv; 838*6c92544dSBjoern A. Zeeb 839*6c92544dSBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION && 840*6c92544dSBjoern A. Zeeb vif->type != NL80211_IFTYPE_AP) 841*6c92544dSBjoern A. Zeeb return; 842*6c92544dSBjoern A. Zeeb 843*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); 844*6c92544dSBjoern A. Zeeb 845*6c92544dSBjoern A. Zeeb muru = (struct sta_rec_muru *)tlv; 846*6c92544dSBjoern A. Zeeb 847*6c92544dSBjoern A. Zeeb muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer || 848*6c92544dSBjoern A. Zeeb mvif->cap.vht_mu_ebfer || 849*6c92544dSBjoern A. Zeeb mvif->cap.vht_mu_ebfee; 850*6c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) 851*6c92544dSBjoern A. Zeeb muru->cfg.mimo_ul_en = true; 852*6c92544dSBjoern A. Zeeb muru->cfg.ofdma_dl_en = true; 853*6c92544dSBjoern A. Zeeb 854*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported) 855*6c92544dSBjoern A. Zeeb muru->mimo_dl.vht_mu_bfee = 856*6c92544dSBjoern A. Zeeb !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); 857*6c92544dSBjoern A. Zeeb 858*6c92544dSBjoern A. Zeeb if (!sta->deflink.he_cap.has_he) 859*6c92544dSBjoern A. Zeeb return; 860*6c92544dSBjoern A. Zeeb 861*6c92544dSBjoern A. Zeeb muru->mimo_dl.partial_bw_dl_mimo = 862*6c92544dSBjoern A. Zeeb HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); 863*6c92544dSBjoern A. Zeeb 864*6c92544dSBjoern A. Zeeb muru->mimo_ul.full_ul_mimo = 865*6c92544dSBjoern A. Zeeb HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); 866*6c92544dSBjoern A. Zeeb muru->mimo_ul.partial_ul_mimo = 867*6c92544dSBjoern A. Zeeb HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); 868*6c92544dSBjoern A. Zeeb 869*6c92544dSBjoern A. Zeeb muru->ofdma_dl.punc_pream_rx = 870*6c92544dSBjoern A. Zeeb HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); 871*6c92544dSBjoern A. Zeeb muru->ofdma_dl.he_20m_in_40m_2g = 872*6c92544dSBjoern A. Zeeb HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]); 873*6c92544dSBjoern A. Zeeb muru->ofdma_dl.he_20m_in_160m = 874*6c92544dSBjoern A. Zeeb HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); 875*6c92544dSBjoern A. Zeeb muru->ofdma_dl.he_80m_in_160m = 876*6c92544dSBjoern A. Zeeb HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); 877*6c92544dSBjoern A. Zeeb 878*6c92544dSBjoern A. Zeeb muru->ofdma_ul.t_frame_dur = 879*6c92544dSBjoern A. Zeeb HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); 880*6c92544dSBjoern A. Zeeb muru->ofdma_ul.mu_cascading = 881*6c92544dSBjoern A. Zeeb HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); 882*6c92544dSBjoern A. Zeeb muru->ofdma_ul.uo_ra = 883*6c92544dSBjoern A. Zeeb HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); 884*6c92544dSBjoern A. Zeeb } 885*6c92544dSBjoern A. Zeeb 886*6c92544dSBjoern A. Zeeb static void 887*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 888*6c92544dSBjoern A. Zeeb { 889*6c92544dSBjoern A. Zeeb struct sta_rec_ht *ht; 890*6c92544dSBjoern A. Zeeb struct tlv *tlv; 891*6c92544dSBjoern A. Zeeb 892*6c92544dSBjoern A. Zeeb if (!sta->deflink.ht_cap.ht_supported) 893*6c92544dSBjoern A. Zeeb return; 894*6c92544dSBjoern A. Zeeb 895*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); 896*6c92544dSBjoern A. Zeeb 897*6c92544dSBjoern A. Zeeb ht = (struct sta_rec_ht *)tlv; 898*6c92544dSBjoern A. Zeeb ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); 899*6c92544dSBjoern A. Zeeb } 900*6c92544dSBjoern A. Zeeb 901*6c92544dSBjoern A. Zeeb static void 902*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) 903*6c92544dSBjoern A. Zeeb { 904*6c92544dSBjoern A. Zeeb struct sta_rec_vht *vht; 905*6c92544dSBjoern A. Zeeb struct tlv *tlv; 906*6c92544dSBjoern A. Zeeb 907*6c92544dSBjoern A. Zeeb if (!sta->deflink.vht_cap.vht_supported) 908*6c92544dSBjoern A. Zeeb return; 909*6c92544dSBjoern A. Zeeb 910*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); 911*6c92544dSBjoern A. Zeeb 912*6c92544dSBjoern A. Zeeb vht = (struct sta_rec_vht *)tlv; 913*6c92544dSBjoern A. Zeeb vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); 914*6c92544dSBjoern A. Zeeb vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; 915*6c92544dSBjoern A. Zeeb vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; 916*6c92544dSBjoern A. Zeeb } 917*6c92544dSBjoern A. Zeeb 918*6c92544dSBjoern A. Zeeb static void 919*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 920*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta) 921*6c92544dSBjoern A. Zeeb { 922*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 923*6c92544dSBjoern A. Zeeb struct sta_rec_amsdu *amsdu; 924*6c92544dSBjoern A. Zeeb struct tlv *tlv; 925*6c92544dSBjoern A. Zeeb 926*6c92544dSBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION && 927*6c92544dSBjoern A. Zeeb vif->type != NL80211_IFTYPE_AP) 928*6c92544dSBjoern A. Zeeb return; 929*6c92544dSBjoern A. Zeeb 930*6c92544dSBjoern A. Zeeb if (!sta->deflink.agg.max_amsdu_len) 931*6c92544dSBjoern A. Zeeb return; 932*6c92544dSBjoern A. Zeeb 933*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); 934*6c92544dSBjoern A. Zeeb amsdu = (struct sta_rec_amsdu *)tlv; 935*6c92544dSBjoern A. Zeeb amsdu->max_amsdu_num = 8; 936*6c92544dSBjoern A. Zeeb amsdu->amsdu_en = true; 937*6c92544dSBjoern A. Zeeb msta->wcid.amsdu = true; 938*6c92544dSBjoern A. Zeeb 939*6c92544dSBjoern A. Zeeb switch (sta->deflink.agg.max_amsdu_len) { 940*6c92544dSBjoern A. Zeeb case IEEE80211_MAX_MPDU_LEN_VHT_11454: 941*6c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) { 942*6c92544dSBjoern A. Zeeb amsdu->max_mpdu_size = 943*6c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; 944*6c92544dSBjoern A. Zeeb return; 945*6c92544dSBjoern A. Zeeb } 946*6c92544dSBjoern A. Zeeb fallthrough; 947*6c92544dSBjoern A. Zeeb case IEEE80211_MAX_MPDU_LEN_HT_7935: 948*6c92544dSBjoern A. Zeeb case IEEE80211_MAX_MPDU_LEN_VHT_7991: 949*6c92544dSBjoern A. Zeeb amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; 950*6c92544dSBjoern A. Zeeb return; 951*6c92544dSBjoern A. Zeeb default: 952*6c92544dSBjoern A. Zeeb amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; 953*6c92544dSBjoern A. Zeeb return; 954*6c92544dSBjoern A. Zeeb } 955*6c92544dSBjoern A. Zeeb } 956*6c92544dSBjoern A. Zeeb 957*6c92544dSBjoern A. Zeeb static int 958*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 959*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta) 960*6c92544dSBjoern A. Zeeb { 961*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 962*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta; 963*6c92544dSBjoern A. Zeeb struct wtbl_req_hdr *wtbl_hdr; 964*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid; 965*6c92544dSBjoern A. Zeeb struct tlv *tlv; 966*6c92544dSBjoern A. Zeeb 967*6c92544dSBjoern A. Zeeb msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; 968*6c92544dSBjoern A. Zeeb wcid = sta ? &msta->wcid : NULL; 969*6c92544dSBjoern A. Zeeb 970*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); 971*6c92544dSBjoern A. Zeeb wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, 972*6c92544dSBjoern A. Zeeb WTBL_RESET_AND_SET, tlv, 973*6c92544dSBjoern A. Zeeb &skb); 974*6c92544dSBjoern A. Zeeb if (IS_ERR(wtbl_hdr)) 975*6c92544dSBjoern A. Zeeb return PTR_ERR(wtbl_hdr); 976*6c92544dSBjoern A. Zeeb 977*6c92544dSBjoern A. Zeeb mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, skb, vif, sta, tlv, 978*6c92544dSBjoern A. Zeeb wtbl_hdr); 979*6c92544dSBjoern A. Zeeb mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr); 980*6c92544dSBjoern A. Zeeb if (sta) 981*6c92544dSBjoern A. Zeeb mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv, 982*6c92544dSBjoern A. Zeeb wtbl_hdr, mvif->cap.ht_ldpc, 983*6c92544dSBjoern A. Zeeb mvif->cap.vht_ldpc); 984*6c92544dSBjoern A. Zeeb 985*6c92544dSBjoern A. Zeeb return 0; 986*6c92544dSBjoern A. Zeeb } 987*6c92544dSBjoern A. Zeeb 988*6c92544dSBjoern A. Zeeb static inline bool 989*6c92544dSBjoern A. Zeeb mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, 990*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, bool bfee) 991*6c92544dSBjoern A. Zeeb { 992*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 993*6c92544dSBjoern A. Zeeb int tx_ant = hweight8(phy->mt76->chainmask) - 1; 994*6c92544dSBjoern A. Zeeb 995*6c92544dSBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION && 996*6c92544dSBjoern A. Zeeb vif->type != NL80211_IFTYPE_AP) 997*6c92544dSBjoern A. Zeeb return false; 998*6c92544dSBjoern A. Zeeb 999*6c92544dSBjoern A. Zeeb if (!bfee && tx_ant < 2) 1000*6c92544dSBjoern A. Zeeb return false; 1001*6c92544dSBjoern A. Zeeb 1002*6c92544dSBjoern A. Zeeb if (sta->deflink.he_cap.has_he) { 1003*6c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; 1004*6c92544dSBjoern A. Zeeb 1005*6c92544dSBjoern A. Zeeb if (bfee) 1006*6c92544dSBjoern A. Zeeb return mvif->cap.he_su_ebfee && 1007*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); 1008*6c92544dSBjoern A. Zeeb else 1009*6c92544dSBjoern A. Zeeb return mvif->cap.he_su_ebfer && 1010*6c92544dSBjoern A. Zeeb HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); 1011*6c92544dSBjoern A. Zeeb } 1012*6c92544dSBjoern A. Zeeb 1013*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported) { 1014*6c92544dSBjoern A. Zeeb u32 cap = sta->deflink.vht_cap.cap; 1015*6c92544dSBjoern A. Zeeb 1016*6c92544dSBjoern A. Zeeb if (bfee) 1017*6c92544dSBjoern A. Zeeb return mvif->cap.vht_su_ebfee && 1018*6c92544dSBjoern A. Zeeb (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); 1019*6c92544dSBjoern A. Zeeb else 1020*6c92544dSBjoern A. Zeeb return mvif->cap.vht_su_ebfer && 1021*6c92544dSBjoern A. Zeeb (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); 1022*6c92544dSBjoern A. Zeeb } 1023*6c92544dSBjoern A. Zeeb 1024*6c92544dSBjoern A. Zeeb return false; 1025*6c92544dSBjoern A. Zeeb } 1026*6c92544dSBjoern A. Zeeb 1027*6c92544dSBjoern A. Zeeb static void 1028*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) 1029*6c92544dSBjoern A. Zeeb { 1030*6c92544dSBjoern A. Zeeb bf->sounding_phy = MT_PHY_TYPE_OFDM; 1031*6c92544dSBjoern A. Zeeb bf->ndp_rate = 0; /* mcs0 */ 1032*6c92544dSBjoern A. Zeeb bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ 1033*6c92544dSBjoern A. Zeeb bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ 1034*6c92544dSBjoern A. Zeeb } 1035*6c92544dSBjoern A. Zeeb 1036*6c92544dSBjoern A. Zeeb static void 1037*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy, 1038*6c92544dSBjoern A. Zeeb struct sta_rec_bf *bf) 1039*6c92544dSBjoern A. Zeeb { 1040*6c92544dSBjoern A. Zeeb struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs; 1041*6c92544dSBjoern A. Zeeb u8 n = 0; 1042*6c92544dSBjoern A. Zeeb 1043*6c92544dSBjoern A. Zeeb bf->tx_mode = MT_PHY_TYPE_HT; 1044*6c92544dSBjoern A. Zeeb 1045*6c92544dSBjoern A. Zeeb if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) && 1046*6c92544dSBjoern A. Zeeb (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) 1047*6c92544dSBjoern A. Zeeb n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK, 1048*6c92544dSBjoern A. Zeeb mcs->tx_params); 1049*6c92544dSBjoern A. Zeeb else if (mcs->rx_mask[3]) 1050*6c92544dSBjoern A. Zeeb n = 3; 1051*6c92544dSBjoern A. Zeeb else if (mcs->rx_mask[2]) 1052*6c92544dSBjoern A. Zeeb n = 2; 1053*6c92544dSBjoern A. Zeeb else if (mcs->rx_mask[1]) 1054*6c92544dSBjoern A. Zeeb n = 1; 1055*6c92544dSBjoern A. Zeeb 1056*6c92544dSBjoern A. Zeeb bf->nrow = hweight8(phy->mt76->chainmask) - 1; 1057*6c92544dSBjoern A. Zeeb bf->ncol = min_t(u8, bf->nrow, n); 1058*6c92544dSBjoern A. Zeeb bf->ibf_ncol = n; 1059*6c92544dSBjoern A. Zeeb } 1060*6c92544dSBjoern A. Zeeb 1061*6c92544dSBjoern A. Zeeb static void 1062*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, 1063*6c92544dSBjoern A. Zeeb struct sta_rec_bf *bf, bool explicit) 1064*6c92544dSBjoern A. Zeeb { 1065*6c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; 1066*6c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap; 1067*6c92544dSBjoern A. Zeeb u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); 1068*6c92544dSBjoern A. Zeeb u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 1069*6c92544dSBjoern A. Zeeb u8 tx_ant = hweight8(phy->mt76->chainmask) - 1; 1070*6c92544dSBjoern A. Zeeb 1071*6c92544dSBjoern A. Zeeb bf->tx_mode = MT_PHY_TYPE_VHT; 1072*6c92544dSBjoern A. Zeeb 1073*6c92544dSBjoern A. Zeeb if (explicit) { 1074*6c92544dSBjoern A. Zeeb u8 sts, snd_dim; 1075*6c92544dSBjoern A. Zeeb 1076*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_sounding_rate(bf); 1077*6c92544dSBjoern A. Zeeb 1078*6c92544dSBjoern A. Zeeb sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 1079*6c92544dSBjoern A. Zeeb pc->cap); 1080*6c92544dSBjoern A. Zeeb snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, 1081*6c92544dSBjoern A. Zeeb vc->cap); 1082*6c92544dSBjoern A. Zeeb bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant); 1083*6c92544dSBjoern A. Zeeb bf->ncol = min_t(u8, nss_mcs, bf->nrow); 1084*6c92544dSBjoern A. Zeeb bf->ibf_ncol = bf->ncol; 1085*6c92544dSBjoern A. Zeeb 1086*6c92544dSBjoern A. Zeeb if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) 1087*6c92544dSBjoern A. Zeeb bf->nrow = 1; 1088*6c92544dSBjoern A. Zeeb } else { 1089*6c92544dSBjoern A. Zeeb bf->nrow = tx_ant; 1090*6c92544dSBjoern A. Zeeb bf->ncol = min_t(u8, nss_mcs, bf->nrow); 1091*6c92544dSBjoern A. Zeeb bf->ibf_ncol = nss_mcs; 1092*6c92544dSBjoern A. Zeeb 1093*6c92544dSBjoern A. Zeeb if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) 1094*6c92544dSBjoern A. Zeeb bf->ibf_nrow = 1; 1095*6c92544dSBjoern A. Zeeb } 1096*6c92544dSBjoern A. Zeeb } 1097*6c92544dSBjoern A. Zeeb 1098*6c92544dSBjoern A. Zeeb static void 1099*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, 1100*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy, struct sta_rec_bf *bf) 1101*6c92544dSBjoern A. Zeeb { 1102*6c92544dSBjoern A. Zeeb struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap; 1103*6c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; 1104*6c92544dSBjoern A. Zeeb const struct ieee80211_sta_he_cap *vc = 1105*6c92544dSBjoern A. Zeeb mt76_connac_get_he_phy_cap(phy->mt76, vif); 1106*6c92544dSBjoern A. Zeeb const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; 1107*6c92544dSBjoern A. Zeeb u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); 1108*6c92544dSBjoern A. Zeeb u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 1109*6c92544dSBjoern A. Zeeb u8 snd_dim, sts; 1110*6c92544dSBjoern A. Zeeb 1111*6c92544dSBjoern A. Zeeb bf->tx_mode = MT_PHY_TYPE_HE_SU; 1112*6c92544dSBjoern A. Zeeb 1113*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_sounding_rate(bf); 1114*6c92544dSBjoern A. Zeeb 1115*6c92544dSBjoern A. Zeeb bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB, 1116*6c92544dSBjoern A. Zeeb pe->phy_cap_info[6]); 1117*6c92544dSBjoern A. Zeeb bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB, 1118*6c92544dSBjoern A. Zeeb pe->phy_cap_info[6]); 1119*6c92544dSBjoern A. Zeeb snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, 1120*6c92544dSBjoern A. Zeeb ve->phy_cap_info[5]); 1121*6c92544dSBjoern A. Zeeb sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, 1122*6c92544dSBjoern A. Zeeb pe->phy_cap_info[4]); 1123*6c92544dSBjoern A. Zeeb bf->nrow = min_t(u8, snd_dim, sts); 1124*6c92544dSBjoern A. Zeeb bf->ncol = min_t(u8, nss_mcs, bf->nrow); 1125*6c92544dSBjoern A. Zeeb bf->ibf_ncol = bf->ncol; 1126*6c92544dSBjoern A. Zeeb 1127*6c92544dSBjoern A. Zeeb if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160) 1128*6c92544dSBjoern A. Zeeb return; 1129*6c92544dSBjoern A. Zeeb 1130*6c92544dSBjoern A. Zeeb /* go over for 160MHz and 80p80 */ 1131*6c92544dSBjoern A. Zeeb if (pe->phy_cap_info[0] & 1132*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) { 1133*6c92544dSBjoern A. Zeeb mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); 1134*6c92544dSBjoern A. Zeeb nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 1135*6c92544dSBjoern A. Zeeb 1136*6c92544dSBjoern A. Zeeb bf->ncol_bw160 = nss_mcs; 1137*6c92544dSBjoern A. Zeeb } 1138*6c92544dSBjoern A. Zeeb 1139*6c92544dSBjoern A. Zeeb if (pe->phy_cap_info[0] & 1140*6c92544dSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { 1141*6c92544dSBjoern A. Zeeb mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); 1142*6c92544dSBjoern A. Zeeb nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); 1143*6c92544dSBjoern A. Zeeb 1144*6c92544dSBjoern A. Zeeb if (bf->ncol_bw160) 1145*6c92544dSBjoern A. Zeeb bf->ncol_bw160 = min_t(u8, bf->ncol_bw160, nss_mcs); 1146*6c92544dSBjoern A. Zeeb else 1147*6c92544dSBjoern A. Zeeb bf->ncol_bw160 = nss_mcs; 1148*6c92544dSBjoern A. Zeeb } 1149*6c92544dSBjoern A. Zeeb 1150*6c92544dSBjoern A. Zeeb snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, 1151*6c92544dSBjoern A. Zeeb ve->phy_cap_info[5]); 1152*6c92544dSBjoern A. Zeeb sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, 1153*6c92544dSBjoern A. Zeeb pe->phy_cap_info[4]); 1154*6c92544dSBjoern A. Zeeb 1155*6c92544dSBjoern A. Zeeb bf->nrow_bw160 = min_t(int, snd_dim, sts); 1156*6c92544dSBjoern A. Zeeb } 1157*6c92544dSBjoern A. Zeeb 1158*6c92544dSBjoern A. Zeeb static void 1159*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 1160*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta) 1161*6c92544dSBjoern A. Zeeb { 1162*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1163*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy = mvif->phy; 1164*6c92544dSBjoern A. Zeeb int tx_ant = hweight8(phy->mt76->chainmask) - 1; 1165*6c92544dSBjoern A. Zeeb struct sta_rec_bf *bf; 1166*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1167*6c92544dSBjoern A. Zeeb const u8 matrix[4][4] = { 1168*6c92544dSBjoern A. Zeeb {0, 0, 0, 0}, 1169*6c92544dSBjoern A. Zeeb {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */ 1170*6c92544dSBjoern A. Zeeb {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ 1171*6c92544dSBjoern A. Zeeb {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ 1172*6c92544dSBjoern A. Zeeb }; 1173*6c92544dSBjoern A. Zeeb bool ebf; 1174*6c92544dSBjoern A. Zeeb 1175*6c92544dSBjoern A. Zeeb if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) 1176*6c92544dSBjoern A. Zeeb return; 1177*6c92544dSBjoern A. Zeeb 1178*6c92544dSBjoern A. Zeeb ebf = mt7915_is_ebf_supported(phy, vif, sta, false); 1179*6c92544dSBjoern A. Zeeb if (!ebf && !dev->ibf) 1180*6c92544dSBjoern A. Zeeb return; 1181*6c92544dSBjoern A. Zeeb 1182*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); 1183*6c92544dSBjoern A. Zeeb bf = (struct sta_rec_bf *)tlv; 1184*6c92544dSBjoern A. Zeeb 1185*6c92544dSBjoern A. Zeeb /* he: eBF only, in accordance with spec 1186*6c92544dSBjoern A. Zeeb * vht: support eBF and iBF 1187*6c92544dSBjoern A. Zeeb * ht: iBF only, since mac80211 lacks of eBF support 1188*6c92544dSBjoern A. Zeeb */ 1189*6c92544dSBjoern A. Zeeb if (sta->deflink.he_cap.has_he && ebf) 1190*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); 1191*6c92544dSBjoern A. Zeeb else if (sta->deflink.vht_cap.vht_supported) 1192*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf); 1193*6c92544dSBjoern A. Zeeb else if (sta->deflink.ht_cap.ht_supported) 1194*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_ht(sta, phy, bf); 1195*6c92544dSBjoern A. Zeeb else 1196*6c92544dSBjoern A. Zeeb return; 1197*6c92544dSBjoern A. Zeeb 1198*6c92544dSBjoern A. Zeeb bf->bf_cap = ebf ? ebf : dev->ibf << 1; 1199*6c92544dSBjoern A. Zeeb bf->bw = sta->deflink.bandwidth; 1200*6c92544dSBjoern A. Zeeb bf->ibf_dbw = sta->deflink.bandwidth; 1201*6c92544dSBjoern A. Zeeb bf->ibf_nrow = tx_ant; 1202*6c92544dSBjoern A. Zeeb 1203*6c92544dSBjoern A. Zeeb if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) 1204*6c92544dSBjoern A. Zeeb bf->ibf_timeout = 0x48; 1205*6c92544dSBjoern A. Zeeb else 1206*6c92544dSBjoern A. Zeeb bf->ibf_timeout = 0x18; 1207*6c92544dSBjoern A. Zeeb 1208*6c92544dSBjoern A. Zeeb if (ebf && bf->nrow != tx_ant) 1209*6c92544dSBjoern A. Zeeb bf->mem_20m = matrix[tx_ant][bf->ncol]; 1210*6c92544dSBjoern A. Zeeb else 1211*6c92544dSBjoern A. Zeeb bf->mem_20m = matrix[bf->nrow][bf->ncol]; 1212*6c92544dSBjoern A. Zeeb 1213*6c92544dSBjoern A. Zeeb switch (sta->deflink.bandwidth) { 1214*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_160: 1215*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_80: 1216*6c92544dSBjoern A. Zeeb bf->mem_total = bf->mem_20m * 2; 1217*6c92544dSBjoern A. Zeeb break; 1218*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_40: 1219*6c92544dSBjoern A. Zeeb bf->mem_total = bf->mem_20m; 1220*6c92544dSBjoern A. Zeeb break; 1221*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_20: 1222*6c92544dSBjoern A. Zeeb default: 1223*6c92544dSBjoern A. Zeeb break; 1224*6c92544dSBjoern A. Zeeb } 1225*6c92544dSBjoern A. Zeeb } 1226*6c92544dSBjoern A. Zeeb 1227*6c92544dSBjoern A. Zeeb static void 1228*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 1229*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta) 1230*6c92544dSBjoern A. Zeeb { 1231*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1232*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy = mvif->phy; 1233*6c92544dSBjoern A. Zeeb int tx_ant = hweight8(phy->mt76->chainmask) - 1; 1234*6c92544dSBjoern A. Zeeb struct sta_rec_bfee *bfee; 1235*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1236*6c92544dSBjoern A. Zeeb u8 nrow = 0; 1237*6c92544dSBjoern A. Zeeb 1238*6c92544dSBjoern A. Zeeb if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he)) 1239*6c92544dSBjoern A. Zeeb return; 1240*6c92544dSBjoern A. Zeeb 1241*6c92544dSBjoern A. Zeeb if (!mt7915_is_ebf_supported(phy, vif, sta, true)) 1242*6c92544dSBjoern A. Zeeb return; 1243*6c92544dSBjoern A. Zeeb 1244*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); 1245*6c92544dSBjoern A. Zeeb bfee = (struct sta_rec_bfee *)tlv; 1246*6c92544dSBjoern A. Zeeb 1247*6c92544dSBjoern A. Zeeb if (sta->deflink.he_cap.has_he) { 1248*6c92544dSBjoern A. Zeeb struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; 1249*6c92544dSBjoern A. Zeeb 1250*6c92544dSBjoern A. Zeeb nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, 1251*6c92544dSBjoern A. Zeeb pe->phy_cap_info[5]); 1252*6c92544dSBjoern A. Zeeb } else if (sta->deflink.vht_cap.vht_supported) { 1253*6c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; 1254*6c92544dSBjoern A. Zeeb 1255*6c92544dSBjoern A. Zeeb nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, 1256*6c92544dSBjoern A. Zeeb pc->cap); 1257*6c92544dSBjoern A. Zeeb } 1258*6c92544dSBjoern A. Zeeb 1259*6c92544dSBjoern A. Zeeb /* reply with identity matrix to avoid 2x2 BF negative gain */ 1260*6c92544dSBjoern A. Zeeb bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); 1261*6c92544dSBjoern A. Zeeb } 1262*6c92544dSBjoern A. Zeeb 1263*6c92544dSBjoern A. Zeeb static enum mcu_mmps_mode 1264*6c92544dSBjoern A. Zeeb mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps) 1265*6c92544dSBjoern A. Zeeb { 1266*6c92544dSBjoern A. Zeeb switch (smps) { 1267*6c92544dSBjoern A. Zeeb case IEEE80211_SMPS_OFF: 1268*6c92544dSBjoern A. Zeeb return MCU_MMPS_DISABLE; 1269*6c92544dSBjoern A. Zeeb case IEEE80211_SMPS_STATIC: 1270*6c92544dSBjoern A. Zeeb return MCU_MMPS_STATIC; 1271*6c92544dSBjoern A. Zeeb case IEEE80211_SMPS_DYNAMIC: 1272*6c92544dSBjoern A. Zeeb return MCU_MMPS_DYNAMIC; 1273*6c92544dSBjoern A. Zeeb default: 1274*6c92544dSBjoern A. Zeeb return MCU_MMPS_DISABLE; 1275*6c92544dSBjoern A. Zeeb } 1276*6c92544dSBjoern A. Zeeb } 1277*6c92544dSBjoern A. Zeeb 1278*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, 1279*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, 1280*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, 1281*6c92544dSBjoern A. Zeeb void *data, u32 field) 1282*6c92544dSBjoern A. Zeeb { 1283*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1284*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 1285*6c92544dSBjoern A. Zeeb struct sta_phy *phy = data; 1286*6c92544dSBjoern A. Zeeb struct sta_rec_ra_fixed *ra; 1287*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 1288*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1289*6c92544dSBjoern A. Zeeb 1290*6c92544dSBjoern A. Zeeb skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 1291*6c92544dSBjoern A. Zeeb &msta->wcid); 1292*6c92544dSBjoern A. Zeeb if (IS_ERR(skb)) 1293*6c92544dSBjoern A. Zeeb return PTR_ERR(skb); 1294*6c92544dSBjoern A. Zeeb 1295*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); 1296*6c92544dSBjoern A. Zeeb ra = (struct sta_rec_ra_fixed *)tlv; 1297*6c92544dSBjoern A. Zeeb 1298*6c92544dSBjoern A. Zeeb switch (field) { 1299*6c92544dSBjoern A. Zeeb case RATE_PARAM_AUTO: 1300*6c92544dSBjoern A. Zeeb break; 1301*6c92544dSBjoern A. Zeeb case RATE_PARAM_FIXED: 1302*6c92544dSBjoern A. Zeeb case RATE_PARAM_FIXED_MCS: 1303*6c92544dSBjoern A. Zeeb case RATE_PARAM_FIXED_GI: 1304*6c92544dSBjoern A. Zeeb case RATE_PARAM_FIXED_HE_LTF: 1305*6c92544dSBjoern A. Zeeb if (phy) 1306*6c92544dSBjoern A. Zeeb ra->phy = *phy; 1307*6c92544dSBjoern A. Zeeb break; 1308*6c92544dSBjoern A. Zeeb case RATE_PARAM_MMPS_UPDATE: 1309*6c92544dSBjoern A. Zeeb ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode); 1310*6c92544dSBjoern A. Zeeb break; 1311*6c92544dSBjoern A. Zeeb default: 1312*6c92544dSBjoern A. Zeeb break; 1313*6c92544dSBjoern A. Zeeb } 1314*6c92544dSBjoern A. Zeeb ra->field = cpu_to_le32(field); 1315*6c92544dSBjoern A. Zeeb 1316*6c92544dSBjoern A. Zeeb return mt76_mcu_skb_send_msg(&dev->mt76, skb, 1317*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(STA_REC_UPDATE), true); 1318*6c92544dSBjoern A. Zeeb } 1319*6c92544dSBjoern A. Zeeb 1320*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1321*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 1322*6c92544dSBjoern A. Zeeb { 1323*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1324*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 1325*6c92544dSBjoern A. Zeeb struct wtbl_req_hdr *wtbl_hdr; 1326*6c92544dSBjoern A. Zeeb struct tlv *sta_wtbl; 1327*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 1328*6c92544dSBjoern A. Zeeb int ret; 1329*6c92544dSBjoern A. Zeeb 1330*6c92544dSBjoern A. Zeeb skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 1331*6c92544dSBjoern A. Zeeb &msta->wcid); 1332*6c92544dSBjoern A. Zeeb if (IS_ERR(skb)) 1333*6c92544dSBjoern A. Zeeb return PTR_ERR(skb); 1334*6c92544dSBjoern A. Zeeb 1335*6c92544dSBjoern A. Zeeb sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, 1336*6c92544dSBjoern A. Zeeb sizeof(struct tlv)); 1337*6c92544dSBjoern A. Zeeb wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, 1338*6c92544dSBjoern A. Zeeb WTBL_SET, sta_wtbl, &skb); 1339*6c92544dSBjoern A. Zeeb if (IS_ERR(wtbl_hdr)) 1340*6c92544dSBjoern A. Zeeb return PTR_ERR(wtbl_hdr); 1341*6c92544dSBjoern A. Zeeb 1342*6c92544dSBjoern A. Zeeb mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr); 1343*6c92544dSBjoern A. Zeeb 1344*6c92544dSBjoern A. Zeeb ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, 1345*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(STA_REC_UPDATE), true); 1346*6c92544dSBjoern A. Zeeb if (ret) 1347*6c92544dSBjoern A. Zeeb return ret; 1348*6c92544dSBjoern A. Zeeb 1349*6c92544dSBjoern A. Zeeb return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL, 1350*6c92544dSBjoern A. Zeeb RATE_PARAM_MMPS_UPDATE); 1351*6c92544dSBjoern A. Zeeb } 1352*6c92544dSBjoern A. Zeeb 1353*6c92544dSBjoern A. Zeeb static int 1354*6c92544dSBjoern A. Zeeb mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev, 1355*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, 1356*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 1357*6c92544dSBjoern A. Zeeb { 1358*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1359*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; 1360*6c92544dSBjoern A. Zeeb struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; 1361*6c92544dSBjoern A. Zeeb enum nl80211_band band = chandef->chan->band; 1362*6c92544dSBjoern A. Zeeb struct sta_phy phy = {}; 1363*6c92544dSBjoern A. Zeeb int ret, nrates = 0; 1364*6c92544dSBjoern A. Zeeb 1365*6c92544dSBjoern A. Zeeb #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ 1366*6c92544dSBjoern A. Zeeb do { \ 1367*6c92544dSBjoern A. Zeeb u8 i, gi = mask->control[band]._gi; \ 1368*6c92544dSBjoern A. Zeeb gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \ 1369*6c92544dSBjoern A. Zeeb for (i = 0; i <= sta->deflink.bandwidth; i++) { \ 1370*6c92544dSBjoern A. Zeeb phy.sgi |= gi << (i << (_he)); \ 1371*6c92544dSBjoern A. Zeeb phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\ 1372*6c92544dSBjoern A. Zeeb } \ 1373*6c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \ 1374*6c92544dSBjoern A. Zeeb if (!mask->control[band]._mcs[i]) \ 1375*6c92544dSBjoern A. Zeeb continue; \ 1376*6c92544dSBjoern A. Zeeb nrates += hweight16(mask->control[band]._mcs[i]); \ 1377*6c92544dSBjoern A. Zeeb phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \ 1378*6c92544dSBjoern A. Zeeb if (_ht) \ 1379*6c92544dSBjoern A. Zeeb phy.mcs += 8 * i; \ 1380*6c92544dSBjoern A. Zeeb } \ 1381*6c92544dSBjoern A. Zeeb } while (0) 1382*6c92544dSBjoern A. Zeeb 1383*6c92544dSBjoern A. Zeeb if (sta->deflink.he_cap.has_he) { 1384*6c92544dSBjoern A. Zeeb __sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1); 1385*6c92544dSBjoern A. Zeeb } else if (sta->deflink.vht_cap.vht_supported) { 1386*6c92544dSBjoern A. Zeeb __sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0); 1387*6c92544dSBjoern A. Zeeb } else if (sta->deflink.ht_cap.ht_supported) { 1388*6c92544dSBjoern A. Zeeb __sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0); 1389*6c92544dSBjoern A. Zeeb } else { 1390*6c92544dSBjoern A. Zeeb nrates = hweight32(mask->control[band].legacy); 1391*6c92544dSBjoern A. Zeeb phy.mcs = ffs(mask->control[band].legacy) - 1; 1392*6c92544dSBjoern A. Zeeb } 1393*6c92544dSBjoern A. Zeeb #undef __sta_phy_bitrate_mask_check 1394*6c92544dSBjoern A. Zeeb 1395*6c92544dSBjoern A. Zeeb /* fall back to auto rate control */ 1396*6c92544dSBjoern A. Zeeb if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI && 1397*6c92544dSBjoern A. Zeeb mask->control[band].he_gi == GENMASK(7, 0) && 1398*6c92544dSBjoern A. Zeeb mask->control[band].he_ltf == GENMASK(7, 0) && 1399*6c92544dSBjoern A. Zeeb nrates != 1) 1400*6c92544dSBjoern A. Zeeb return 0; 1401*6c92544dSBjoern A. Zeeb 1402*6c92544dSBjoern A. Zeeb /* fixed single rate */ 1403*6c92544dSBjoern A. Zeeb if (nrates == 1) { 1404*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, 1405*6c92544dSBjoern A. Zeeb RATE_PARAM_FIXED_MCS); 1406*6c92544dSBjoern A. Zeeb if (ret) 1407*6c92544dSBjoern A. Zeeb return ret; 1408*6c92544dSBjoern A. Zeeb } 1409*6c92544dSBjoern A. Zeeb 1410*6c92544dSBjoern A. Zeeb /* fixed GI */ 1411*6c92544dSBjoern A. Zeeb if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI || 1412*6c92544dSBjoern A. Zeeb mask->control[band].he_gi != GENMASK(7, 0)) { 1413*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 1414*6c92544dSBjoern A. Zeeb u32 addr; 1415*6c92544dSBjoern A. Zeeb 1416*6c92544dSBjoern A. Zeeb /* firmware updates only TXCMD but doesn't take WTBL into 1417*6c92544dSBjoern A. Zeeb * account, so driver should update here to reflect the 1418*6c92544dSBjoern A. Zeeb * actual txrate hardware sends out. 1419*6c92544dSBjoern A. Zeeb */ 1420*6c92544dSBjoern A. Zeeb addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7); 1421*6c92544dSBjoern A. Zeeb if (sta->deflink.he_cap.has_he) 1422*6c92544dSBjoern A. Zeeb mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi); 1423*6c92544dSBjoern A. Zeeb else 1424*6c92544dSBjoern A. Zeeb mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi); 1425*6c92544dSBjoern A. Zeeb 1426*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, 1427*6c92544dSBjoern A. Zeeb RATE_PARAM_FIXED_GI); 1428*6c92544dSBjoern A. Zeeb if (ret) 1429*6c92544dSBjoern A. Zeeb return ret; 1430*6c92544dSBjoern A. Zeeb } 1431*6c92544dSBjoern A. Zeeb 1432*6c92544dSBjoern A. Zeeb /* fixed HE_LTF */ 1433*6c92544dSBjoern A. Zeeb if (mask->control[band].he_ltf != GENMASK(7, 0)) { 1434*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, 1435*6c92544dSBjoern A. Zeeb RATE_PARAM_FIXED_HE_LTF); 1436*6c92544dSBjoern A. Zeeb if (ret) 1437*6c92544dSBjoern A. Zeeb return ret; 1438*6c92544dSBjoern A. Zeeb } 1439*6c92544dSBjoern A. Zeeb 1440*6c92544dSBjoern A. Zeeb return 0; 1441*6c92544dSBjoern A. Zeeb } 1442*6c92544dSBjoern A. Zeeb 1443*6c92544dSBjoern A. Zeeb static void 1444*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, 1445*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta) 1446*6c92544dSBjoern A. Zeeb { 1447*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1448*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = mvif->phy->mt76; 1449*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &mphy->chandef; 1450*6c92544dSBjoern A. Zeeb struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; 1451*6c92544dSBjoern A. Zeeb enum nl80211_band band = chandef->chan->band; 1452*6c92544dSBjoern A. Zeeb struct sta_rec_ra *ra; 1453*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1454*6c92544dSBjoern A. Zeeb u32 supp_rate = sta->deflink.supp_rates[band]; 1455*6c92544dSBjoern A. Zeeb u32 cap = sta->wme ? STA_CAP_WMM : 0; 1456*6c92544dSBjoern A. Zeeb 1457*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); 1458*6c92544dSBjoern A. Zeeb ra = (struct sta_rec_ra *)tlv; 1459*6c92544dSBjoern A. Zeeb 1460*6c92544dSBjoern A. Zeeb ra->valid = true; 1461*6c92544dSBjoern A. Zeeb ra->auto_rate = true; 1462*6c92544dSBjoern A. Zeeb ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta); 1463*6c92544dSBjoern A. Zeeb ra->channel = chandef->chan->hw_value; 1464*6c92544dSBjoern A. Zeeb ra->bw = sta->deflink.bandwidth; 1465*6c92544dSBjoern A. Zeeb ra->phy.bw = sta->deflink.bandwidth; 1466*6c92544dSBjoern A. Zeeb ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode); 1467*6c92544dSBjoern A. Zeeb 1468*6c92544dSBjoern A. Zeeb if (supp_rate) { 1469*6c92544dSBjoern A. Zeeb supp_rate &= mask->control[band].legacy; 1470*6c92544dSBjoern A. Zeeb ra->rate_len = hweight32(supp_rate); 1471*6c92544dSBjoern A. Zeeb 1472*6c92544dSBjoern A. Zeeb if (band == NL80211_BAND_2GHZ) { 1473*6c92544dSBjoern A. Zeeb ra->supp_mode = MODE_CCK; 1474*6c92544dSBjoern A. Zeeb ra->supp_cck_rate = supp_rate & GENMASK(3, 0); 1475*6c92544dSBjoern A. Zeeb 1476*6c92544dSBjoern A. Zeeb if (ra->rate_len > 4) { 1477*6c92544dSBjoern A. Zeeb ra->supp_mode |= MODE_OFDM; 1478*6c92544dSBjoern A. Zeeb ra->supp_ofdm_rate = supp_rate >> 4; 1479*6c92544dSBjoern A. Zeeb } 1480*6c92544dSBjoern A. Zeeb } else { 1481*6c92544dSBjoern A. Zeeb ra->supp_mode = MODE_OFDM; 1482*6c92544dSBjoern A. Zeeb ra->supp_ofdm_rate = supp_rate; 1483*6c92544dSBjoern A. Zeeb } 1484*6c92544dSBjoern A. Zeeb } 1485*6c92544dSBjoern A. Zeeb 1486*6c92544dSBjoern A. Zeeb if (sta->deflink.ht_cap.ht_supported) { 1487*6c92544dSBjoern A. Zeeb ra->supp_mode |= MODE_HT; 1488*6c92544dSBjoern A. Zeeb ra->af = sta->deflink.ht_cap.ampdu_factor; 1489*6c92544dSBjoern A. Zeeb ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); 1490*6c92544dSBjoern A. Zeeb 1491*6c92544dSBjoern A. Zeeb cap |= STA_CAP_HT; 1492*6c92544dSBjoern A. Zeeb if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) 1493*6c92544dSBjoern A. Zeeb cap |= STA_CAP_SGI_20; 1494*6c92544dSBjoern A. Zeeb if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) 1495*6c92544dSBjoern A. Zeeb cap |= STA_CAP_SGI_40; 1496*6c92544dSBjoern A. Zeeb if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) 1497*6c92544dSBjoern A. Zeeb cap |= STA_CAP_TX_STBC; 1498*6c92544dSBjoern A. Zeeb if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) 1499*6c92544dSBjoern A. Zeeb cap |= STA_CAP_RX_STBC; 1500*6c92544dSBjoern A. Zeeb if (mvif->cap.ht_ldpc && 1501*6c92544dSBjoern A. Zeeb (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) 1502*6c92544dSBjoern A. Zeeb cap |= STA_CAP_LDPC; 1503*6c92544dSBjoern A. Zeeb 1504*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, 1505*6c92544dSBjoern A. Zeeb mask->control[band].ht_mcs); 1506*6c92544dSBjoern A. Zeeb ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; 1507*6c92544dSBjoern A. Zeeb } 1508*6c92544dSBjoern A. Zeeb 1509*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported) { 1510*6c92544dSBjoern A. Zeeb u8 af; 1511*6c92544dSBjoern A. Zeeb 1512*6c92544dSBjoern A. Zeeb ra->supp_mode |= MODE_VHT; 1513*6c92544dSBjoern A. Zeeb af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, 1514*6c92544dSBjoern A. Zeeb sta->deflink.vht_cap.cap); 1515*6c92544dSBjoern A. Zeeb ra->af = max_t(u8, ra->af, af); 1516*6c92544dSBjoern A. Zeeb 1517*6c92544dSBjoern A. Zeeb cap |= STA_CAP_VHT; 1518*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) 1519*6c92544dSBjoern A. Zeeb cap |= STA_CAP_VHT_SGI_80; 1520*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) 1521*6c92544dSBjoern A. Zeeb cap |= STA_CAP_VHT_SGI_160; 1522*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) 1523*6c92544dSBjoern A. Zeeb cap |= STA_CAP_VHT_TX_STBC; 1524*6c92544dSBjoern A. Zeeb if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) 1525*6c92544dSBjoern A. Zeeb cap |= STA_CAP_VHT_RX_STBC; 1526*6c92544dSBjoern A. Zeeb if (mvif->cap.vht_ldpc && 1527*6c92544dSBjoern A. Zeeb (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) 1528*6c92544dSBjoern A. Zeeb cap |= STA_CAP_VHT_LDPC; 1529*6c92544dSBjoern A. Zeeb 1530*6c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, 1531*6c92544dSBjoern A. Zeeb mask->control[band].vht_mcs); 1532*6c92544dSBjoern A. Zeeb } 1533*6c92544dSBjoern A. Zeeb 1534*6c92544dSBjoern A. Zeeb if (sta->deflink.he_cap.has_he) { 1535*6c92544dSBjoern A. Zeeb ra->supp_mode |= MODE_HE; 1536*6c92544dSBjoern A. Zeeb cap |= STA_CAP_HE; 1537*6c92544dSBjoern A. Zeeb 1538*6c92544dSBjoern A. Zeeb if (sta->deflink.he_6ghz_capa.capa) 1539*6c92544dSBjoern A. Zeeb ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, 1540*6c92544dSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); 1541*6c92544dSBjoern A. Zeeb } 1542*6c92544dSBjoern A. Zeeb 1543*6c92544dSBjoern A. Zeeb ra->sta_cap = cpu_to_le32(cap); 1544*6c92544dSBjoern A. Zeeb } 1545*6c92544dSBjoern A. Zeeb 1546*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1547*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, bool changed) 1548*6c92544dSBjoern A. Zeeb { 1549*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1550*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 1551*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 1552*6c92544dSBjoern A. Zeeb int ret; 1553*6c92544dSBjoern A. Zeeb 1554*6c92544dSBjoern A. Zeeb skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 1555*6c92544dSBjoern A. Zeeb &msta->wcid); 1556*6c92544dSBjoern A. Zeeb if (IS_ERR(skb)) 1557*6c92544dSBjoern A. Zeeb return PTR_ERR(skb); 1558*6c92544dSBjoern A. Zeeb 1559*6c92544dSBjoern A. Zeeb /* firmware rc algorithm refers to sta_rec_he for HE control. 1560*6c92544dSBjoern A. Zeeb * once dev->rc_work changes the settings driver should also 1561*6c92544dSBjoern A. Zeeb * update sta_rec_he here. 1562*6c92544dSBjoern A. Zeeb */ 1563*6c92544dSBjoern A. Zeeb if (changed) 1564*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_he_tlv(skb, sta, vif); 1565*6c92544dSBjoern A. Zeeb 1566*6c92544dSBjoern A. Zeeb /* sta_rec_ra accommodates BW, NSS and only MCS range format 1567*6c92544dSBjoern A. Zeeb * i.e 0-{7,8,9} for VHT. 1568*6c92544dSBjoern A. Zeeb */ 1569*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); 1570*6c92544dSBjoern A. Zeeb 1571*6c92544dSBjoern A. Zeeb ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, 1572*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(STA_REC_UPDATE), true); 1573*6c92544dSBjoern A. Zeeb if (ret) 1574*6c92544dSBjoern A. Zeeb return ret; 1575*6c92544dSBjoern A. Zeeb 1576*6c92544dSBjoern A. Zeeb /* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE, 1577*6c92544dSBjoern A. Zeeb * and updates as peer fixed rate parameters, which overrides 1578*6c92544dSBjoern A. Zeeb * sta_rec_ra and firmware rate control algorithm. 1579*6c92544dSBjoern A. Zeeb */ 1580*6c92544dSBjoern A. Zeeb return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta); 1581*6c92544dSBjoern A. Zeeb } 1582*6c92544dSBjoern A. Zeeb 1583*6c92544dSBjoern A. Zeeb static int 1584*6c92544dSBjoern A. Zeeb mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1585*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 1586*6c92544dSBjoern A. Zeeb { 1587*6c92544dSBjoern A. Zeeb #define MT_STA_BSS_GROUP 1 1588*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1589*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta; 1590*6c92544dSBjoern A. Zeeb struct { 1591*6c92544dSBjoern A. Zeeb __le32 action; 1592*6c92544dSBjoern A. Zeeb u8 wlan_idx_lo; 1593*6c92544dSBjoern A. Zeeb u8 status; 1594*6c92544dSBjoern A. Zeeb u8 wlan_idx_hi; 1595*6c92544dSBjoern A. Zeeb u8 rsv0[5]; 1596*6c92544dSBjoern A. Zeeb __le32 val; 1597*6c92544dSBjoern A. Zeeb u8 rsv1[8]; 1598*6c92544dSBjoern A. Zeeb } __packed req = { 1599*6c92544dSBjoern A. Zeeb .action = cpu_to_le32(MT_STA_BSS_GROUP), 1600*6c92544dSBjoern A. Zeeb .val = cpu_to_le32(mvif->mt76.idx % 16), 1601*6c92544dSBjoern A. Zeeb }; 1602*6c92544dSBjoern A. Zeeb 1603*6c92544dSBjoern A. Zeeb msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; 1604*6c92544dSBjoern A. Zeeb req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx); 1605*6c92544dSBjoern A. Zeeb req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx); 1606*6c92544dSBjoern A. Zeeb 1607*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req, 1608*6c92544dSBjoern A. Zeeb sizeof(req), true); 1609*6c92544dSBjoern A. Zeeb } 1610*6c92544dSBjoern A. Zeeb 1611*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1612*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, bool enable) 1613*6c92544dSBjoern A. Zeeb { 1614*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1615*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta; 1616*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 1617*6c92544dSBjoern A. Zeeb int ret; 1618*6c92544dSBjoern A. Zeeb 1619*6c92544dSBjoern A. Zeeb msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; 1620*6c92544dSBjoern A. Zeeb 1621*6c92544dSBjoern A. Zeeb skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 1622*6c92544dSBjoern A. Zeeb &msta->wcid); 1623*6c92544dSBjoern A. Zeeb if (IS_ERR(skb)) 1624*6c92544dSBjoern A. Zeeb return PTR_ERR(skb); 1625*6c92544dSBjoern A. Zeeb 1626*6c92544dSBjoern A. Zeeb /* starec basic */ 1627*6c92544dSBjoern A. Zeeb mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable, 1628*6c92544dSBjoern A. Zeeb !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx])); 1629*6c92544dSBjoern A. Zeeb if (!enable) 1630*6c92544dSBjoern A. Zeeb goto out; 1631*6c92544dSBjoern A. Zeeb 1632*6c92544dSBjoern A. Zeeb /* tag order is in accordance with firmware dependency. */ 1633*6c92544dSBjoern A. Zeeb if (sta) { 1634*6c92544dSBjoern A. Zeeb /* starec bfer */ 1635*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta); 1636*6c92544dSBjoern A. Zeeb /* starec ht */ 1637*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_ht_tlv(skb, sta); 1638*6c92544dSBjoern A. Zeeb /* starec vht */ 1639*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_vht_tlv(skb, sta); 1640*6c92544dSBjoern A. Zeeb /* starec uapsd */ 1641*6c92544dSBjoern A. Zeeb mt76_connac_mcu_sta_uapsd(skb, vif, sta); 1642*6c92544dSBjoern A. Zeeb } 1643*6c92544dSBjoern A. Zeeb 1644*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta); 1645*6c92544dSBjoern A. Zeeb if (ret) { 1646*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 1647*6c92544dSBjoern A. Zeeb return ret; 1648*6c92544dSBjoern A. Zeeb } 1649*6c92544dSBjoern A. Zeeb 1650*6c92544dSBjoern A. Zeeb if (sta) { 1651*6c92544dSBjoern A. Zeeb /* starec amsdu */ 1652*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_amsdu_tlv(dev, skb, vif, sta); 1653*6c92544dSBjoern A. Zeeb /* starec he */ 1654*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_he_tlv(skb, sta, vif); 1655*6c92544dSBjoern A. Zeeb /* starec muru */ 1656*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif); 1657*6c92544dSBjoern A. Zeeb /* starec bfee */ 1658*6c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta); 1659*6c92544dSBjoern A. Zeeb } 1660*6c92544dSBjoern A. Zeeb 1661*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_add_group(dev, vif, sta); 1662*6c92544dSBjoern A. Zeeb if (ret) { 1663*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 1664*6c92544dSBjoern A. Zeeb return ret; 1665*6c92544dSBjoern A. Zeeb } 1666*6c92544dSBjoern A. Zeeb out: 1667*6c92544dSBjoern A. Zeeb return mt76_mcu_skb_send_msg(&dev->mt76, skb, 1668*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(STA_REC_UPDATE), true); 1669*6c92544dSBjoern A. Zeeb } 1670*6c92544dSBjoern A. Zeeb 1671*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, 1672*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, bool enable) 1673*6c92544dSBjoern A. Zeeb { 1674*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 1675*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1676*6c92544dSBjoern A. Zeeb struct { 1677*6c92544dSBjoern A. Zeeb struct req_hdr { 1678*6c92544dSBjoern A. Zeeb u8 omac_idx; 1679*6c92544dSBjoern A. Zeeb u8 dbdc_idx; 1680*6c92544dSBjoern A. Zeeb __le16 tlv_num; 1681*6c92544dSBjoern A. Zeeb u8 is_tlv_append; 1682*6c92544dSBjoern A. Zeeb u8 rsv[3]; 1683*6c92544dSBjoern A. Zeeb } __packed hdr; 1684*6c92544dSBjoern A. Zeeb struct req_tlv { 1685*6c92544dSBjoern A. Zeeb __le16 tag; 1686*6c92544dSBjoern A. Zeeb __le16 len; 1687*6c92544dSBjoern A. Zeeb u8 active; 1688*6c92544dSBjoern A. Zeeb u8 dbdc_idx; 1689*6c92544dSBjoern A. Zeeb u8 omac_addr[ETH_ALEN]; 1690*6c92544dSBjoern A. Zeeb } __packed tlv; 1691*6c92544dSBjoern A. Zeeb } data = { 1692*6c92544dSBjoern A. Zeeb .hdr = { 1693*6c92544dSBjoern A. Zeeb .omac_idx = mvif->mt76.omac_idx, 1694*6c92544dSBjoern A. Zeeb .dbdc_idx = mvif->mt76.band_idx, 1695*6c92544dSBjoern A. Zeeb .tlv_num = cpu_to_le16(1), 1696*6c92544dSBjoern A. Zeeb .is_tlv_append = 1, 1697*6c92544dSBjoern A. Zeeb }, 1698*6c92544dSBjoern A. Zeeb .tlv = { 1699*6c92544dSBjoern A. Zeeb .tag = cpu_to_le16(DEV_INFO_ACTIVE), 1700*6c92544dSBjoern A. Zeeb .len = cpu_to_le16(sizeof(struct req_tlv)), 1701*6c92544dSBjoern A. Zeeb .active = enable, 1702*6c92544dSBjoern A. Zeeb .dbdc_idx = mvif->mt76.band_idx, 1703*6c92544dSBjoern A. Zeeb }, 1704*6c92544dSBjoern A. Zeeb }; 1705*6c92544dSBjoern A. Zeeb 1706*6c92544dSBjoern A. Zeeb if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) 1707*6c92544dSBjoern A. Zeeb return mt7915_mcu_muar_config(phy, vif, false, enable); 1708*6c92544dSBjoern A. Zeeb 1709*6c92544dSBjoern A. Zeeb memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); 1710*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE), 1711*6c92544dSBjoern A. Zeeb &data, sizeof(data), true); 1712*6c92544dSBjoern A. Zeeb } 1713*6c92544dSBjoern A. Zeeb 1714*6c92544dSBjoern A. Zeeb static void 1715*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, 1716*6c92544dSBjoern A. Zeeb struct sk_buff *skb, struct bss_info_bcn *bcn, 1717*6c92544dSBjoern A. Zeeb struct ieee80211_mutable_offsets *offs) 1718*6c92544dSBjoern A. Zeeb { 1719*6c92544dSBjoern A. Zeeb struct bss_info_bcn_cntdwn *info; 1720*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1721*6c92544dSBjoern A. Zeeb int sub_tag; 1722*6c92544dSBjoern A. Zeeb 1723*6c92544dSBjoern A. Zeeb if (!offs->cntdwn_counter_offs[0]) 1724*6c92544dSBjoern A. Zeeb return; 1725*6c92544dSBjoern A. Zeeb 1726*6c92544dSBjoern A. Zeeb sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; 1727*6c92544dSBjoern A. Zeeb tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info), 1728*6c92544dSBjoern A. Zeeb &bcn->sub_ntlv, &bcn->len); 1729*6c92544dSBjoern A. Zeeb info = (struct bss_info_bcn_cntdwn *)tlv; 1730*6c92544dSBjoern A. Zeeb info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; 1731*6c92544dSBjoern A. Zeeb } 1732*6c92544dSBjoern A. Zeeb 1733*6c92544dSBjoern A. Zeeb static void 1734*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, 1735*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct bss_info_bcn *bcn, 1736*6c92544dSBjoern A. Zeeb struct ieee80211_mutable_offsets *offs) 1737*6c92544dSBjoern A. Zeeb { 1738*6c92544dSBjoern A. Zeeb struct bss_info_bcn_mbss *mbss; 1739*6c92544dSBjoern A. Zeeb const struct element *elem; 1740*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1741*6c92544dSBjoern A. Zeeb 1742*6c92544dSBjoern A. Zeeb if (!vif->bss_conf.bssid_indicator) 1743*6c92544dSBjoern A. Zeeb return; 1744*6c92544dSBjoern A. Zeeb 1745*6c92544dSBjoern A. Zeeb tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID, 1746*6c92544dSBjoern A. Zeeb sizeof(*mbss), &bcn->sub_ntlv, 1747*6c92544dSBjoern A. Zeeb &bcn->len); 1748*6c92544dSBjoern A. Zeeb 1749*6c92544dSBjoern A. Zeeb mbss = (struct bss_info_bcn_mbss *)tlv; 1750*6c92544dSBjoern A. Zeeb mbss->offset[0] = cpu_to_le16(offs->tim_offset); 1751*6c92544dSBjoern A. Zeeb mbss->bitmap = cpu_to_le32(1); 1752*6c92544dSBjoern A. Zeeb 1753*6c92544dSBjoern A. Zeeb for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, 1754*6c92544dSBjoern A. Zeeb &skb->data[offs->mbssid_off], 1755*6c92544dSBjoern A. Zeeb skb->len - offs->mbssid_off) { 1756*6c92544dSBjoern A. Zeeb const struct element *sub_elem; 1757*6c92544dSBjoern A. Zeeb 1758*6c92544dSBjoern A. Zeeb if (elem->datalen < 2) 1759*6c92544dSBjoern A. Zeeb continue; 1760*6c92544dSBjoern A. Zeeb 1761*6c92544dSBjoern A. Zeeb for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) { 1762*6c92544dSBjoern A. Zeeb const struct ieee80211_bssid_index *idx; 1763*6c92544dSBjoern A. Zeeb const u8 *idx_ie; 1764*6c92544dSBjoern A. Zeeb 1765*6c92544dSBjoern A. Zeeb if (sub_elem->id || sub_elem->datalen < 4) 1766*6c92544dSBjoern A. Zeeb continue; /* not a valid BSS profile */ 1767*6c92544dSBjoern A. Zeeb 1768*6c92544dSBjoern A. Zeeb /* Find WLAN_EID_MULTI_BSSID_IDX 1769*6c92544dSBjoern A. Zeeb * in the merged nontransmitted profile 1770*6c92544dSBjoern A. Zeeb */ 1771*6c92544dSBjoern A. Zeeb idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, 1772*6c92544dSBjoern A. Zeeb sub_elem->data, 1773*6c92544dSBjoern A. Zeeb sub_elem->datalen); 1774*6c92544dSBjoern A. Zeeb if (!idx_ie || idx_ie[1] < sizeof(*idx)) 1775*6c92544dSBjoern A. Zeeb continue; 1776*6c92544dSBjoern A. Zeeb 1777*6c92544dSBjoern A. Zeeb #if defined(__linux__) 1778*6c92544dSBjoern A. Zeeb idx = (void *)(idx_ie + 2); 1779*6c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 1780*6c92544dSBjoern A. Zeeb idx = (const void *)(idx_ie + 2); 1781*6c92544dSBjoern A. Zeeb #endif 1782*6c92544dSBjoern A. Zeeb if (!idx->bssid_index || idx->bssid_index > 31) 1783*6c92544dSBjoern A. Zeeb continue; 1784*6c92544dSBjoern A. Zeeb 1785*6c92544dSBjoern A. Zeeb mbss->offset[idx->bssid_index] = 1786*6c92544dSBjoern A. Zeeb cpu_to_le16(idx_ie - skb->data); 1787*6c92544dSBjoern A. Zeeb mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index)); 1788*6c92544dSBjoern A. Zeeb } 1789*6c92544dSBjoern A. Zeeb } 1790*6c92544dSBjoern A. Zeeb } 1791*6c92544dSBjoern A. Zeeb 1792*6c92544dSBjoern A. Zeeb static void 1793*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1794*6c92544dSBjoern A. Zeeb struct sk_buff *rskb, struct sk_buff *skb, 1795*6c92544dSBjoern A. Zeeb struct bss_info_bcn *bcn, 1796*6c92544dSBjoern A. Zeeb struct ieee80211_mutable_offsets *offs) 1797*6c92544dSBjoern A. Zeeb { 1798*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = &dev->mt76.global_wcid; 1799*6c92544dSBjoern A. Zeeb struct bss_info_bcn_cont *cont; 1800*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1801*6c92544dSBjoern A. Zeeb u8 *buf; 1802*6c92544dSBjoern A. Zeeb int len = sizeof(*cont) + MT_TXD_SIZE + skb->len; 1803*6c92544dSBjoern A. Zeeb 1804*6c92544dSBjoern A. Zeeb len = (len & 0x3) ? ((len | 0x3) + 1) : len; 1805*6c92544dSBjoern A. Zeeb tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT, 1806*6c92544dSBjoern A. Zeeb len, &bcn->sub_ntlv, &bcn->len); 1807*6c92544dSBjoern A. Zeeb 1808*6c92544dSBjoern A. Zeeb cont = (struct bss_info_bcn_cont *)tlv; 1809*6c92544dSBjoern A. Zeeb cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); 1810*6c92544dSBjoern A. Zeeb cont->tim_ofs = cpu_to_le16(offs->tim_offset); 1811*6c92544dSBjoern A. Zeeb 1812*6c92544dSBjoern A. Zeeb if (offs->cntdwn_counter_offs[0]) { 1813*6c92544dSBjoern A. Zeeb u16 offset = offs->cntdwn_counter_offs[0]; 1814*6c92544dSBjoern A. Zeeb 1815*6c92544dSBjoern A. Zeeb if (vif->bss_conf.csa_active) 1816*6c92544dSBjoern A. Zeeb cont->csa_ofs = cpu_to_le16(offset - 4); 1817*6c92544dSBjoern A. Zeeb if (vif->bss_conf.color_change_active) 1818*6c92544dSBjoern A. Zeeb cont->bcc_ofs = cpu_to_le16(offset - 3); 1819*6c92544dSBjoern A. Zeeb } 1820*6c92544dSBjoern A. Zeeb 1821*6c92544dSBjoern A. Zeeb buf = (u8 *)tlv + sizeof(*cont); 1822*6c92544dSBjoern A. Zeeb mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, 1823*6c92544dSBjoern A. Zeeb 0, BSS_CHANGED_BEACON); 1824*6c92544dSBjoern A. Zeeb memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); 1825*6c92544dSBjoern A. Zeeb } 1826*6c92544dSBjoern A. Zeeb 1827*6c92544dSBjoern A. Zeeb static void 1828*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif, 1829*6c92544dSBjoern A. Zeeb struct sk_buff *skb) 1830*6c92544dSBjoern A. Zeeb { 1831*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1832*6c92544dSBjoern A. Zeeb struct mt7915_vif_cap *vc = &mvif->cap; 1833*6c92544dSBjoern A. Zeeb const struct ieee80211_he_cap_elem *he; 1834*6c92544dSBjoern A. Zeeb const struct ieee80211_vht_cap *vht; 1835*6c92544dSBjoern A. Zeeb const struct ieee80211_ht_cap *ht; 1836*6c92544dSBjoern A. Zeeb struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 1837*6c92544dSBjoern A. Zeeb const u8 *ie; 1838*6c92544dSBjoern A. Zeeb u32 len, bc; 1839*6c92544dSBjoern A. Zeeb 1840*6c92544dSBjoern A. Zeeb /* Check missing configuration options to allow AP mode in mac80211 1841*6c92544dSBjoern A. Zeeb * to remain in sync with hostapd settings, and get a subset of 1842*6c92544dSBjoern A. Zeeb * beacon and hardware capabilities. 1843*6c92544dSBjoern A. Zeeb */ 1844*6c92544dSBjoern A. Zeeb if (WARN_ON_ONCE(skb->len <= (mgmt->u.beacon.variable - skb->data))) 1845*6c92544dSBjoern A. Zeeb return; 1846*6c92544dSBjoern A. Zeeb 1847*6c92544dSBjoern A. Zeeb memset(vc, 0, sizeof(*vc)); 1848*6c92544dSBjoern A. Zeeb 1849*6c92544dSBjoern A. Zeeb len = skb->len - (mgmt->u.beacon.variable - skb->data); 1850*6c92544dSBjoern A. Zeeb 1851*6c92544dSBjoern A. Zeeb ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, mgmt->u.beacon.variable, 1852*6c92544dSBjoern A. Zeeb len); 1853*6c92544dSBjoern A. Zeeb if (ie && ie[1] >= sizeof(*ht)) { 1854*6c92544dSBjoern A. Zeeb #if defined(__linux__) 1855*6c92544dSBjoern A. Zeeb ht = (void *)(ie + 2); 1856*6c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 1857*6c92544dSBjoern A. Zeeb ht = (const void *)(ie + 2); 1858*6c92544dSBjoern A. Zeeb #endif 1859*6c92544dSBjoern A. Zeeb vc->ht_ldpc = !!(le16_to_cpu(ht->cap_info) & 1860*6c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING); 1861*6c92544dSBjoern A. Zeeb } 1862*6c92544dSBjoern A. Zeeb 1863*6c92544dSBjoern A. Zeeb ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, mgmt->u.beacon.variable, 1864*6c92544dSBjoern A. Zeeb len); 1865*6c92544dSBjoern A. Zeeb if (ie && ie[1] >= sizeof(*vht)) { 1866*6c92544dSBjoern A. Zeeb u32 pc = phy->mt76->sband_5g.sband.vht_cap.cap; 1867*6c92544dSBjoern A. Zeeb 1868*6c92544dSBjoern A. Zeeb #if defined(__linux__) 1869*6c92544dSBjoern A. Zeeb vht = (void *)(ie + 2); 1870*6c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 1871*6c92544dSBjoern A. Zeeb vht = (const void *)(ie + 2); 1872*6c92544dSBjoern A. Zeeb #endif 1873*6c92544dSBjoern A. Zeeb bc = le32_to_cpu(vht->vht_cap_info); 1874*6c92544dSBjoern A. Zeeb 1875*6c92544dSBjoern A. Zeeb vc->vht_ldpc = !!(bc & IEEE80211_VHT_CAP_RXLDPC); 1876*6c92544dSBjoern A. Zeeb vc->vht_su_ebfer = 1877*6c92544dSBjoern A. Zeeb (bc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && 1878*6c92544dSBjoern A. Zeeb (pc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); 1879*6c92544dSBjoern A. Zeeb vc->vht_su_ebfee = 1880*6c92544dSBjoern A. Zeeb (bc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) && 1881*6c92544dSBjoern A. Zeeb (pc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); 1882*6c92544dSBjoern A. Zeeb vc->vht_mu_ebfer = 1883*6c92544dSBjoern A. Zeeb (bc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) && 1884*6c92544dSBjoern A. Zeeb (pc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); 1885*6c92544dSBjoern A. Zeeb vc->vht_mu_ebfee = 1886*6c92544dSBjoern A. Zeeb (bc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && 1887*6c92544dSBjoern A. Zeeb (pc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); 1888*6c92544dSBjoern A. Zeeb } 1889*6c92544dSBjoern A. Zeeb 1890*6c92544dSBjoern A. Zeeb ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, 1891*6c92544dSBjoern A. Zeeb mgmt->u.beacon.variable, len); 1892*6c92544dSBjoern A. Zeeb if (ie && ie[1] >= sizeof(*he) + 1) { 1893*6c92544dSBjoern A. Zeeb const struct ieee80211_sta_he_cap *pc = 1894*6c92544dSBjoern A. Zeeb mt76_connac_get_he_phy_cap(phy->mt76, vif); 1895*6c92544dSBjoern A. Zeeb const struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; 1896*6c92544dSBjoern A. Zeeb 1897*6c92544dSBjoern A. Zeeb #if defined(__linux__) 1898*6c92544dSBjoern A. Zeeb he = (void *)(ie + 3); 1899*6c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 1900*6c92544dSBjoern A. Zeeb he = (const void *)(ie + 3); 1901*6c92544dSBjoern A. Zeeb #endif 1902*6c92544dSBjoern A. Zeeb 1903*6c92544dSBjoern A. Zeeb vc->he_ldpc = 1904*6c92544dSBjoern A. Zeeb HE_PHY(CAP1_LDPC_CODING_IN_PAYLOAD, pe->phy_cap_info[1]); 1905*6c92544dSBjoern A. Zeeb vc->he_su_ebfer = 1906*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_SU_BEAMFORMER, he->phy_cap_info[3]) && 1907*6c92544dSBjoern A. Zeeb HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); 1908*6c92544dSBjoern A. Zeeb vc->he_su_ebfee = 1909*6c92544dSBjoern A. Zeeb HE_PHY(CAP4_SU_BEAMFORMEE, he->phy_cap_info[4]) && 1910*6c92544dSBjoern A. Zeeb HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); 1911*6c92544dSBjoern A. Zeeb vc->he_mu_ebfer = 1912*6c92544dSBjoern A. Zeeb HE_PHY(CAP4_MU_BEAMFORMER, he->phy_cap_info[4]) && 1913*6c92544dSBjoern A. Zeeb HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4]); 1914*6c92544dSBjoern A. Zeeb } 1915*6c92544dSBjoern A. Zeeb } 1916*6c92544dSBjoern A. Zeeb 1917*6c92544dSBjoern A. Zeeb static void 1918*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif, 1919*6c92544dSBjoern A. Zeeb struct sk_buff *rskb, struct bss_info_bcn *bcn, 1920*6c92544dSBjoern A. Zeeb u32 changed) 1921*6c92544dSBjoern A. Zeeb { 1922*6c92544dSBjoern A. Zeeb #define OFFLOAD_TX_MODE_SU BIT(0) 1923*6c92544dSBjoern A. Zeeb #define OFFLOAD_TX_MODE_MU BIT(1) 1924*6c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev); 1925*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy = mt7915_hw_phy(hw); 1926*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1927*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; 1928*6c92544dSBjoern A. Zeeb enum nl80211_band band = chandef->chan->band; 1929*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = &dev->mt76.global_wcid; 1930*6c92544dSBjoern A. Zeeb struct bss_info_inband_discovery *discov; 1931*6c92544dSBjoern A. Zeeb struct ieee80211_tx_info *info; 1932*6c92544dSBjoern A. Zeeb struct sk_buff *skb = NULL; 1933*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1934*6c92544dSBjoern A. Zeeb bool ext_phy = phy != &dev->phy; 1935*6c92544dSBjoern A. Zeeb u8 *buf, interval; 1936*6c92544dSBjoern A. Zeeb int len; 1937*6c92544dSBjoern A. Zeeb 1938*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_FILS_DISCOVERY && 1939*6c92544dSBjoern A. Zeeb vif->bss_conf.fils_discovery.max_interval) { 1940*6c92544dSBjoern A. Zeeb interval = vif->bss_conf.fils_discovery.max_interval; 1941*6c92544dSBjoern A. Zeeb skb = ieee80211_get_fils_discovery_tmpl(hw, vif); 1942*6c92544dSBjoern A. Zeeb } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP && 1943*6c92544dSBjoern A. Zeeb vif->bss_conf.unsol_bcast_probe_resp_interval) { 1944*6c92544dSBjoern A. Zeeb interval = vif->bss_conf.unsol_bcast_probe_resp_interval; 1945*6c92544dSBjoern A. Zeeb skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif); 1946*6c92544dSBjoern A. Zeeb } 1947*6c92544dSBjoern A. Zeeb 1948*6c92544dSBjoern A. Zeeb if (!skb) 1949*6c92544dSBjoern A. Zeeb return; 1950*6c92544dSBjoern A. Zeeb 1951*6c92544dSBjoern A. Zeeb info = IEEE80211_SKB_CB(skb); 1952*6c92544dSBjoern A. Zeeb info->control.vif = vif; 1953*6c92544dSBjoern A. Zeeb info->band = band; 1954*6c92544dSBjoern A. Zeeb 1955*6c92544dSBjoern A. Zeeb info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy); 1956*6c92544dSBjoern A. Zeeb 1957*6c92544dSBjoern A. Zeeb len = sizeof(*discov) + MT_TXD_SIZE + skb->len; 1958*6c92544dSBjoern A. Zeeb len = (len & 0x3) ? ((len | 0x3) + 1) : len; 1959*6c92544dSBjoern A. Zeeb 1960*6c92544dSBjoern A. Zeeb if (len > (MT7915_MAX_BSS_OFFLOAD_SIZE - rskb->len)) { 1961*6c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "inband discovery size limit exceed\n"); 1962*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 1963*6c92544dSBjoern A. Zeeb return; 1964*6c92544dSBjoern A. Zeeb } 1965*6c92544dSBjoern A. Zeeb 1966*6c92544dSBjoern A. Zeeb tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV, 1967*6c92544dSBjoern A. Zeeb len, &bcn->sub_ntlv, &bcn->len); 1968*6c92544dSBjoern A. Zeeb discov = (struct bss_info_inband_discovery *)tlv; 1969*6c92544dSBjoern A. Zeeb discov->tx_mode = OFFLOAD_TX_MODE_SU; 1970*6c92544dSBjoern A. Zeeb /* 0: UNSOL PROBE RESP, 1: FILS DISCOV */ 1971*6c92544dSBjoern A. Zeeb discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY); 1972*6c92544dSBjoern A. Zeeb discov->tx_interval = interval; 1973*6c92544dSBjoern A. Zeeb discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len); 1974*6c92544dSBjoern A. Zeeb discov->enable = true; 1975*6c92544dSBjoern A. Zeeb 1976*6c92544dSBjoern A. Zeeb buf = (u8 *)tlv + sizeof(*discov); 1977*6c92544dSBjoern A. Zeeb 1978*6c92544dSBjoern A. Zeeb mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, 1979*6c92544dSBjoern A. Zeeb 0, changed); 1980*6c92544dSBjoern A. Zeeb memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); 1981*6c92544dSBjoern A. Zeeb 1982*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 1983*6c92544dSBjoern A. Zeeb } 1984*6c92544dSBjoern A. Zeeb 1985*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1986*6c92544dSBjoern A. Zeeb int en, u32 changed) 1987*6c92544dSBjoern A. Zeeb { 1988*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = mt7915_hw_dev(hw); 1989*6c92544dSBjoern A. Zeeb struct mt7915_phy *phy = mt7915_hw_phy(hw); 1990*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 1991*6c92544dSBjoern A. Zeeb struct ieee80211_mutable_offsets offs; 1992*6c92544dSBjoern A. Zeeb struct ieee80211_tx_info *info; 1993*6c92544dSBjoern A. Zeeb struct sk_buff *skb, *rskb; 1994*6c92544dSBjoern A. Zeeb struct tlv *tlv; 1995*6c92544dSBjoern A. Zeeb struct bss_info_bcn *bcn; 1996*6c92544dSBjoern A. Zeeb int len = MT7915_MAX_BSS_OFFLOAD_SIZE; 1997*6c92544dSBjoern A. Zeeb bool ext_phy = phy != &dev->phy; 1998*6c92544dSBjoern A. Zeeb 1999*6c92544dSBjoern A. Zeeb if (vif->bss_conf.nontransmitted) 2000*6c92544dSBjoern A. Zeeb return 0; 2001*6c92544dSBjoern A. Zeeb 2002*6c92544dSBjoern A. Zeeb rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 2003*6c92544dSBjoern A. Zeeb NULL, len); 2004*6c92544dSBjoern A. Zeeb if (IS_ERR(rskb)) 2005*6c92544dSBjoern A. Zeeb return PTR_ERR(rskb); 2006*6c92544dSBjoern A. Zeeb 2007*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn)); 2008*6c92544dSBjoern A. Zeeb bcn = (struct bss_info_bcn *)tlv; 2009*6c92544dSBjoern A. Zeeb bcn->enable = en; 2010*6c92544dSBjoern A. Zeeb 2011*6c92544dSBjoern A. Zeeb if (!en) 2012*6c92544dSBjoern A. Zeeb goto out; 2013*6c92544dSBjoern A. Zeeb 2014*6c92544dSBjoern A. Zeeb skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); 2015*6c92544dSBjoern A. Zeeb if (!skb) 2016*6c92544dSBjoern A. Zeeb return -EINVAL; 2017*6c92544dSBjoern A. Zeeb 2018*6c92544dSBjoern A. Zeeb if (skb->len > MT7915_MAX_BEACON_SIZE - MT_TXD_SIZE) { 2019*6c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); 2020*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 2021*6c92544dSBjoern A. Zeeb return -EINVAL; 2022*6c92544dSBjoern A. Zeeb } 2023*6c92544dSBjoern A. Zeeb 2024*6c92544dSBjoern A. Zeeb info = IEEE80211_SKB_CB(skb); 2025*6c92544dSBjoern A. Zeeb info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy); 2026*6c92544dSBjoern A. Zeeb 2027*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_check_caps(phy, vif, skb); 2028*6c92544dSBjoern A. Zeeb 2029*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs); 2030*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs); 2031*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs); 2032*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 2033*6c92544dSBjoern A. Zeeb 2034*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP || 2035*6c92544dSBjoern A. Zeeb changed & BSS_CHANGED_FILS_DISCOVERY) 2036*6c92544dSBjoern A. Zeeb mt7915_mcu_beacon_inband_discov(dev, vif, rskb, 2037*6c92544dSBjoern A. Zeeb bcn, changed); 2038*6c92544dSBjoern A. Zeeb 2039*6c92544dSBjoern A. Zeeb out: 2040*6c92544dSBjoern A. Zeeb return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, 2041*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(BSS_INFO_UPDATE), true); 2042*6c92544dSBjoern A. Zeeb } 2043*6c92544dSBjoern A. Zeeb 2044*6c92544dSBjoern A. Zeeb static int mt7915_driver_own(struct mt7915_dev *dev, u8 band) 2045*6c92544dSBjoern A. Zeeb { 2046*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN); 2047*6c92544dSBjoern A. Zeeb if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band), 2048*6c92544dSBjoern A. Zeeb MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) { 2049*6c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Timeout for driver own\n"); 2050*6c92544dSBjoern A. Zeeb return -EIO; 2051*6c92544dSBjoern A. Zeeb } 2052*6c92544dSBjoern A. Zeeb 2053*6c92544dSBjoern A. Zeeb /* clear irq when the driver own success */ 2054*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band), 2055*6c92544dSBjoern A. Zeeb MT_TOP_LPCR_HOST_BAND_STAT); 2056*6c92544dSBjoern A. Zeeb 2057*6c92544dSBjoern A. Zeeb return 0; 2058*6c92544dSBjoern A. Zeeb } 2059*6c92544dSBjoern A. Zeeb 2060*6c92544dSBjoern A. Zeeb static int 2061*6c92544dSBjoern A. Zeeb mt7915_firmware_state(struct mt7915_dev *dev, bool wa) 2062*6c92544dSBjoern A. Zeeb { 2063*6c92544dSBjoern A. Zeeb u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, 2064*6c92544dSBjoern A. Zeeb wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD); 2065*6c92544dSBjoern A. Zeeb 2066*6c92544dSBjoern A. Zeeb if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE, 2067*6c92544dSBjoern A. Zeeb state, 1000)) { 2068*6c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); 2069*6c92544dSBjoern A. Zeeb return -EIO; 2070*6c92544dSBjoern A. Zeeb } 2071*6c92544dSBjoern A. Zeeb return 0; 2072*6c92544dSBjoern A. Zeeb } 2073*6c92544dSBjoern A. Zeeb 2074*6c92544dSBjoern A. Zeeb static int mt7915_load_firmware(struct mt7915_dev *dev) 2075*6c92544dSBjoern A. Zeeb { 2076*6c92544dSBjoern A. Zeeb int ret; 2077*6c92544dSBjoern A. Zeeb 2078*6c92544dSBjoern A. Zeeb /* make sure fw is download state */ 2079*6c92544dSBjoern A. Zeeb if (mt7915_firmware_state(dev, false)) { 2080*6c92544dSBjoern A. Zeeb /* restart firmware once */ 2081*6c92544dSBjoern A. Zeeb __mt76_mcu_restart(&dev->mt76); 2082*6c92544dSBjoern A. Zeeb ret = mt7915_firmware_state(dev, false); 2083*6c92544dSBjoern A. Zeeb if (ret) { 2084*6c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, 2085*6c92544dSBjoern A. Zeeb "Firmware is not ready for download\n"); 2086*6c92544dSBjoern A. Zeeb return ret; 2087*6c92544dSBjoern A. Zeeb } 2088*6c92544dSBjoern A. Zeeb } 2089*6c92544dSBjoern A. Zeeb 2090*6c92544dSBjoern A. Zeeb ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH)); 2091*6c92544dSBjoern A. Zeeb if (ret) 2092*6c92544dSBjoern A. Zeeb return ret; 2093*6c92544dSBjoern A. Zeeb 2094*6c92544dSBjoern A. Zeeb ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM), 2095*6c92544dSBjoern A. Zeeb fw_name(dev, FIRMWARE_WA)); 2096*6c92544dSBjoern A. Zeeb if (ret) 2097*6c92544dSBjoern A. Zeeb return ret; 2098*6c92544dSBjoern A. Zeeb 2099*6c92544dSBjoern A. Zeeb ret = mt7915_firmware_state(dev, true); 2100*6c92544dSBjoern A. Zeeb if (ret) 2101*6c92544dSBjoern A. Zeeb return ret; 2102*6c92544dSBjoern A. Zeeb 2103*6c92544dSBjoern A. Zeeb mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); 2104*6c92544dSBjoern A. Zeeb 2105*6c92544dSBjoern A. Zeeb dev_dbg(dev->mt76.dev, "Firmware init done\n"); 2106*6c92544dSBjoern A. Zeeb 2107*6c92544dSBjoern A. Zeeb return 0; 2108*6c92544dSBjoern A. Zeeb } 2109*6c92544dSBjoern A. Zeeb 2110*6c92544dSBjoern A. Zeeb int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl) 2111*6c92544dSBjoern A. Zeeb { 2112*6c92544dSBjoern A. Zeeb struct { 2113*6c92544dSBjoern A. Zeeb u8 ctrl_val; 2114*6c92544dSBjoern A. Zeeb u8 pad[3]; 2115*6c92544dSBjoern A. Zeeb } data = { 2116*6c92544dSBjoern A. Zeeb .ctrl_val = ctrl 2117*6c92544dSBjoern A. Zeeb }; 2118*6c92544dSBjoern A. Zeeb 2119*6c92544dSBjoern A. Zeeb if (type == MCU_FW_LOG_WA) 2120*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(FW_LOG_2_HOST), 2121*6c92544dSBjoern A. Zeeb &data, sizeof(data), true); 2122*6c92544dSBjoern A. Zeeb 2123*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data, 2124*6c92544dSBjoern A. Zeeb sizeof(data), true); 2125*6c92544dSBjoern A. Zeeb } 2126*6c92544dSBjoern A. Zeeb 2127*6c92544dSBjoern A. Zeeb int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level) 2128*6c92544dSBjoern A. Zeeb { 2129*6c92544dSBjoern A. Zeeb struct { 2130*6c92544dSBjoern A. Zeeb u8 ver; 2131*6c92544dSBjoern A. Zeeb u8 pad; 2132*6c92544dSBjoern A. Zeeb __le16 len; 2133*6c92544dSBjoern A. Zeeb u8 level; 2134*6c92544dSBjoern A. Zeeb u8 rsv[3]; 2135*6c92544dSBjoern A. Zeeb __le32 module_idx; 2136*6c92544dSBjoern A. Zeeb } data = { 2137*6c92544dSBjoern A. Zeeb .module_idx = cpu_to_le32(module), 2138*6c92544dSBjoern A. Zeeb .level = level, 2139*6c92544dSBjoern A. Zeeb }; 2140*6c92544dSBjoern A. Zeeb 2141*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data, 2142*6c92544dSBjoern A. Zeeb sizeof(data), false); 2143*6c92544dSBjoern A. Zeeb } 2144*6c92544dSBjoern A. Zeeb 2145*6c92544dSBjoern A. Zeeb int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled) 2146*6c92544dSBjoern A. Zeeb { 2147*6c92544dSBjoern A. Zeeb struct { 2148*6c92544dSBjoern A. Zeeb __le32 cmd; 2149*6c92544dSBjoern A. Zeeb u8 enable; 2150*6c92544dSBjoern A. Zeeb } data = { 2151*6c92544dSBjoern A. Zeeb .cmd = cpu_to_le32(MURU_SET_TXC_TX_STATS_EN), 2152*6c92544dSBjoern A. Zeeb .enable = enabled, 2153*6c92544dSBjoern A. Zeeb }; 2154*6c92544dSBjoern A. Zeeb 2155*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &data, 2156*6c92544dSBjoern A. Zeeb sizeof(data), false); 2157*6c92544dSBjoern A. Zeeb } 2158*6c92544dSBjoern A. Zeeb 2159*6c92544dSBjoern A. Zeeb int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms) 2160*6c92544dSBjoern A. Zeeb { 2161*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 2162*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 2163*6c92544dSBjoern A. Zeeb struct mt7915_mcu_muru_stats *mu_stats = 2164*6c92544dSBjoern A. Zeeb (struct mt7915_mcu_muru_stats *)ms; 2165*6c92544dSBjoern A. Zeeb int ret; 2166*6c92544dSBjoern A. Zeeb 2167*6c92544dSBjoern A. Zeeb struct { 2168*6c92544dSBjoern A. Zeeb __le32 cmd; 2169*6c92544dSBjoern A. Zeeb u8 band_idx; 2170*6c92544dSBjoern A. Zeeb } req = { 2171*6c92544dSBjoern A. Zeeb .cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS), 2172*6c92544dSBjoern A. Zeeb .band_idx = phy->band_idx, 2173*6c92544dSBjoern A. Zeeb }; 2174*6c92544dSBjoern A. Zeeb 2175*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), 2176*6c92544dSBjoern A. Zeeb &req, sizeof(req), true, &skb); 2177*6c92544dSBjoern A. Zeeb if (ret) 2178*6c92544dSBjoern A. Zeeb return ret; 2179*6c92544dSBjoern A. Zeeb 2180*6c92544dSBjoern A. Zeeb memcpy(mu_stats, skb->data, sizeof(struct mt7915_mcu_muru_stats)); 2181*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 2182*6c92544dSBjoern A. Zeeb 2183*6c92544dSBjoern A. Zeeb return 0; 2184*6c92544dSBjoern A. Zeeb } 2185*6c92544dSBjoern A. Zeeb 2186*6c92544dSBjoern A. Zeeb static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled) 2187*6c92544dSBjoern A. Zeeb { 2188*6c92544dSBjoern A. Zeeb struct { 2189*6c92544dSBjoern A. Zeeb u8 enable; 2190*6c92544dSBjoern A. Zeeb u8 _rsv[3]; 2191*6c92544dSBjoern A. Zeeb } __packed req = { 2192*6c92544dSBjoern A. Zeeb .enable = enabled 2193*6c92544dSBjoern A. Zeeb }; 2194*6c92544dSBjoern A. Zeeb 2195*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req, 2196*6c92544dSBjoern A. Zeeb sizeof(req), false); 2197*6c92544dSBjoern A. Zeeb } 2198*6c92544dSBjoern A. Zeeb 2199*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val) 2200*6c92544dSBjoern A. Zeeb { 2201*6c92544dSBjoern A. Zeeb struct { 2202*6c92544dSBjoern A. Zeeb __le32 cmd; 2203*6c92544dSBjoern A. Zeeb u8 val[4]; 2204*6c92544dSBjoern A. Zeeb } __packed req = { 2205*6c92544dSBjoern A. Zeeb .cmd = cpu_to_le32(cmd), 2206*6c92544dSBjoern A. Zeeb }; 2207*6c92544dSBjoern A. Zeeb 2208*6c92544dSBjoern A. Zeeb put_unaligned_le32(val, req.val); 2209*6c92544dSBjoern A. Zeeb 2210*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req, 2211*6c92544dSBjoern A. Zeeb sizeof(req), false); 2212*6c92544dSBjoern A. Zeeb } 2213*6c92544dSBjoern A. Zeeb 2214*6c92544dSBjoern A. Zeeb static int 2215*6c92544dSBjoern A. Zeeb mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) 2216*6c92544dSBjoern A. Zeeb { 2217*6c92544dSBjoern A. Zeeb #define RX_AIRTIME_FEATURE_CTRL 1 2218*6c92544dSBjoern A. Zeeb #define RX_AIRTIME_BITWISE_CTRL 2 2219*6c92544dSBjoern A. Zeeb #define RX_AIRTIME_CLEAR_EN 1 2220*6c92544dSBjoern A. Zeeb struct { 2221*6c92544dSBjoern A. Zeeb __le16 field; 2222*6c92544dSBjoern A. Zeeb __le16 sub_field; 2223*6c92544dSBjoern A. Zeeb __le32 set_status; 2224*6c92544dSBjoern A. Zeeb __le32 get_status; 2225*6c92544dSBjoern A. Zeeb u8 _rsv[12]; 2226*6c92544dSBjoern A. Zeeb 2227*6c92544dSBjoern A. Zeeb bool airtime_en; 2228*6c92544dSBjoern A. Zeeb bool mibtime_en; 2229*6c92544dSBjoern A. Zeeb bool earlyend_en; 2230*6c92544dSBjoern A. Zeeb u8 _rsv1[9]; 2231*6c92544dSBjoern A. Zeeb 2232*6c92544dSBjoern A. Zeeb bool airtime_clear; 2233*6c92544dSBjoern A. Zeeb bool mibtime_clear; 2234*6c92544dSBjoern A. Zeeb u8 _rsv2[98]; 2235*6c92544dSBjoern A. Zeeb } __packed req = { 2236*6c92544dSBjoern A. Zeeb .field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL), 2237*6c92544dSBjoern A. Zeeb .sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN), 2238*6c92544dSBjoern A. Zeeb .airtime_clear = true, 2239*6c92544dSBjoern A. Zeeb }; 2240*6c92544dSBjoern A. Zeeb int ret; 2241*6c92544dSBjoern A. Zeeb 2242*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req, 2243*6c92544dSBjoern A. Zeeb sizeof(req), true); 2244*6c92544dSBjoern A. Zeeb if (ret) 2245*6c92544dSBjoern A. Zeeb return ret; 2246*6c92544dSBjoern A. Zeeb 2247*6c92544dSBjoern A. Zeeb req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL); 2248*6c92544dSBjoern A. Zeeb req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN); 2249*6c92544dSBjoern A. Zeeb req.airtime_en = true; 2250*6c92544dSBjoern A. Zeeb 2251*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req, 2252*6c92544dSBjoern A. Zeeb sizeof(req), true); 2253*6c92544dSBjoern A. Zeeb } 2254*6c92544dSBjoern A. Zeeb 2255*6c92544dSBjoern A. Zeeb int mt7915_mcu_init(struct mt7915_dev *dev) 2256*6c92544dSBjoern A. Zeeb { 2257*6c92544dSBjoern A. Zeeb static const struct mt76_mcu_ops mt7915_mcu_ops = { 2258*6c92544dSBjoern A. Zeeb .headroom = sizeof(struct mt76_connac2_mcu_txd), 2259*6c92544dSBjoern A. Zeeb .mcu_skb_send_msg = mt7915_mcu_send_message, 2260*6c92544dSBjoern A. Zeeb .mcu_parse_response = mt7915_mcu_parse_response, 2261*6c92544dSBjoern A. Zeeb .mcu_restart = mt76_connac_mcu_restart, 2262*6c92544dSBjoern A. Zeeb }; 2263*6c92544dSBjoern A. Zeeb int ret; 2264*6c92544dSBjoern A. Zeeb 2265*6c92544dSBjoern A. Zeeb dev->mt76.mcu_ops = &mt7915_mcu_ops; 2266*6c92544dSBjoern A. Zeeb 2267*6c92544dSBjoern A. Zeeb /* force firmware operation mode into normal state, 2268*6c92544dSBjoern A. Zeeb * which should be set before firmware download stage. 2269*6c92544dSBjoern A. Zeeb */ 2270*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); 2271*6c92544dSBjoern A. Zeeb 2272*6c92544dSBjoern A. Zeeb ret = mt7915_driver_own(dev, 0); 2273*6c92544dSBjoern A. Zeeb if (ret) 2274*6c92544dSBjoern A. Zeeb return ret; 2275*6c92544dSBjoern A. Zeeb /* set driver own for band1 when two hif exist */ 2276*6c92544dSBjoern A. Zeeb if (dev->hif2) { 2277*6c92544dSBjoern A. Zeeb ret = mt7915_driver_own(dev, 1); 2278*6c92544dSBjoern A. Zeeb if (ret) 2279*6c92544dSBjoern A. Zeeb return ret; 2280*6c92544dSBjoern A. Zeeb } 2281*6c92544dSBjoern A. Zeeb 2282*6c92544dSBjoern A. Zeeb ret = mt7915_load_firmware(dev); 2283*6c92544dSBjoern A. Zeeb if (ret) 2284*6c92544dSBjoern A. Zeeb return ret; 2285*6c92544dSBjoern A. Zeeb 2286*6c92544dSBjoern A. Zeeb set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 2287*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0); 2288*6c92544dSBjoern A. Zeeb if (ret) 2289*6c92544dSBjoern A. Zeeb return ret; 2290*6c92544dSBjoern A. Zeeb 2291*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); 2292*6c92544dSBjoern A. Zeeb if (ret) 2293*6c92544dSBjoern A. Zeeb return ret; 2294*6c92544dSBjoern A. Zeeb 2295*6c92544dSBjoern A. Zeeb if (mtk_wed_device_active(&dev->mt76.mmio.wed)) 2296*6c92544dSBjoern A. Zeeb mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0); 2297*6c92544dSBjoern A. Zeeb 2298*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_mwds(dev, 1); 2299*6c92544dSBjoern A. Zeeb if (ret) 2300*6c92544dSBjoern A. Zeeb return ret; 2301*6c92544dSBjoern A. Zeeb 2302*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE, 2303*6c92544dSBjoern A. Zeeb MURU_PLATFORM_TYPE_PERF_LEVEL_2); 2304*6c92544dSBjoern A. Zeeb if (ret) 2305*6c92544dSBjoern A. Zeeb return ret; 2306*6c92544dSBjoern A. Zeeb 2307*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_init_rx_airtime(dev); 2308*6c92544dSBjoern A. Zeeb if (ret) 2309*6c92544dSBjoern A. Zeeb return ret; 2310*6c92544dSBjoern A. Zeeb 2311*6c92544dSBjoern A. Zeeb return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), 2312*6c92544dSBjoern A. Zeeb MCU_WA_PARAM_RED, 0, 0); 2313*6c92544dSBjoern A. Zeeb } 2314*6c92544dSBjoern A. Zeeb 2315*6c92544dSBjoern A. Zeeb void mt7915_mcu_exit(struct mt7915_dev *dev) 2316*6c92544dSBjoern A. Zeeb { 2317*6c92544dSBjoern A. Zeeb __mt76_mcu_restart(&dev->mt76); 2318*6c92544dSBjoern A. Zeeb if (mt7915_firmware_state(dev, false)) { 2319*6c92544dSBjoern A. Zeeb dev_err(dev->mt76.dev, "Failed to exit mcu\n"); 2320*6c92544dSBjoern A. Zeeb return; 2321*6c92544dSBjoern A. Zeeb } 2322*6c92544dSBjoern A. Zeeb 2323*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN); 2324*6c92544dSBjoern A. Zeeb if (dev->hif2) 2325*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1), 2326*6c92544dSBjoern A. Zeeb MT_TOP_LPCR_HOST_FW_OWN); 2327*6c92544dSBjoern A. Zeeb skb_queue_purge(&dev->mt76.mcu.res_q); 2328*6c92544dSBjoern A. Zeeb } 2329*6c92544dSBjoern A. Zeeb 2330*6c92544dSBjoern A. Zeeb static int 2331*6c92544dSBjoern A. Zeeb mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band) 2332*6c92544dSBjoern A. Zeeb { 2333*6c92544dSBjoern A. Zeeb struct { 2334*6c92544dSBjoern A. Zeeb u8 operation; 2335*6c92544dSBjoern A. Zeeb u8 count; 2336*6c92544dSBjoern A. Zeeb u8 _rsv[2]; 2337*6c92544dSBjoern A. Zeeb u8 index; 2338*6c92544dSBjoern A. Zeeb u8 enable; 2339*6c92544dSBjoern A. Zeeb __le16 etype; 2340*6c92544dSBjoern A. Zeeb } req = { 2341*6c92544dSBjoern A. Zeeb .operation = 1, 2342*6c92544dSBjoern A. Zeeb .count = 1, 2343*6c92544dSBjoern A. Zeeb .enable = 1, 2344*6c92544dSBjoern A. Zeeb .etype = cpu_to_le16(ETH_P_PAE), 2345*6c92544dSBjoern A. Zeeb }; 2346*6c92544dSBjoern A. Zeeb 2347*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS), 2348*6c92544dSBjoern A. Zeeb &req, sizeof(req), false); 2349*6c92544dSBjoern A. Zeeb } 2350*6c92544dSBjoern A. Zeeb 2351*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, 2352*6c92544dSBjoern A. Zeeb bool enable, bool hdr_trans) 2353*6c92544dSBjoern A. Zeeb { 2354*6c92544dSBjoern A. Zeeb struct { 2355*6c92544dSBjoern A. Zeeb u8 operation; 2356*6c92544dSBjoern A. Zeeb u8 enable; 2357*6c92544dSBjoern A. Zeeb u8 check_bssid; 2358*6c92544dSBjoern A. Zeeb u8 insert_vlan; 2359*6c92544dSBjoern A. Zeeb u8 remove_vlan; 2360*6c92544dSBjoern A. Zeeb u8 tid; 2361*6c92544dSBjoern A. Zeeb u8 mode; 2362*6c92544dSBjoern A. Zeeb u8 rsv; 2363*6c92544dSBjoern A. Zeeb } __packed req_trans = { 2364*6c92544dSBjoern A. Zeeb .enable = hdr_trans, 2365*6c92544dSBjoern A. Zeeb }; 2366*6c92544dSBjoern A. Zeeb struct { 2367*6c92544dSBjoern A. Zeeb u8 enable; 2368*6c92544dSBjoern A. Zeeb u8 band; 2369*6c92544dSBjoern A. Zeeb u8 rsv[2]; 2370*6c92544dSBjoern A. Zeeb } __packed req_mac = { 2371*6c92544dSBjoern A. Zeeb .enable = enable, 2372*6c92544dSBjoern A. Zeeb .band = band, 2373*6c92544dSBjoern A. Zeeb }; 2374*6c92544dSBjoern A. Zeeb int ret; 2375*6c92544dSBjoern A. Zeeb 2376*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS), 2377*6c92544dSBjoern A. Zeeb &req_trans, sizeof(req_trans), false); 2378*6c92544dSBjoern A. Zeeb if (ret) 2379*6c92544dSBjoern A. Zeeb return ret; 2380*6c92544dSBjoern A. Zeeb 2381*6c92544dSBjoern A. Zeeb if (hdr_trans) 2382*6c92544dSBjoern A. Zeeb mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band); 2383*6c92544dSBjoern A. Zeeb 2384*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL), 2385*6c92544dSBjoern A. Zeeb &req_mac, sizeof(req_mac), true); 2386*6c92544dSBjoern A. Zeeb } 2387*6c92544dSBjoern A. Zeeb 2388*6c92544dSBjoern A. Zeeb int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param) 2389*6c92544dSBjoern A. Zeeb { 2390*6c92544dSBjoern A. Zeeb struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param; 2391*6c92544dSBjoern A. Zeeb u8 num = req->total; 2392*6c92544dSBjoern A. Zeeb size_t len = sizeof(*req) - 2393*6c92544dSBjoern A. Zeeb (IEEE80211_NUM_ACS - num) * sizeof(struct edca); 2394*6c92544dSBjoern A. Zeeb 2395*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req, 2396*6c92544dSBjoern A. Zeeb len, true); 2397*6c92544dSBjoern A. Zeeb } 2398*6c92544dSBjoern A. Zeeb 2399*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) 2400*6c92544dSBjoern A. Zeeb { 2401*6c92544dSBjoern A. Zeeb #define TX_CMD_MODE 1 2402*6c92544dSBjoern A. Zeeb struct mt7915_mcu_tx req = { 2403*6c92544dSBjoern A. Zeeb .valid = true, 2404*6c92544dSBjoern A. Zeeb .mode = TX_CMD_MODE, 2405*6c92544dSBjoern A. Zeeb .total = IEEE80211_NUM_ACS, 2406*6c92544dSBjoern A. Zeeb }; 2407*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 2408*6c92544dSBjoern A. Zeeb int ac; 2409*6c92544dSBjoern A. Zeeb 2410*6c92544dSBjoern A. Zeeb for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 2411*6c92544dSBjoern A. Zeeb struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; 2412*6c92544dSBjoern A. Zeeb struct edca *e = &req.edca[ac]; 2413*6c92544dSBjoern A. Zeeb 2414*6c92544dSBjoern A. Zeeb e->set = WMM_PARAM_SET; 2415*6c92544dSBjoern A. Zeeb e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; 2416*6c92544dSBjoern A. Zeeb e->aifs = q->aifs; 2417*6c92544dSBjoern A. Zeeb e->txop = cpu_to_le16(q->txop); 2418*6c92544dSBjoern A. Zeeb 2419*6c92544dSBjoern A. Zeeb if (q->cw_min) 2420*6c92544dSBjoern A. Zeeb e->cw_min = fls(q->cw_min); 2421*6c92544dSBjoern A. Zeeb else 2422*6c92544dSBjoern A. Zeeb e->cw_min = 5; 2423*6c92544dSBjoern A. Zeeb 2424*6c92544dSBjoern A. Zeeb if (q->cw_max) 2425*6c92544dSBjoern A. Zeeb e->cw_max = cpu_to_le16(fls(q->cw_max)); 2426*6c92544dSBjoern A. Zeeb else 2427*6c92544dSBjoern A. Zeeb e->cw_max = cpu_to_le16(10); 2428*6c92544dSBjoern A. Zeeb } 2429*6c92544dSBjoern A. Zeeb 2430*6c92544dSBjoern A. Zeeb return mt7915_mcu_update_edca(dev, &req); 2431*6c92544dSBjoern A. Zeeb } 2432*6c92544dSBjoern A. Zeeb 2433*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val) 2434*6c92544dSBjoern A. Zeeb { 2435*6c92544dSBjoern A. Zeeb struct { 2436*6c92544dSBjoern A. Zeeb __le32 tag; 2437*6c92544dSBjoern A. Zeeb __le16 min_lpn; 2438*6c92544dSBjoern A. Zeeb u8 rsv[2]; 2439*6c92544dSBjoern A. Zeeb } __packed req = { 2440*6c92544dSBjoern A. Zeeb .tag = cpu_to_le32(0x1), 2441*6c92544dSBjoern A. Zeeb .min_lpn = cpu_to_le16(val), 2442*6c92544dSBjoern A. Zeeb }; 2443*6c92544dSBjoern A. Zeeb 2444*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, 2445*6c92544dSBjoern A. Zeeb sizeof(req), true); 2446*6c92544dSBjoern A. Zeeb } 2447*6c92544dSBjoern A. Zeeb 2448*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, 2449*6c92544dSBjoern A. Zeeb const struct mt7915_dfs_pulse *pulse) 2450*6c92544dSBjoern A. Zeeb { 2451*6c92544dSBjoern A. Zeeb struct { 2452*6c92544dSBjoern A. Zeeb __le32 tag; 2453*6c92544dSBjoern A. Zeeb 2454*6c92544dSBjoern A. Zeeb __le32 max_width; /* us */ 2455*6c92544dSBjoern A. Zeeb __le32 max_pwr; /* dbm */ 2456*6c92544dSBjoern A. Zeeb __le32 min_pwr; /* dbm */ 2457*6c92544dSBjoern A. Zeeb __le32 min_stgr_pri; /* us */ 2458*6c92544dSBjoern A. Zeeb __le32 max_stgr_pri; /* us */ 2459*6c92544dSBjoern A. Zeeb __le32 min_cr_pri; /* us */ 2460*6c92544dSBjoern A. Zeeb __le32 max_cr_pri; /* us */ 2461*6c92544dSBjoern A. Zeeb } __packed req = { 2462*6c92544dSBjoern A. Zeeb .tag = cpu_to_le32(0x3), 2463*6c92544dSBjoern A. Zeeb 2464*6c92544dSBjoern A. Zeeb #define __req_field(field) .field = cpu_to_le32(pulse->field) 2465*6c92544dSBjoern A. Zeeb __req_field(max_width), 2466*6c92544dSBjoern A. Zeeb __req_field(max_pwr), 2467*6c92544dSBjoern A. Zeeb __req_field(min_pwr), 2468*6c92544dSBjoern A. Zeeb __req_field(min_stgr_pri), 2469*6c92544dSBjoern A. Zeeb __req_field(max_stgr_pri), 2470*6c92544dSBjoern A. Zeeb __req_field(min_cr_pri), 2471*6c92544dSBjoern A. Zeeb __req_field(max_cr_pri), 2472*6c92544dSBjoern A. Zeeb #undef __req_field 2473*6c92544dSBjoern A. Zeeb }; 2474*6c92544dSBjoern A. Zeeb 2475*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, 2476*6c92544dSBjoern A. Zeeb sizeof(req), true); 2477*6c92544dSBjoern A. Zeeb } 2478*6c92544dSBjoern A. Zeeb 2479*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, 2480*6c92544dSBjoern A. Zeeb const struct mt7915_dfs_pattern *pattern) 2481*6c92544dSBjoern A. Zeeb { 2482*6c92544dSBjoern A. Zeeb struct { 2483*6c92544dSBjoern A. Zeeb __le32 tag; 2484*6c92544dSBjoern A. Zeeb __le16 radar_type; 2485*6c92544dSBjoern A. Zeeb 2486*6c92544dSBjoern A. Zeeb u8 enb; 2487*6c92544dSBjoern A. Zeeb u8 stgr; 2488*6c92544dSBjoern A. Zeeb u8 min_crpn; 2489*6c92544dSBjoern A. Zeeb u8 max_crpn; 2490*6c92544dSBjoern A. Zeeb u8 min_crpr; 2491*6c92544dSBjoern A. Zeeb u8 min_pw; 2492*6c92544dSBjoern A. Zeeb __le32 min_pri; 2493*6c92544dSBjoern A. Zeeb __le32 max_pri; 2494*6c92544dSBjoern A. Zeeb u8 max_pw; 2495*6c92544dSBjoern A. Zeeb u8 min_crbn; 2496*6c92544dSBjoern A. Zeeb u8 max_crbn; 2497*6c92544dSBjoern A. Zeeb u8 min_stgpn; 2498*6c92544dSBjoern A. Zeeb u8 max_stgpn; 2499*6c92544dSBjoern A. Zeeb u8 min_stgpr; 2500*6c92544dSBjoern A. Zeeb u8 rsv[2]; 2501*6c92544dSBjoern A. Zeeb __le32 min_stgpr_diff; 2502*6c92544dSBjoern A. Zeeb } __packed req = { 2503*6c92544dSBjoern A. Zeeb .tag = cpu_to_le32(0x2), 2504*6c92544dSBjoern A. Zeeb .radar_type = cpu_to_le16(index), 2505*6c92544dSBjoern A. Zeeb 2506*6c92544dSBjoern A. Zeeb #define __req_field_u8(field) .field = pattern->field 2507*6c92544dSBjoern A. Zeeb #define __req_field_u32(field) .field = cpu_to_le32(pattern->field) 2508*6c92544dSBjoern A. Zeeb __req_field_u8(enb), 2509*6c92544dSBjoern A. Zeeb __req_field_u8(stgr), 2510*6c92544dSBjoern A. Zeeb __req_field_u8(min_crpn), 2511*6c92544dSBjoern A. Zeeb __req_field_u8(max_crpn), 2512*6c92544dSBjoern A. Zeeb __req_field_u8(min_crpr), 2513*6c92544dSBjoern A. Zeeb __req_field_u8(min_pw), 2514*6c92544dSBjoern A. Zeeb __req_field_u32(min_pri), 2515*6c92544dSBjoern A. Zeeb __req_field_u32(max_pri), 2516*6c92544dSBjoern A. Zeeb __req_field_u8(max_pw), 2517*6c92544dSBjoern A. Zeeb __req_field_u8(min_crbn), 2518*6c92544dSBjoern A. Zeeb __req_field_u8(max_crbn), 2519*6c92544dSBjoern A. Zeeb __req_field_u8(min_stgpn), 2520*6c92544dSBjoern A. Zeeb __req_field_u8(max_stgpn), 2521*6c92544dSBjoern A. Zeeb __req_field_u8(min_stgpr), 2522*6c92544dSBjoern A. Zeeb __req_field_u32(min_stgpr_diff), 2523*6c92544dSBjoern A. Zeeb #undef __req_field_u8 2524*6c92544dSBjoern A. Zeeb #undef __req_field_u32 2525*6c92544dSBjoern A. Zeeb }; 2526*6c92544dSBjoern A. Zeeb 2527*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, 2528*6c92544dSBjoern A. Zeeb sizeof(req), true); 2529*6c92544dSBjoern A. Zeeb } 2530*6c92544dSBjoern A. Zeeb 2531*6c92544dSBjoern A. Zeeb static int 2532*6c92544dSBjoern A. Zeeb mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy, 2533*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef, 2534*6c92544dSBjoern A. Zeeb int cmd) 2535*6c92544dSBjoern A. Zeeb { 2536*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 2537*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = phy->mt76; 2538*6c92544dSBjoern A. Zeeb struct ieee80211_channel *chan = mphy->chandef.chan; 2539*6c92544dSBjoern A. Zeeb int freq = mphy->chandef.center_freq1; 2540*6c92544dSBjoern A. Zeeb struct mt7915_mcu_background_chain_ctrl req = { 2541*6c92544dSBjoern A. Zeeb .monitor_scan_type = 2, /* simple rx */ 2542*6c92544dSBjoern A. Zeeb }; 2543*6c92544dSBjoern A. Zeeb 2544*6c92544dSBjoern A. Zeeb if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP) 2545*6c92544dSBjoern A. Zeeb return -EINVAL; 2546*6c92544dSBjoern A. Zeeb 2547*6c92544dSBjoern A. Zeeb if (!cfg80211_chandef_valid(&mphy->chandef)) 2548*6c92544dSBjoern A. Zeeb return -EINVAL; 2549*6c92544dSBjoern A. Zeeb 2550*6c92544dSBjoern A. Zeeb switch (cmd) { 2551*6c92544dSBjoern A. Zeeb case CH_SWITCH_BACKGROUND_SCAN_START: { 2552*6c92544dSBjoern A. Zeeb req.chan = chan->hw_value; 2553*6c92544dSBjoern A. Zeeb req.central_chan = ieee80211_frequency_to_channel(freq); 2554*6c92544dSBjoern A. Zeeb req.bw = mt76_connac_chan_bw(&mphy->chandef); 2555*6c92544dSBjoern A. Zeeb req.monitor_chan = chandef->chan->hw_value; 2556*6c92544dSBjoern A. Zeeb req.monitor_central_chan = 2557*6c92544dSBjoern A. Zeeb ieee80211_frequency_to_channel(chandef->center_freq1); 2558*6c92544dSBjoern A. Zeeb req.monitor_bw = mt76_connac_chan_bw(chandef); 2559*6c92544dSBjoern A. Zeeb req.band_idx = phy != &dev->phy; 2560*6c92544dSBjoern A. Zeeb req.scan_mode = 1; 2561*6c92544dSBjoern A. Zeeb break; 2562*6c92544dSBjoern A. Zeeb } 2563*6c92544dSBjoern A. Zeeb case CH_SWITCH_BACKGROUND_SCAN_RUNNING: 2564*6c92544dSBjoern A. Zeeb req.monitor_chan = chandef->chan->hw_value; 2565*6c92544dSBjoern A. Zeeb req.monitor_central_chan = 2566*6c92544dSBjoern A. Zeeb ieee80211_frequency_to_channel(chandef->center_freq1); 2567*6c92544dSBjoern A. Zeeb req.band_idx = phy != &dev->phy; 2568*6c92544dSBjoern A. Zeeb req.scan_mode = 2; 2569*6c92544dSBjoern A. Zeeb break; 2570*6c92544dSBjoern A. Zeeb case CH_SWITCH_BACKGROUND_SCAN_STOP: 2571*6c92544dSBjoern A. Zeeb req.chan = chan->hw_value; 2572*6c92544dSBjoern A. Zeeb req.central_chan = ieee80211_frequency_to_channel(freq); 2573*6c92544dSBjoern A. Zeeb req.bw = mt76_connac_chan_bw(&mphy->chandef); 2574*6c92544dSBjoern A. Zeeb req.tx_stream = hweight8(mphy->antenna_mask); 2575*6c92544dSBjoern A. Zeeb req.rx_stream = mphy->antenna_mask; 2576*6c92544dSBjoern A. Zeeb break; 2577*6c92544dSBjoern A. Zeeb default: 2578*6c92544dSBjoern A. Zeeb return -EINVAL; 2579*6c92544dSBjoern A. Zeeb } 2580*6c92544dSBjoern A. Zeeb req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1; 2581*6c92544dSBjoern A. Zeeb 2582*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL), 2583*6c92544dSBjoern A. Zeeb &req, sizeof(req), false); 2584*6c92544dSBjoern A. Zeeb } 2585*6c92544dSBjoern A. Zeeb 2586*6c92544dSBjoern A. Zeeb int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy, 2587*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef) 2588*6c92544dSBjoern A. Zeeb { 2589*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 2590*6c92544dSBjoern A. Zeeb int err, region; 2591*6c92544dSBjoern A. Zeeb 2592*6c92544dSBjoern A. Zeeb if (!chandef) { /* disable offchain */ 2593*6c92544dSBjoern A. Zeeb err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2, 2594*6c92544dSBjoern A. Zeeb 0, 0); 2595*6c92544dSBjoern A. Zeeb if (err) 2596*6c92544dSBjoern A. Zeeb return err; 2597*6c92544dSBjoern A. Zeeb 2598*6c92544dSBjoern A. Zeeb return mt7915_mcu_background_chain_ctrl(phy, NULL, 2599*6c92544dSBjoern A. Zeeb CH_SWITCH_BACKGROUND_SCAN_STOP); 2600*6c92544dSBjoern A. Zeeb } 2601*6c92544dSBjoern A. Zeeb 2602*6c92544dSBjoern A. Zeeb err = mt7915_mcu_background_chain_ctrl(phy, chandef, 2603*6c92544dSBjoern A. Zeeb CH_SWITCH_BACKGROUND_SCAN_START); 2604*6c92544dSBjoern A. Zeeb if (err) 2605*6c92544dSBjoern A. Zeeb return err; 2606*6c92544dSBjoern A. Zeeb 2607*6c92544dSBjoern A. Zeeb switch (dev->mt76.region) { 2608*6c92544dSBjoern A. Zeeb case NL80211_DFS_ETSI: 2609*6c92544dSBjoern A. Zeeb region = 0; 2610*6c92544dSBjoern A. Zeeb break; 2611*6c92544dSBjoern A. Zeeb case NL80211_DFS_JP: 2612*6c92544dSBjoern A. Zeeb region = 2; 2613*6c92544dSBjoern A. Zeeb break; 2614*6c92544dSBjoern A. Zeeb case NL80211_DFS_FCC: 2615*6c92544dSBjoern A. Zeeb default: 2616*6c92544dSBjoern A. Zeeb region = 1; 2617*6c92544dSBjoern A. Zeeb break; 2618*6c92544dSBjoern A. Zeeb } 2619*6c92544dSBjoern A. Zeeb 2620*6c92544dSBjoern A. Zeeb return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2, 2621*6c92544dSBjoern A. Zeeb 0, region); 2622*6c92544dSBjoern A. Zeeb } 2623*6c92544dSBjoern A. Zeeb 2624*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) 2625*6c92544dSBjoern A. Zeeb { 2626*6c92544dSBjoern A. Zeeb static const u8 ch_band[] = { 2627*6c92544dSBjoern A. Zeeb [NL80211_BAND_2GHZ] = 0, 2628*6c92544dSBjoern A. Zeeb [NL80211_BAND_5GHZ] = 1, 2629*6c92544dSBjoern A. Zeeb [NL80211_BAND_6GHZ] = 2, 2630*6c92544dSBjoern A. Zeeb }; 2631*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 2632*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 2633*6c92544dSBjoern A. Zeeb int freq1 = chandef->center_freq1; 2634*6c92544dSBjoern A. Zeeb struct { 2635*6c92544dSBjoern A. Zeeb u8 control_ch; 2636*6c92544dSBjoern A. Zeeb u8 center_ch; 2637*6c92544dSBjoern A. Zeeb u8 bw; 2638*6c92544dSBjoern A. Zeeb u8 tx_streams_num; 2639*6c92544dSBjoern A. Zeeb u8 rx_streams; /* mask or num */ 2640*6c92544dSBjoern A. Zeeb u8 switch_reason; 2641*6c92544dSBjoern A. Zeeb u8 band_idx; 2642*6c92544dSBjoern A. Zeeb u8 center_ch2; /* for 80+80 only */ 2643*6c92544dSBjoern A. Zeeb __le16 cac_case; 2644*6c92544dSBjoern A. Zeeb u8 channel_band; 2645*6c92544dSBjoern A. Zeeb u8 rsv0; 2646*6c92544dSBjoern A. Zeeb __le32 outband_freq; 2647*6c92544dSBjoern A. Zeeb u8 txpower_drop; 2648*6c92544dSBjoern A. Zeeb u8 ap_bw; 2649*6c92544dSBjoern A. Zeeb u8 ap_center_ch; 2650*6c92544dSBjoern A. Zeeb u8 rsv1[57]; 2651*6c92544dSBjoern A. Zeeb } __packed req = { 2652*6c92544dSBjoern A. Zeeb .control_ch = chandef->chan->hw_value, 2653*6c92544dSBjoern A. Zeeb .center_ch = ieee80211_frequency_to_channel(freq1), 2654*6c92544dSBjoern A. Zeeb .bw = mt76_connac_chan_bw(chandef), 2655*6c92544dSBjoern A. Zeeb .tx_streams_num = hweight8(phy->mt76->antenna_mask), 2656*6c92544dSBjoern A. Zeeb .rx_streams = phy->mt76->antenna_mask, 2657*6c92544dSBjoern A. Zeeb .band_idx = phy->band_idx, 2658*6c92544dSBjoern A. Zeeb .channel_band = ch_band[chandef->chan->band], 2659*6c92544dSBjoern A. Zeeb }; 2660*6c92544dSBjoern A. Zeeb 2661*6c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE 2662*6c92544dSBjoern A. Zeeb if (phy->mt76->test.tx_antenna_mask && 2663*6c92544dSBjoern A. Zeeb (phy->mt76->test.state == MT76_TM_STATE_TX_FRAMES || 2664*6c92544dSBjoern A. Zeeb phy->mt76->test.state == MT76_TM_STATE_RX_FRAMES || 2665*6c92544dSBjoern A. Zeeb phy->mt76->test.state == MT76_TM_STATE_TX_CONT)) { 2666*6c92544dSBjoern A. Zeeb req.tx_streams_num = fls(phy->mt76->test.tx_antenna_mask); 2667*6c92544dSBjoern A. Zeeb req.rx_streams = phy->mt76->test.tx_antenna_mask; 2668*6c92544dSBjoern A. Zeeb 2669*6c92544dSBjoern A. Zeeb if (phy != &dev->phy) 2670*6c92544dSBjoern A. Zeeb req.rx_streams >>= dev->chainshift; 2671*6c92544dSBjoern A. Zeeb } 2672*6c92544dSBjoern A. Zeeb #endif 2673*6c92544dSBjoern A. Zeeb 2674*6c92544dSBjoern A. Zeeb if (cmd == MCU_EXT_CMD(SET_RX_PATH) || 2675*6c92544dSBjoern A. Zeeb dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) 2676*6c92544dSBjoern A. Zeeb req.switch_reason = CH_SWITCH_NORMAL; 2677*6c92544dSBjoern A. Zeeb else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) 2678*6c92544dSBjoern A. Zeeb req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; 2679*6c92544dSBjoern A. Zeeb else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, 2680*6c92544dSBjoern A. Zeeb NL80211_IFTYPE_AP)) 2681*6c92544dSBjoern A. Zeeb req.switch_reason = CH_SWITCH_DFS; 2682*6c92544dSBjoern A. Zeeb else 2683*6c92544dSBjoern A. Zeeb req.switch_reason = CH_SWITCH_NORMAL; 2684*6c92544dSBjoern A. Zeeb 2685*6c92544dSBjoern A. Zeeb if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) 2686*6c92544dSBjoern A. Zeeb req.rx_streams = hweight8(req.rx_streams); 2687*6c92544dSBjoern A. Zeeb 2688*6c92544dSBjoern A. Zeeb if (chandef->width == NL80211_CHAN_WIDTH_80P80) { 2689*6c92544dSBjoern A. Zeeb int freq2 = chandef->center_freq2; 2690*6c92544dSBjoern A. Zeeb 2691*6c92544dSBjoern A. Zeeb req.center_ch2 = ieee80211_frequency_to_channel(freq2); 2692*6c92544dSBjoern A. Zeeb } 2693*6c92544dSBjoern A. Zeeb 2694*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); 2695*6c92544dSBjoern A. Zeeb } 2696*6c92544dSBjoern A. Zeeb 2697*6c92544dSBjoern A. Zeeb static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev) 2698*6c92544dSBjoern A. Zeeb { 2699*6c92544dSBjoern A. Zeeb #define MAX_PAGE_IDX_MASK GENMASK(7, 5) 2700*6c92544dSBjoern A. Zeeb #define PAGE_IDX_MASK GENMASK(4, 2) 2701*6c92544dSBjoern A. Zeeb #define PER_PAGE_SIZE 0x400 2702*6c92544dSBjoern A. Zeeb struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER }; 2703*6c92544dSBjoern A. Zeeb u16 eeprom_size = mt7915_eeprom_size(dev); 2704*6c92544dSBjoern A. Zeeb u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); 2705*6c92544dSBjoern A. Zeeb u8 *eep = (u8 *)dev->mt76.eeprom.data; 2706*6c92544dSBjoern A. Zeeb int eep_len; 2707*6c92544dSBjoern A. Zeeb int i; 2708*6c92544dSBjoern A. Zeeb 2709*6c92544dSBjoern A. Zeeb for (i = 0; i < total; i++, eep += eep_len) { 2710*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 2711*6c92544dSBjoern A. Zeeb int ret; 2712*6c92544dSBjoern A. Zeeb 2713*6c92544dSBjoern A. Zeeb if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) 2714*6c92544dSBjoern A. Zeeb eep_len = eeprom_size % PER_PAGE_SIZE; 2715*6c92544dSBjoern A. Zeeb else 2716*6c92544dSBjoern A. Zeeb eep_len = PER_PAGE_SIZE; 2717*6c92544dSBjoern A. Zeeb 2718*6c92544dSBjoern A. Zeeb skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, 2719*6c92544dSBjoern A. Zeeb sizeof(req) + eep_len); 2720*6c92544dSBjoern A. Zeeb if (!skb) 2721*6c92544dSBjoern A. Zeeb return -ENOMEM; 2722*6c92544dSBjoern A. Zeeb 2723*6c92544dSBjoern A. Zeeb req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) | 2724*6c92544dSBjoern A. Zeeb FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE; 2725*6c92544dSBjoern A. Zeeb req.len = cpu_to_le16(eep_len); 2726*6c92544dSBjoern A. Zeeb 2727*6c92544dSBjoern A. Zeeb skb_put_data(skb, &req, sizeof(req)); 2728*6c92544dSBjoern A. Zeeb skb_put_data(skb, eep, eep_len); 2729*6c92544dSBjoern A. Zeeb 2730*6c92544dSBjoern A. Zeeb ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, 2731*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(EFUSE_BUFFER_MODE), true); 2732*6c92544dSBjoern A. Zeeb if (ret) 2733*6c92544dSBjoern A. Zeeb return ret; 2734*6c92544dSBjoern A. Zeeb } 2735*6c92544dSBjoern A. Zeeb 2736*6c92544dSBjoern A. Zeeb return 0; 2737*6c92544dSBjoern A. Zeeb } 2738*6c92544dSBjoern A. Zeeb 2739*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) 2740*6c92544dSBjoern A. Zeeb { 2741*6c92544dSBjoern A. Zeeb struct mt7915_mcu_eeprom req = { 2742*6c92544dSBjoern A. Zeeb .buffer_mode = EE_MODE_EFUSE, 2743*6c92544dSBjoern A. Zeeb .format = EE_FORMAT_WHOLE, 2744*6c92544dSBjoern A. Zeeb }; 2745*6c92544dSBjoern A. Zeeb 2746*6c92544dSBjoern A. Zeeb if (dev->flash_mode) 2747*6c92544dSBjoern A. Zeeb return mt7915_mcu_set_eeprom_flash(dev); 2748*6c92544dSBjoern A. Zeeb 2749*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE), 2750*6c92544dSBjoern A. Zeeb &req, sizeof(req), true); 2751*6c92544dSBjoern A. Zeeb } 2752*6c92544dSBjoern A. Zeeb 2753*6c92544dSBjoern A. Zeeb int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) 2754*6c92544dSBjoern A. Zeeb { 2755*6c92544dSBjoern A. Zeeb struct mt7915_mcu_eeprom_info req = { 2756*6c92544dSBjoern A. Zeeb .addr = cpu_to_le32(round_down(offset, 2757*6c92544dSBjoern A. Zeeb MT7915_EEPROM_BLOCK_SIZE)), 2758*6c92544dSBjoern A. Zeeb }; 2759*6c92544dSBjoern A. Zeeb struct mt7915_mcu_eeprom_info *res; 2760*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 2761*6c92544dSBjoern A. Zeeb int ret; 2762*6c92544dSBjoern A. Zeeb u8 *buf; 2763*6c92544dSBjoern A. Zeeb 2764*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), &req, 2765*6c92544dSBjoern A. Zeeb sizeof(req), true, &skb); 2766*6c92544dSBjoern A. Zeeb if (ret) 2767*6c92544dSBjoern A. Zeeb return ret; 2768*6c92544dSBjoern A. Zeeb 2769*6c92544dSBjoern A. Zeeb res = (struct mt7915_mcu_eeprom_info *)skb->data; 2770*6c92544dSBjoern A. Zeeb #if defined(__linux__) 2771*6c92544dSBjoern A. Zeeb buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); 2772*6c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 2773*6c92544dSBjoern A. Zeeb buf = (u8 *)dev->mt76.eeprom.data + le32_to_cpu(res->addr); 2774*6c92544dSBjoern A. Zeeb #endif 2775*6c92544dSBjoern A. Zeeb memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE); 2776*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 2777*6c92544dSBjoern A. Zeeb 2778*6c92544dSBjoern A. Zeeb return 0; 2779*6c92544dSBjoern A. Zeeb } 2780*6c92544dSBjoern A. Zeeb 2781*6c92544dSBjoern A. Zeeb int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num) 2782*6c92544dSBjoern A. Zeeb { 2783*6c92544dSBjoern A. Zeeb struct { 2784*6c92544dSBjoern A. Zeeb u8 _rsv; 2785*6c92544dSBjoern A. Zeeb u8 version; 2786*6c92544dSBjoern A. Zeeb u8 die_idx; 2787*6c92544dSBjoern A. Zeeb u8 _rsv2; 2788*6c92544dSBjoern A. Zeeb } __packed req = { 2789*6c92544dSBjoern A. Zeeb .version = 1, 2790*6c92544dSBjoern A. Zeeb }; 2791*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 2792*6c92544dSBjoern A. Zeeb int ret; 2793*6c92544dSBjoern A. Zeeb 2794*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_FREE_BLOCK), &req, 2795*6c92544dSBjoern A. Zeeb sizeof(req), true, &skb); 2796*6c92544dSBjoern A. Zeeb if (ret) 2797*6c92544dSBjoern A. Zeeb return ret; 2798*6c92544dSBjoern A. Zeeb 2799*6c92544dSBjoern A. Zeeb *block_num = *(u8 *)skb->data; 2800*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 2801*6c92544dSBjoern A. Zeeb 2802*6c92544dSBjoern A. Zeeb return 0; 2803*6c92544dSBjoern A. Zeeb } 2804*6c92544dSBjoern A. Zeeb 2805*6c92544dSBjoern A. Zeeb static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx, 2806*6c92544dSBjoern A. Zeeb u8 *data, u32 len, int cmd) 2807*6c92544dSBjoern A. Zeeb { 2808*6c92544dSBjoern A. Zeeb struct { 2809*6c92544dSBjoern A. Zeeb u8 dir; 2810*6c92544dSBjoern A. Zeeb u8 valid; 2811*6c92544dSBjoern A. Zeeb __le16 bitmap; 2812*6c92544dSBjoern A. Zeeb s8 precal; 2813*6c92544dSBjoern A. Zeeb u8 action; 2814*6c92544dSBjoern A. Zeeb u8 band; 2815*6c92544dSBjoern A. Zeeb u8 idx; 2816*6c92544dSBjoern A. Zeeb u8 rsv[4]; 2817*6c92544dSBjoern A. Zeeb __le32 len; 2818*6c92544dSBjoern A. Zeeb } req = {}; 2819*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 2820*6c92544dSBjoern A. Zeeb 2821*6c92544dSBjoern A. Zeeb skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len); 2822*6c92544dSBjoern A. Zeeb if (!skb) 2823*6c92544dSBjoern A. Zeeb return -ENOMEM; 2824*6c92544dSBjoern A. Zeeb 2825*6c92544dSBjoern A. Zeeb req.idx = idx; 2826*6c92544dSBjoern A. Zeeb req.len = cpu_to_le32(len); 2827*6c92544dSBjoern A. Zeeb skb_put_data(skb, &req, sizeof(req)); 2828*6c92544dSBjoern A. Zeeb skb_put_data(skb, data, len); 2829*6c92544dSBjoern A. Zeeb 2830*6c92544dSBjoern A. Zeeb return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false); 2831*6c92544dSBjoern A. Zeeb } 2832*6c92544dSBjoern A. Zeeb 2833*6c92544dSBjoern A. Zeeb int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev) 2834*6c92544dSBjoern A. Zeeb { 2835*6c92544dSBjoern A. Zeeb u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data; 2836*6c92544dSBjoern A. Zeeb u32 total = MT_EE_CAL_GROUP_SIZE; 2837*6c92544dSBjoern A. Zeeb 2838*6c92544dSBjoern A. Zeeb if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP)) 2839*6c92544dSBjoern A. Zeeb return 0; 2840*6c92544dSBjoern A. Zeeb 2841*6c92544dSBjoern A. Zeeb /* 2842*6c92544dSBjoern A. Zeeb * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG 2843*6c92544dSBjoern A. Zeeb * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC 2844*6c92544dSBjoern A. Zeeb */ 2845*6c92544dSBjoern A. Zeeb while (total > 0) { 2846*6c92544dSBjoern A. Zeeb int ret, len; 2847*6c92544dSBjoern A. Zeeb 2848*6c92544dSBjoern A. Zeeb len = min_t(u32, total, MT_EE_CAL_UNIT); 2849*6c92544dSBjoern A. Zeeb 2850*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len, 2851*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(GROUP_PRE_CAL_INFO)); 2852*6c92544dSBjoern A. Zeeb if (ret) 2853*6c92544dSBjoern A. Zeeb return ret; 2854*6c92544dSBjoern A. Zeeb 2855*6c92544dSBjoern A. Zeeb total -= len; 2856*6c92544dSBjoern A. Zeeb cal += len; 2857*6c92544dSBjoern A. Zeeb idx++; 2858*6c92544dSBjoern A. Zeeb } 2859*6c92544dSBjoern A. Zeeb 2860*6c92544dSBjoern A. Zeeb return 0; 2861*6c92544dSBjoern A. Zeeb } 2862*6c92544dSBjoern A. Zeeb 2863*6c92544dSBjoern A. Zeeb static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur) 2864*6c92544dSBjoern A. Zeeb { 2865*6c92544dSBjoern A. Zeeb int i; 2866*6c92544dSBjoern A. Zeeb 2867*6c92544dSBjoern A. Zeeb for (i = 0; i < n_freqs; i++) 2868*6c92544dSBjoern A. Zeeb if (cur == freqs[i]) 2869*6c92544dSBjoern A. Zeeb return i; 2870*6c92544dSBjoern A. Zeeb 2871*6c92544dSBjoern A. Zeeb return -1; 2872*6c92544dSBjoern A. Zeeb } 2873*6c92544dSBjoern A. Zeeb 2874*6c92544dSBjoern A. Zeeb static int mt7915_dpd_freq_idx(u16 freq, u8 bw) 2875*6c92544dSBjoern A. Zeeb { 2876*6c92544dSBjoern A. Zeeb static const u16 freq_list[] = { 2877*6c92544dSBjoern A. Zeeb 5180, 5200, 5220, 5240, 2878*6c92544dSBjoern A. Zeeb 5260, 5280, 5300, 5320, 2879*6c92544dSBjoern A. Zeeb 5500, 5520, 5540, 5560, 2880*6c92544dSBjoern A. Zeeb 5580, 5600, 5620, 5640, 2881*6c92544dSBjoern A. Zeeb 5660, 5680, 5700, 5745, 2882*6c92544dSBjoern A. Zeeb 5765, 5785, 5805, 5825 2883*6c92544dSBjoern A. Zeeb }; 2884*6c92544dSBjoern A. Zeeb int offset_2g = ARRAY_SIZE(freq_list); 2885*6c92544dSBjoern A. Zeeb int idx; 2886*6c92544dSBjoern A. Zeeb 2887*6c92544dSBjoern A. Zeeb if (freq < 4000) { 2888*6c92544dSBjoern A. Zeeb if (freq < 2432) 2889*6c92544dSBjoern A. Zeeb return offset_2g; 2890*6c92544dSBjoern A. Zeeb if (freq < 2457) 2891*6c92544dSBjoern A. Zeeb return offset_2g + 1; 2892*6c92544dSBjoern A. Zeeb 2893*6c92544dSBjoern A. Zeeb return offset_2g + 2; 2894*6c92544dSBjoern A. Zeeb } 2895*6c92544dSBjoern A. Zeeb 2896*6c92544dSBjoern A. Zeeb if (bw == NL80211_CHAN_WIDTH_80P80 || bw == NL80211_CHAN_WIDTH_160) 2897*6c92544dSBjoern A. Zeeb return -1; 2898*6c92544dSBjoern A. Zeeb 2899*6c92544dSBjoern A. Zeeb if (bw != NL80211_CHAN_WIDTH_20) { 2900*6c92544dSBjoern A. Zeeb idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), 2901*6c92544dSBjoern A. Zeeb freq + 10); 2902*6c92544dSBjoern A. Zeeb if (idx >= 0) 2903*6c92544dSBjoern A. Zeeb return idx; 2904*6c92544dSBjoern A. Zeeb 2905*6c92544dSBjoern A. Zeeb idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), 2906*6c92544dSBjoern A. Zeeb freq - 10); 2907*6c92544dSBjoern A. Zeeb if (idx >= 0) 2908*6c92544dSBjoern A. Zeeb return idx; 2909*6c92544dSBjoern A. Zeeb } 2910*6c92544dSBjoern A. Zeeb 2911*6c92544dSBjoern A. Zeeb return mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); 2912*6c92544dSBjoern A. Zeeb } 2913*6c92544dSBjoern A. Zeeb 2914*6c92544dSBjoern A. Zeeb int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) 2915*6c92544dSBjoern A. Zeeb { 2916*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 2917*6c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 2918*6c92544dSBjoern A. Zeeb u16 total = 2, center_freq = chandef->center_freq1; 2919*6c92544dSBjoern A. Zeeb u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data; 2920*6c92544dSBjoern A. Zeeb int idx; 2921*6c92544dSBjoern A. Zeeb 2922*6c92544dSBjoern A. Zeeb if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD)) 2923*6c92544dSBjoern A. Zeeb return 0; 2924*6c92544dSBjoern A. Zeeb 2925*6c92544dSBjoern A. Zeeb idx = mt7915_dpd_freq_idx(center_freq, chandef->width); 2926*6c92544dSBjoern A. Zeeb if (idx < 0) 2927*6c92544dSBjoern A. Zeeb return -EINVAL; 2928*6c92544dSBjoern A. Zeeb 2929*6c92544dSBjoern A. Zeeb /* Items: Tx DPD, Tx Flatness */ 2930*6c92544dSBjoern A. Zeeb idx = idx * 2; 2931*6c92544dSBjoern A. Zeeb cal += MT_EE_CAL_GROUP_SIZE; 2932*6c92544dSBjoern A. Zeeb 2933*6c92544dSBjoern A. Zeeb while (total--) { 2934*6c92544dSBjoern A. Zeeb int ret; 2935*6c92544dSBjoern A. Zeeb 2936*6c92544dSBjoern A. Zeeb cal += (idx * MT_EE_CAL_UNIT); 2937*6c92544dSBjoern A. Zeeb ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT, 2938*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(DPD_PRE_CAL_INFO)); 2939*6c92544dSBjoern A. Zeeb if (ret) 2940*6c92544dSBjoern A. Zeeb return ret; 2941*6c92544dSBjoern A. Zeeb 2942*6c92544dSBjoern A. Zeeb idx++; 2943*6c92544dSBjoern A. Zeeb } 2944*6c92544dSBjoern A. Zeeb 2945*6c92544dSBjoern A. Zeeb return 0; 2946*6c92544dSBjoern A. Zeeb } 2947*6c92544dSBjoern A. Zeeb 2948*6c92544dSBjoern A. Zeeb int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) 2949*6c92544dSBjoern A. Zeeb { 2950*6c92544dSBjoern A. Zeeb /* strict order */ 2951*6c92544dSBjoern A. Zeeb static const u32 offs[] = { 2952*6c92544dSBjoern A. Zeeb MIB_BUSY_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME, 2953*6c92544dSBjoern A. Zeeb MIB_BUSY_TIME_V2, MIB_TX_TIME_V2, MIB_RX_TIME_V2, 2954*6c92544dSBjoern A. Zeeb MIB_OBSS_AIRTIME_V2 2955*6c92544dSBjoern A. Zeeb }; 2956*6c92544dSBjoern A. Zeeb struct mt76_channel_state *state = phy->mt76->chan_state; 2957*6c92544dSBjoern A. Zeeb struct mt76_channel_state *state_ts = &phy->state_ts; 2958*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 2959*6c92544dSBjoern A. Zeeb struct mt7915_mcu_mib *res, req[4]; 2960*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 2961*6c92544dSBjoern A. Zeeb int i, ret, start = 0, ofs = 20; 2962*6c92544dSBjoern A. Zeeb 2963*6c92544dSBjoern A. Zeeb if (!is_mt7915(&dev->mt76)) { 2964*6c92544dSBjoern A. Zeeb start = 4; 2965*6c92544dSBjoern A. Zeeb ofs = 0; 2966*6c92544dSBjoern A. Zeeb } 2967*6c92544dSBjoern A. Zeeb 2968*6c92544dSBjoern A. Zeeb for (i = 0; i < 4; i++) { 2969*6c92544dSBjoern A. Zeeb req[i].band = cpu_to_le32(phy != &dev->phy); 2970*6c92544dSBjoern A. Zeeb req[i].offs = cpu_to_le32(offs[i + start]); 2971*6c92544dSBjoern A. Zeeb } 2972*6c92544dSBjoern A. Zeeb 2973*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), 2974*6c92544dSBjoern A. Zeeb req, sizeof(req), true, &skb); 2975*6c92544dSBjoern A. Zeeb if (ret) 2976*6c92544dSBjoern A. Zeeb return ret; 2977*6c92544dSBjoern A. Zeeb 2978*6c92544dSBjoern A. Zeeb res = (struct mt7915_mcu_mib *)(skb->data + ofs); 2979*6c92544dSBjoern A. Zeeb 2980*6c92544dSBjoern A. Zeeb if (chan_switch) 2981*6c92544dSBjoern A. Zeeb goto out; 2982*6c92544dSBjoern A. Zeeb 2983*6c92544dSBjoern A. Zeeb #define __res_u64(s) le64_to_cpu(res[s].data) 2984*6c92544dSBjoern A. Zeeb state->cc_busy += __res_u64(0) - state_ts->cc_busy; 2985*6c92544dSBjoern A. Zeeb state->cc_tx += __res_u64(1) - state_ts->cc_tx; 2986*6c92544dSBjoern A. Zeeb state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; 2987*6c92544dSBjoern A. Zeeb state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; 2988*6c92544dSBjoern A. Zeeb 2989*6c92544dSBjoern A. Zeeb out: 2990*6c92544dSBjoern A. Zeeb state_ts->cc_busy = __res_u64(0); 2991*6c92544dSBjoern A. Zeeb state_ts->cc_tx = __res_u64(1); 2992*6c92544dSBjoern A. Zeeb state_ts->cc_bss_rx = __res_u64(2); 2993*6c92544dSBjoern A. Zeeb state_ts->cc_rx = __res_u64(2) + __res_u64(3); 2994*6c92544dSBjoern A. Zeeb #undef __res_u64 2995*6c92544dSBjoern A. Zeeb 2996*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 2997*6c92544dSBjoern A. Zeeb 2998*6c92544dSBjoern A. Zeeb return 0; 2999*6c92544dSBjoern A. Zeeb } 3000*6c92544dSBjoern A. Zeeb 3001*6c92544dSBjoern A. Zeeb int mt7915_mcu_get_temperature(struct mt7915_phy *phy) 3002*6c92544dSBjoern A. Zeeb { 3003*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3004*6c92544dSBjoern A. Zeeb struct { 3005*6c92544dSBjoern A. Zeeb u8 ctrl_id; 3006*6c92544dSBjoern A. Zeeb u8 action; 3007*6c92544dSBjoern A. Zeeb u8 dbdc_idx; 3008*6c92544dSBjoern A. Zeeb u8 rsv[5]; 3009*6c92544dSBjoern A. Zeeb } req = { 3010*6c92544dSBjoern A. Zeeb .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, 3011*6c92544dSBjoern A. Zeeb .dbdc_idx = phy != &dev->phy, 3012*6c92544dSBjoern A. Zeeb }; 3013*6c92544dSBjoern A. Zeeb 3014*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, 3015*6c92544dSBjoern A. Zeeb sizeof(req), true); 3016*6c92544dSBjoern A. Zeeb } 3017*6c92544dSBjoern A. Zeeb 3018*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) 3019*6c92544dSBjoern A. Zeeb { 3020*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3021*6c92544dSBjoern A. Zeeb struct { 3022*6c92544dSBjoern A. Zeeb struct mt7915_mcu_thermal_ctrl ctrl; 3023*6c92544dSBjoern A. Zeeb 3024*6c92544dSBjoern A. Zeeb __le32 trigger_temp; 3025*6c92544dSBjoern A. Zeeb __le32 restore_temp; 3026*6c92544dSBjoern A. Zeeb __le16 sustain_time; 3027*6c92544dSBjoern A. Zeeb u8 rsv[2]; 3028*6c92544dSBjoern A. Zeeb } __packed req = { 3029*6c92544dSBjoern A. Zeeb .ctrl = { 3030*6c92544dSBjoern A. Zeeb .band_idx = phy->band_idx, 3031*6c92544dSBjoern A. Zeeb }, 3032*6c92544dSBjoern A. Zeeb }; 3033*6c92544dSBjoern A. Zeeb int level; 3034*6c92544dSBjoern A. Zeeb 3035*6c92544dSBjoern A. Zeeb if (!state) { 3036*6c92544dSBjoern A. Zeeb req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE; 3037*6c92544dSBjoern A. Zeeb goto out; 3038*6c92544dSBjoern A. Zeeb } 3039*6c92544dSBjoern A. Zeeb 3040*6c92544dSBjoern A. Zeeb /* set duty cycle and level */ 3041*6c92544dSBjoern A. Zeeb for (level = 0; level < 4; level++) { 3042*6c92544dSBjoern A. Zeeb int ret; 3043*6c92544dSBjoern A. Zeeb 3044*6c92544dSBjoern A. Zeeb req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG; 3045*6c92544dSBjoern A. Zeeb req.ctrl.duty.duty_level = level; 3046*6c92544dSBjoern A. Zeeb req.ctrl.duty.duty_cycle = state; 3047*6c92544dSBjoern A. Zeeb state /= 2; 3048*6c92544dSBjoern A. Zeeb 3049*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), 3050*6c92544dSBjoern A. Zeeb &req, sizeof(req.ctrl), false); 3051*6c92544dSBjoern A. Zeeb if (ret) 3052*6c92544dSBjoern A. Zeeb return ret; 3053*6c92544dSBjoern A. Zeeb } 3054*6c92544dSBjoern A. Zeeb 3055*6c92544dSBjoern A. Zeeb /* set high-temperature trigger threshold */ 3056*6c92544dSBjoern A. Zeeb req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE; 3057*6c92544dSBjoern A. Zeeb /* add a safety margin ~10 */ 3058*6c92544dSBjoern A. Zeeb req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10); 3059*6c92544dSBjoern A. Zeeb req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); 3060*6c92544dSBjoern A. Zeeb req.sustain_time = cpu_to_le16(10); 3061*6c92544dSBjoern A. Zeeb 3062*6c92544dSBjoern A. Zeeb out: 3063*6c92544dSBjoern A. Zeeb req.ctrl.type.protect_type = 1; 3064*6c92544dSBjoern A. Zeeb req.ctrl.type.trigger_type = 1; 3065*6c92544dSBjoern A. Zeeb 3066*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), 3067*6c92544dSBjoern A. Zeeb &req, sizeof(req), false); 3068*6c92544dSBjoern A. Zeeb } 3069*6c92544dSBjoern A. Zeeb 3070*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) 3071*6c92544dSBjoern A. Zeeb { 3072*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3073*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = phy->mt76; 3074*6c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mphy->hw; 3075*6c92544dSBjoern A. Zeeb struct mt7915_sku_val { 3076*6c92544dSBjoern A. Zeeb u8 format_id; 3077*6c92544dSBjoern A. Zeeb u8 limit_type; 3078*6c92544dSBjoern A. Zeeb u8 dbdc_idx; 3079*6c92544dSBjoern A. Zeeb s8 val[MT7915_SKU_RATE_NUM]; 3080*6c92544dSBjoern A. Zeeb } __packed req = { 3081*6c92544dSBjoern A. Zeeb .format_id = 4, 3082*6c92544dSBjoern A. Zeeb .dbdc_idx = phy != &dev->phy, 3083*6c92544dSBjoern A. Zeeb }; 3084*6c92544dSBjoern A. Zeeb struct mt76_power_limits limits_array; 3085*6c92544dSBjoern A. Zeeb s8 *la = (s8 *)&limits_array; 3086*6c92544dSBjoern A. Zeeb int i, idx, n_chains = hweight8(mphy->antenna_mask); 3087*6c92544dSBjoern A. Zeeb int tx_power = hw->conf.power_level * 2; 3088*6c92544dSBjoern A. Zeeb 3089*6c92544dSBjoern A. Zeeb tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, 3090*6c92544dSBjoern A. Zeeb tx_power); 3091*6c92544dSBjoern A. Zeeb tx_power -= mt76_tx_power_nss_delta(n_chains); 3092*6c92544dSBjoern A. Zeeb tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, 3093*6c92544dSBjoern A. Zeeb &limits_array, tx_power); 3094*6c92544dSBjoern A. Zeeb mphy->txpower_cur = tx_power; 3095*6c92544dSBjoern A. Zeeb 3096*6c92544dSBjoern A. Zeeb for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { 3097*6c92544dSBjoern A. Zeeb u8 mcs_num, len = mt7915_sku_group_len[i]; 3098*6c92544dSBjoern A. Zeeb int j; 3099*6c92544dSBjoern A. Zeeb 3100*6c92544dSBjoern A. Zeeb if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) { 3101*6c92544dSBjoern A. Zeeb mcs_num = 10; 3102*6c92544dSBjoern A. Zeeb 3103*6c92544dSBjoern A. Zeeb if (i == SKU_HT_BW20 || i == SKU_VHT_BW20) 3104*6c92544dSBjoern A. Zeeb la = (s8 *)&limits_array + 12; 3105*6c92544dSBjoern A. Zeeb } else { 3106*6c92544dSBjoern A. Zeeb mcs_num = len; 3107*6c92544dSBjoern A. Zeeb } 3108*6c92544dSBjoern A. Zeeb 3109*6c92544dSBjoern A. Zeeb for (j = 0; j < min_t(u8, mcs_num, len); j++) 3110*6c92544dSBjoern A. Zeeb req.val[idx + j] = la[j]; 3111*6c92544dSBjoern A. Zeeb 3112*6c92544dSBjoern A. Zeeb la += mcs_num; 3113*6c92544dSBjoern A. Zeeb idx += len; 3114*6c92544dSBjoern A. Zeeb } 3115*6c92544dSBjoern A. Zeeb 3116*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, 3117*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, 3118*6c92544dSBjoern A. Zeeb sizeof(req), true); 3119*6c92544dSBjoern A. Zeeb } 3120*6c92544dSBjoern A. Zeeb 3121*6c92544dSBjoern A. Zeeb int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) 3122*6c92544dSBjoern A. Zeeb { 3123*6c92544dSBjoern A. Zeeb #define RATE_POWER_INFO 2 3124*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3125*6c92544dSBjoern A. Zeeb struct { 3126*6c92544dSBjoern A. Zeeb u8 format_id; 3127*6c92544dSBjoern A. Zeeb u8 category; 3128*6c92544dSBjoern A. Zeeb u8 band; 3129*6c92544dSBjoern A. Zeeb u8 _rsv; 3130*6c92544dSBjoern A. Zeeb } __packed req = { 3131*6c92544dSBjoern A. Zeeb .format_id = 7, 3132*6c92544dSBjoern A. Zeeb .category = RATE_POWER_INFO, 3133*6c92544dSBjoern A. Zeeb .band = phy != &dev->phy, 3134*6c92544dSBjoern A. Zeeb }; 3135*6c92544dSBjoern A. Zeeb s8 res[MT7915_SKU_RATE_NUM][2]; 3136*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 3137*6c92544dSBjoern A. Zeeb int ret, i; 3138*6c92544dSBjoern A. Zeeb 3139*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, 3140*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), 3141*6c92544dSBjoern A. Zeeb &req, sizeof(req), true, &skb); 3142*6c92544dSBjoern A. Zeeb if (ret) 3143*6c92544dSBjoern A. Zeeb return ret; 3144*6c92544dSBjoern A. Zeeb 3145*6c92544dSBjoern A. Zeeb memcpy(res, skb->data + 4, sizeof(res)); 3146*6c92544dSBjoern A. Zeeb for (i = 0; i < len; i++) 3147*6c92544dSBjoern A. Zeeb txpower[i] = res[i][req.band]; 3148*6c92544dSBjoern A. Zeeb 3149*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 3150*6c92544dSBjoern A. Zeeb 3151*6c92544dSBjoern A. Zeeb return 0; 3152*6c92544dSBjoern A. Zeeb } 3153*6c92544dSBjoern A. Zeeb 3154*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, 3155*6c92544dSBjoern A. Zeeb u8 en) 3156*6c92544dSBjoern A. Zeeb { 3157*6c92544dSBjoern A. Zeeb struct { 3158*6c92544dSBjoern A. Zeeb u8 test_mode_en; 3159*6c92544dSBjoern A. Zeeb u8 param_idx; 3160*6c92544dSBjoern A. Zeeb u8 _rsv[2]; 3161*6c92544dSBjoern A. Zeeb 3162*6c92544dSBjoern A. Zeeb u8 enable; 3163*6c92544dSBjoern A. Zeeb u8 _rsv2[3]; 3164*6c92544dSBjoern A. Zeeb 3165*6c92544dSBjoern A. Zeeb u8 pad[8]; 3166*6c92544dSBjoern A. Zeeb } __packed req = { 3167*6c92544dSBjoern A. Zeeb .test_mode_en = test_mode, 3168*6c92544dSBjoern A. Zeeb .param_idx = param, 3169*6c92544dSBjoern A. Zeeb .enable = en, 3170*6c92544dSBjoern A. Zeeb }; 3171*6c92544dSBjoern A. Zeeb 3172*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, 3173*6c92544dSBjoern A. Zeeb sizeof(req), false); 3174*6c92544dSBjoern A. Zeeb } 3175*6c92544dSBjoern A. Zeeb 3176*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) 3177*6c92544dSBjoern A. Zeeb { 3178*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3179*6c92544dSBjoern A. Zeeb struct mt7915_sku { 3180*6c92544dSBjoern A. Zeeb u8 format_id; 3181*6c92544dSBjoern A. Zeeb u8 sku_enable; 3182*6c92544dSBjoern A. Zeeb u8 dbdc_idx; 3183*6c92544dSBjoern A. Zeeb u8 rsv; 3184*6c92544dSBjoern A. Zeeb } __packed req = { 3185*6c92544dSBjoern A. Zeeb .format_id = 0, 3186*6c92544dSBjoern A. Zeeb .dbdc_idx = phy != &dev->phy, 3187*6c92544dSBjoern A. Zeeb .sku_enable = enable, 3188*6c92544dSBjoern A. Zeeb }; 3189*6c92544dSBjoern A. Zeeb 3190*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, 3191*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, 3192*6c92544dSBjoern A. Zeeb sizeof(req), true); 3193*6c92544dSBjoern A. Zeeb } 3194*6c92544dSBjoern A. Zeeb 3195*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) 3196*6c92544dSBjoern A. Zeeb { 3197*6c92544dSBjoern A. Zeeb struct { 3198*6c92544dSBjoern A. Zeeb u8 action; 3199*6c92544dSBjoern A. Zeeb u8 set; 3200*6c92544dSBjoern A. Zeeb u8 band; 3201*6c92544dSBjoern A. Zeeb u8 rsv; 3202*6c92544dSBjoern A. Zeeb } req = { 3203*6c92544dSBjoern A. Zeeb .action = action, 3204*6c92544dSBjoern A. Zeeb .set = set, 3205*6c92544dSBjoern A. Zeeb .band = band, 3206*6c92544dSBjoern A. Zeeb }; 3207*6c92544dSBjoern A. Zeeb 3208*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER), 3209*6c92544dSBjoern A. Zeeb &req, sizeof(req), false); 3210*6c92544dSBjoern A. Zeeb } 3211*6c92544dSBjoern A. Zeeb 3212*6c92544dSBjoern A. Zeeb int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) 3213*6c92544dSBjoern A. Zeeb { 3214*6c92544dSBjoern A. Zeeb struct { 3215*6c92544dSBjoern A. Zeeb u8 action; 3216*6c92544dSBjoern A. Zeeb union { 3217*6c92544dSBjoern A. Zeeb struct { 3218*6c92544dSBjoern A. Zeeb u8 snd_mode; 3219*6c92544dSBjoern A. Zeeb u8 sta_num; 3220*6c92544dSBjoern A. Zeeb u8 rsv; 3221*6c92544dSBjoern A. Zeeb u8 wlan_idx[4]; 3222*6c92544dSBjoern A. Zeeb __le32 snd_period; /* ms */ 3223*6c92544dSBjoern A. Zeeb } __packed snd; 3224*6c92544dSBjoern A. Zeeb struct { 3225*6c92544dSBjoern A. Zeeb bool ebf; 3226*6c92544dSBjoern A. Zeeb bool ibf; 3227*6c92544dSBjoern A. Zeeb u8 rsv; 3228*6c92544dSBjoern A. Zeeb } __packed type; 3229*6c92544dSBjoern A. Zeeb struct { 3230*6c92544dSBjoern A. Zeeb u8 bf_num; 3231*6c92544dSBjoern A. Zeeb u8 bf_bitmap; 3232*6c92544dSBjoern A. Zeeb u8 bf_sel[8]; 3233*6c92544dSBjoern A. Zeeb u8 rsv[5]; 3234*6c92544dSBjoern A. Zeeb } __packed mod; 3235*6c92544dSBjoern A. Zeeb }; 3236*6c92544dSBjoern A. Zeeb } __packed req = { 3237*6c92544dSBjoern A. Zeeb .action = action, 3238*6c92544dSBjoern A. Zeeb }; 3239*6c92544dSBjoern A. Zeeb 3240*6c92544dSBjoern A. Zeeb #define MT_BF_PROCESSING 4 3241*6c92544dSBjoern A. Zeeb switch (action) { 3242*6c92544dSBjoern A. Zeeb case MT_BF_SOUNDING_ON: 3243*6c92544dSBjoern A. Zeeb req.snd.snd_mode = MT_BF_PROCESSING; 3244*6c92544dSBjoern A. Zeeb break; 3245*6c92544dSBjoern A. Zeeb case MT_BF_TYPE_UPDATE: 3246*6c92544dSBjoern A. Zeeb req.type.ebf = true; 3247*6c92544dSBjoern A. Zeeb req.type.ibf = dev->ibf; 3248*6c92544dSBjoern A. Zeeb break; 3249*6c92544dSBjoern A. Zeeb case MT_BF_MODULE_UPDATE: 3250*6c92544dSBjoern A. Zeeb req.mod.bf_num = 2; 3251*6c92544dSBjoern A. Zeeb req.mod.bf_bitmap = GENMASK(1, 0); 3252*6c92544dSBjoern A. Zeeb break; 3253*6c92544dSBjoern A. Zeeb default: 3254*6c92544dSBjoern A. Zeeb return -EINVAL; 3255*6c92544dSBjoern A. Zeeb } 3256*6c92544dSBjoern A. Zeeb 3257*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, 3258*6c92544dSBjoern A. Zeeb sizeof(req), true); 3259*6c92544dSBjoern A. Zeeb } 3260*6c92544dSBjoern A. Zeeb 3261*6c92544dSBjoern A. Zeeb int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, 3262*6c92544dSBjoern A. Zeeb bool enable) 3263*6c92544dSBjoern A. Zeeb { 3264*6c92544dSBjoern A. Zeeb #define MT_SPR_ENABLE 1 3265*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 3266*6c92544dSBjoern A. Zeeb struct { 3267*6c92544dSBjoern A. Zeeb u8 action; 3268*6c92544dSBjoern A. Zeeb u8 arg_num; 3269*6c92544dSBjoern A. Zeeb u8 band_idx; 3270*6c92544dSBjoern A. Zeeb u8 status; 3271*6c92544dSBjoern A. Zeeb u8 drop_tx_idx; 3272*6c92544dSBjoern A. Zeeb u8 sta_idx; /* 256 sta */ 3273*6c92544dSBjoern A. Zeeb u8 rsv[2]; 3274*6c92544dSBjoern A. Zeeb __le32 val; 3275*6c92544dSBjoern A. Zeeb } __packed req = { 3276*6c92544dSBjoern A. Zeeb .action = MT_SPR_ENABLE, 3277*6c92544dSBjoern A. Zeeb .arg_num = 1, 3278*6c92544dSBjoern A. Zeeb .band_idx = mvif->mt76.band_idx, 3279*6c92544dSBjoern A. Zeeb .val = cpu_to_le32(enable), 3280*6c92544dSBjoern A. Zeeb }; 3281*6c92544dSBjoern A. Zeeb 3282*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, 3283*6c92544dSBjoern A. Zeeb sizeof(req), true); 3284*6c92544dSBjoern A. Zeeb } 3285*6c92544dSBjoern A. Zeeb 3286*6c92544dSBjoern A. Zeeb int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, 3287*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, struct rate_info *rate) 3288*6c92544dSBjoern A. Zeeb { 3289*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 3290*6c92544dSBjoern A. Zeeb struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 3291*6c92544dSBjoern A. Zeeb struct mt7915_dev *dev = phy->dev; 3292*6c92544dSBjoern A. Zeeb struct mt76_phy *mphy = phy->mt76; 3293*6c92544dSBjoern A. Zeeb struct { 3294*6c92544dSBjoern A. Zeeb u8 category; 3295*6c92544dSBjoern A. Zeeb u8 band; 3296*6c92544dSBjoern A. Zeeb __le16 wcid; 3297*6c92544dSBjoern A. Zeeb } __packed req = { 3298*6c92544dSBjoern A. Zeeb .category = MCU_PHY_STATE_CONTENTION_RX_RATE, 3299*6c92544dSBjoern A. Zeeb .band = mvif->mt76.band_idx, 3300*6c92544dSBjoern A. Zeeb .wcid = cpu_to_le16(msta->wcid.idx), 3301*6c92544dSBjoern A. Zeeb }; 3302*6c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband; 3303*6c92544dSBjoern A. Zeeb struct mt7915_mcu_phy_rx_info *res; 3304*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 3305*6c92544dSBjoern A. Zeeb int ret; 3306*6c92544dSBjoern A. Zeeb bool cck = false; 3307*6c92544dSBjoern A. Zeeb 3308*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO), 3309*6c92544dSBjoern A. Zeeb &req, sizeof(req), true, &skb); 3310*6c92544dSBjoern A. Zeeb if (ret) 3311*6c92544dSBjoern A. Zeeb return ret; 3312*6c92544dSBjoern A. Zeeb 3313*6c92544dSBjoern A. Zeeb res = (struct mt7915_mcu_phy_rx_info *)skb->data; 3314*6c92544dSBjoern A. Zeeb 3315*6c92544dSBjoern A. Zeeb rate->mcs = res->rate; 3316*6c92544dSBjoern A. Zeeb rate->nss = res->nsts + 1; 3317*6c92544dSBjoern A. Zeeb 3318*6c92544dSBjoern A. Zeeb switch (res->mode) { 3319*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_CCK: 3320*6c92544dSBjoern A. Zeeb cck = true; 3321*6c92544dSBjoern A. Zeeb fallthrough; 3322*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_OFDM: 3323*6c92544dSBjoern A. Zeeb if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 3324*6c92544dSBjoern A. Zeeb sband = &mphy->sband_5g.sband; 3325*6c92544dSBjoern A. Zeeb else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) 3326*6c92544dSBjoern A. Zeeb sband = &mphy->sband_6g.sband; 3327*6c92544dSBjoern A. Zeeb else 3328*6c92544dSBjoern A. Zeeb sband = &mphy->sband_2g.sband; 3329*6c92544dSBjoern A. Zeeb 3330*6c92544dSBjoern A. Zeeb rate->mcs = mt76_get_rate(&dev->mt76, sband, rate->mcs, cck); 3331*6c92544dSBjoern A. Zeeb rate->legacy = sband->bitrates[rate->mcs].bitrate; 3332*6c92544dSBjoern A. Zeeb break; 3333*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_HT: 3334*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_HT_GF: 3335*6c92544dSBjoern A. Zeeb if (rate->mcs > 31) { 3336*6c92544dSBjoern A. Zeeb ret = -EINVAL; 3337*6c92544dSBjoern A. Zeeb goto out; 3338*6c92544dSBjoern A. Zeeb } 3339*6c92544dSBjoern A. Zeeb 3340*6c92544dSBjoern A. Zeeb rate->flags = RATE_INFO_FLAGS_MCS; 3341*6c92544dSBjoern A. Zeeb if (res->gi) 3342*6c92544dSBjoern A. Zeeb rate->flags |= RATE_INFO_FLAGS_SHORT_GI; 3343*6c92544dSBjoern A. Zeeb break; 3344*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_VHT: 3345*6c92544dSBjoern A. Zeeb if (rate->mcs > 9) { 3346*6c92544dSBjoern A. Zeeb ret = -EINVAL; 3347*6c92544dSBjoern A. Zeeb goto out; 3348*6c92544dSBjoern A. Zeeb } 3349*6c92544dSBjoern A. Zeeb 3350*6c92544dSBjoern A. Zeeb rate->flags = RATE_INFO_FLAGS_VHT_MCS; 3351*6c92544dSBjoern A. Zeeb if (res->gi) 3352*6c92544dSBjoern A. Zeeb rate->flags |= RATE_INFO_FLAGS_SHORT_GI; 3353*6c92544dSBjoern A. Zeeb break; 3354*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_HE_SU: 3355*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_HE_EXT_SU: 3356*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_HE_TB: 3357*6c92544dSBjoern A. Zeeb case MT_PHY_TYPE_HE_MU: 3358*6c92544dSBjoern A. Zeeb if (res->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) { 3359*6c92544dSBjoern A. Zeeb ret = -EINVAL; 3360*6c92544dSBjoern A. Zeeb goto out; 3361*6c92544dSBjoern A. Zeeb } 3362*6c92544dSBjoern A. Zeeb rate->he_gi = res->gi; 3363*6c92544dSBjoern A. Zeeb rate->flags = RATE_INFO_FLAGS_HE_MCS; 3364*6c92544dSBjoern A. Zeeb break; 3365*6c92544dSBjoern A. Zeeb default: 3366*6c92544dSBjoern A. Zeeb ret = -EINVAL; 3367*6c92544dSBjoern A. Zeeb goto out; 3368*6c92544dSBjoern A. Zeeb } 3369*6c92544dSBjoern A. Zeeb 3370*6c92544dSBjoern A. Zeeb switch (res->bw) { 3371*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_160: 3372*6c92544dSBjoern A. Zeeb rate->bw = RATE_INFO_BW_160; 3373*6c92544dSBjoern A. Zeeb break; 3374*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_80: 3375*6c92544dSBjoern A. Zeeb rate->bw = RATE_INFO_BW_80; 3376*6c92544dSBjoern A. Zeeb break; 3377*6c92544dSBjoern A. Zeeb case IEEE80211_STA_RX_BW_40: 3378*6c92544dSBjoern A. Zeeb rate->bw = RATE_INFO_BW_40; 3379*6c92544dSBjoern A. Zeeb break; 3380*6c92544dSBjoern A. Zeeb default: 3381*6c92544dSBjoern A. Zeeb rate->bw = RATE_INFO_BW_20; 3382*6c92544dSBjoern A. Zeeb break; 3383*6c92544dSBjoern A. Zeeb } 3384*6c92544dSBjoern A. Zeeb 3385*6c92544dSBjoern A. Zeeb out: 3386*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 3387*6c92544dSBjoern A. Zeeb 3388*6c92544dSBjoern A. Zeeb return ret; 3389*6c92544dSBjoern A. Zeeb } 3390*6c92544dSBjoern A. Zeeb 3391*6c92544dSBjoern A. Zeeb int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, 3392*6c92544dSBjoern A. Zeeb struct cfg80211_he_bss_color *he_bss_color) 3393*6c92544dSBjoern A. Zeeb { 3394*6c92544dSBjoern A. Zeeb int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color); 3395*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 3396*6c92544dSBjoern A. Zeeb struct bss_info_color *bss_color; 3397*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 3398*6c92544dSBjoern A. Zeeb struct tlv *tlv; 3399*6c92544dSBjoern A. Zeeb 3400*6c92544dSBjoern A. Zeeb skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, 3401*6c92544dSBjoern A. Zeeb NULL, len); 3402*6c92544dSBjoern A. Zeeb if (IS_ERR(skb)) 3403*6c92544dSBjoern A. Zeeb return PTR_ERR(skb); 3404*6c92544dSBjoern A. Zeeb 3405*6c92544dSBjoern A. Zeeb tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR, 3406*6c92544dSBjoern A. Zeeb sizeof(*bss_color)); 3407*6c92544dSBjoern A. Zeeb bss_color = (struct bss_info_color *)tlv; 3408*6c92544dSBjoern A. Zeeb bss_color->disable = !he_bss_color->enabled; 3409*6c92544dSBjoern A. Zeeb bss_color->color = he_bss_color->color; 3410*6c92544dSBjoern A. Zeeb 3411*6c92544dSBjoern A. Zeeb return mt76_mcu_skb_send_msg(&dev->mt76, skb, 3412*6c92544dSBjoern A. Zeeb MCU_EXT_CMD(BSS_INFO_UPDATE), true); 3413*6c92544dSBjoern A. Zeeb } 3414*6c92544dSBjoern A. Zeeb 3415*6c92544dSBjoern A. Zeeb #define TWT_AGRT_TRIGGER BIT(0) 3416*6c92544dSBjoern A. Zeeb #define TWT_AGRT_ANNOUNCE BIT(1) 3417*6c92544dSBjoern A. Zeeb #define TWT_AGRT_PROTECT BIT(2) 3418*6c92544dSBjoern A. Zeeb 3419*6c92544dSBjoern A. Zeeb int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, 3420*6c92544dSBjoern A. Zeeb struct mt7915_vif *mvif, 3421*6c92544dSBjoern A. Zeeb struct mt7915_twt_flow *flow, 3422*6c92544dSBjoern A. Zeeb int cmd) 3423*6c92544dSBjoern A. Zeeb { 3424*6c92544dSBjoern A. Zeeb struct { 3425*6c92544dSBjoern A. Zeeb u8 tbl_idx; 3426*6c92544dSBjoern A. Zeeb u8 cmd; 3427*6c92544dSBjoern A. Zeeb u8 own_mac_idx; 3428*6c92544dSBjoern A. Zeeb u8 flowid; /* 0xff for group id */ 3429*6c92544dSBjoern A. Zeeb __le16 peer_id; /* specify the peer_id (msb=0) 3430*6c92544dSBjoern A. Zeeb * or group_id (msb=1) 3431*6c92544dSBjoern A. Zeeb */ 3432*6c92544dSBjoern A. Zeeb u8 duration; /* 256 us */ 3433*6c92544dSBjoern A. Zeeb u8 bss_idx; 3434*6c92544dSBjoern A. Zeeb __le64 start_tsf; 3435*6c92544dSBjoern A. Zeeb __le16 mantissa; 3436*6c92544dSBjoern A. Zeeb u8 exponent; 3437*6c92544dSBjoern A. Zeeb u8 is_ap; 3438*6c92544dSBjoern A. Zeeb u8 agrt_params; 3439*6c92544dSBjoern A. Zeeb u8 rsv[23]; 3440*6c92544dSBjoern A. Zeeb } __packed req = { 3441*6c92544dSBjoern A. Zeeb .tbl_idx = flow->table_id, 3442*6c92544dSBjoern A. Zeeb .cmd = cmd, 3443*6c92544dSBjoern A. Zeeb .own_mac_idx = mvif->mt76.omac_idx, 3444*6c92544dSBjoern A. Zeeb .flowid = flow->id, 3445*6c92544dSBjoern A. Zeeb .peer_id = cpu_to_le16(flow->wcid), 3446*6c92544dSBjoern A. Zeeb .duration = flow->duration, 3447*6c92544dSBjoern A. Zeeb .bss_idx = mvif->mt76.idx, 3448*6c92544dSBjoern A. Zeeb .start_tsf = cpu_to_le64(flow->tsf), 3449*6c92544dSBjoern A. Zeeb .mantissa = flow->mantissa, 3450*6c92544dSBjoern A. Zeeb .exponent = flow->exp, 3451*6c92544dSBjoern A. Zeeb .is_ap = true, 3452*6c92544dSBjoern A. Zeeb }; 3453*6c92544dSBjoern A. Zeeb 3454*6c92544dSBjoern A. Zeeb if (flow->protection) 3455*6c92544dSBjoern A. Zeeb req.agrt_params |= TWT_AGRT_PROTECT; 3456*6c92544dSBjoern A. Zeeb if (!flow->flowtype) 3457*6c92544dSBjoern A. Zeeb req.agrt_params |= TWT_AGRT_ANNOUNCE; 3458*6c92544dSBjoern A. Zeeb if (flow->trigger) 3459*6c92544dSBjoern A. Zeeb req.agrt_params |= TWT_AGRT_TRIGGER; 3460*6c92544dSBjoern A. Zeeb 3461*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE), 3462*6c92544dSBjoern A. Zeeb &req, sizeof(req), true); 3463*6c92544dSBjoern A. Zeeb } 3464*6c92544dSBjoern A. Zeeb 3465*6c92544dSBjoern A. Zeeb int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set) 3466*6c92544dSBjoern A. Zeeb { 3467*6c92544dSBjoern A. Zeeb struct { 3468*6c92544dSBjoern A. Zeeb __le32 idx; 3469*6c92544dSBjoern A. Zeeb __le32 ofs; 3470*6c92544dSBjoern A. Zeeb __le32 data; 3471*6c92544dSBjoern A. Zeeb } __packed req = { 3472*6c92544dSBjoern A. Zeeb .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 28))), 3473*6c92544dSBjoern A. Zeeb .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(27, 0))), 3474*6c92544dSBjoern A. Zeeb .data = set ? cpu_to_le32(*val) : 0, 3475*6c92544dSBjoern A. Zeeb }; 3476*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 3477*6c92544dSBjoern A. Zeeb int ret; 3478*6c92544dSBjoern A. Zeeb 3479*6c92544dSBjoern A. Zeeb if (set) 3480*6c92544dSBjoern A. Zeeb return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS), 3481*6c92544dSBjoern A. Zeeb &req, sizeof(req), false); 3482*6c92544dSBjoern A. Zeeb 3483*6c92544dSBjoern A. Zeeb ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS), 3484*6c92544dSBjoern A. Zeeb &req, sizeof(req), true, &skb); 3485*6c92544dSBjoern A. Zeeb if (ret) 3486*6c92544dSBjoern A. Zeeb return ret; 3487*6c92544dSBjoern A. Zeeb 3488*6c92544dSBjoern A. Zeeb *val = le32_to_cpu(*(__le32 *)(skb->data + 8)); 3489*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 3490*6c92544dSBjoern A. Zeeb 3491*6c92544dSBjoern A. Zeeb return 0; 3492*6c92544dSBjoern A. Zeeb } 3493