| diff --git a/eeprom.c b/eeprom.c |
| index 0a88048b..ea54b7af 100644 |
| --- a/eeprom.c |
| +++ b/eeprom.c |
| @@ -138,6 +138,7 @@ mt76_find_power_limits_node(struct mt76_dev *dev) |
| { |
| struct device_node *np = dev->dev->of_node; |
| const char *const region_names[] = { |
| + [NL80211_DFS_UNSET] = "ww", |
| [NL80211_DFS_ETSI] = "etsi", |
| [NL80211_DFS_FCC] = "fcc", |
| [NL80211_DFS_JP] = "jp", |
| diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c |
| index 614df85e..aed4ee95 100644 |
| --- a/mt76_connac_mac.c |
| +++ b/mt76_connac_mac.c |
| @@ -823,7 +823,6 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, |
| HE_BITS(DATA2_TXOP_KNOWN), |
| }; |
| u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; |
| - u32 txbf_mask = is_mt7996(dev) ? BIT(11) : BIT(10); |
| struct ieee80211_radiotap_he *he; |
| |
| status->flag |= RX_FLAG_RADIOTAP_HE; |
| @@ -837,7 +836,7 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, |
| he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | |
| le16_encode_bits(ltf_size, |
| IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); |
| - if (le32_to_cpu(rxv[0]) & txbf_mask) |
| + if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) |
| he->data5 |= HE_BITS(DATA5_TXBF); |
| he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | |
| HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); |
| diff --git a/mt76x0/usb_mcu.c b/mt76x0/usb_mcu.c |
| index 45502fd4..6dc1f51f 100644 |
| --- a/mt76x0/usb_mcu.c |
| +++ b/mt76x0/usb_mcu.c |
| @@ -148,6 +148,7 @@ static int mt76x0u_load_firmware(struct mt76x02_dev *dev) |
| mt76_wr(dev, MT_USB_DMA_CFG, val); |
| |
| ret = mt76x0u_upload_firmware(dev, hdr); |
| + mt76x02_set_ethtool_fwver(dev, hdr); |
| release_firmware(fw); |
| |
| mt76_wr(dev, MT_FCE_PSE_CTRL, 1); |
| diff --git a/mt7996/mac.c b/mt7996/mac.c |
| index 674cea1a..c9a9f0e3 100644 |
| --- a/mt7996/mac.c |
| +++ b/mt7996/mac.c |
| @@ -12,6 +12,10 @@ |
| |
| #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) |
| |
| +#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) |
| +#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ |
| + IEEE80211_RADIOTAP_HE_##f) |
| + |
| static const struct mt7996_dfs_radar_spec etsi_radar_specs = { |
| .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, |
| .radar_pattern = { |
| @@ -251,6 +255,178 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, |
| mt76_clear(dev, addr, BIT(5)); |
| } |
| |
| +static void |
| +mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, |
| + struct ieee80211_radiotap_he *he, |
| + __le32 *rxv) |
| +{ |
| + u32 ru_h, ru_l; |
| + u8 ru, offs = 0; |
| + |
| + ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L); |
| + ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H); |
| + ru = (u8)(ru_l | ru_h << 4); |
| + |
| + status->bw = RATE_INFO_BW_HE_RU; |
| + |
| + switch (ru) { |
| + case 0 ... 36: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; |
| + offs = ru; |
| + break; |
| + case 37 ... 52: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; |
| + offs = ru - 37; |
| + break; |
| + case 53 ... 60: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; |
| + offs = ru - 53; |
| + break; |
| + case 61 ... 64: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; |
| + offs = ru - 61; |
| + break; |
| + case 65 ... 66: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; |
| + offs = ru - 65; |
| + break; |
| + case 67: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; |
| + break; |
| + case 68: |
| + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; |
| + break; |
| + } |
| + |
| + he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); |
| + he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | |
| + le16_encode_bits(offs, |
| + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); |
| +} |
| + |
| +static void |
| +mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv) |
| +{ |
| + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; |
| + static const struct ieee80211_radiotap_he_mu mu_known = { |
| + .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) | |
| + HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) | |
| + HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) | |
| + HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN), |
| + .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), |
| + }; |
| + struct ieee80211_radiotap_he_mu *he_mu = NULL; |
| + |
| + status->flag |= RX_FLAG_RADIOTAP_HE_MU; |
| + |
| + he_mu = skb_push(skb, sizeof(mu_known)); |
| + memcpy(he_mu, &mu_known, sizeof(mu_known)); |
| + |
| +#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) |
| + |
| + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx); |
| + if (status->he_dcm) |
| + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm); |
| + |
| + he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) | |
| + MU_PREP(FLAGS2_SIG_B_SYMS_USERS, |
| + le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER)); |
| + |
| + he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0); |
| + |
| + if (status->bw >= RATE_INFO_BW_40) { |
| + he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN); |
| + he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1); |
| + } |
| + |
| + if (status->bw >= RATE_INFO_BW_80) { |
| + he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2); |
| + he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3); |
| + } |
| +} |
| + |
| +static void |
| +mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode) |
| +{ |
| + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; |
| + static const struct ieee80211_radiotap_he known = { |
| + .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | |
| + HE_BITS(DATA1_DATA_DCM_KNOWN) | |
| + HE_BITS(DATA1_STBC_KNOWN) | |
| + HE_BITS(DATA1_CODING_KNOWN) | |
| + HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | |
| + HE_BITS(DATA1_DOPPLER_KNOWN) | |
| + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | |
| + HE_BITS(DATA1_BSS_COLOR_KNOWN), |
| + .data2 = HE_BITS(DATA2_GI_KNOWN) | |
| + HE_BITS(DATA2_TXBF_KNOWN) | |
| + HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | |
| + HE_BITS(DATA2_TXOP_KNOWN), |
| + }; |
| + struct ieee80211_radiotap_he *he = NULL; |
| + u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; |
| + |
| + status->flag |= RX_FLAG_RADIOTAP_HE; |
| + |
| + he = skb_push(skb, sizeof(known)); |
| + memcpy(he, &known, sizeof(known)); |
| + |
| + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | |
| + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); |
| + he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); |
| + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | |
| + le16_encode_bits(ltf_size, |
| + IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); |
| + if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) |
| + he->data5 |= HE_BITS(DATA5_TXBF); |
| + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | |
| + HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); |
| + |
| + switch (mode) { |
| + case MT_PHY_TYPE_HE_SU: |
| + he->data1 |= HE_BITS(DATA1_FORMAT_SU) | |
| + HE_BITS(DATA1_UL_DL_KNOWN) | |
| + HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | |
| + HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); |
| + |
| + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | |
| + HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); |
| + break; |
| + case MT_PHY_TYPE_HE_EXT_SU: |
| + he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | |
| + HE_BITS(DATA1_UL_DL_KNOWN) | |
| + HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); |
| + |
| + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); |
| + break; |
| + case MT_PHY_TYPE_HE_MU: |
| + he->data1 |= HE_BITS(DATA1_FORMAT_MU) | |
| + HE_BITS(DATA1_UL_DL_KNOWN); |
| + |
| + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); |
| + he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); |
| + |
| + mt7996_mac_decode_he_radiotap_ru(status, he, rxv); |
| + mt7996_mac_decode_he_mu_radiotap(skb, rxv); |
| + break; |
| + case MT_PHY_TYPE_HE_TB: |
| + he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | |
| + HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | |
| + HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | |
| + HE_BITS(DATA1_SPTL_REUSE4_KNOWN); |
| + |
| + he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | |
| + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | |
| + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | |
| + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); |
| + |
| + mt7996_mac_decode_he_radiotap_ru(status, he, rxv); |
| + break; |
| + default: |
| + break; |
| + } |
| +} |
| + |
| /* The HW does not translate the mac header to 802.3 for mesh point */ |
| static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) |
| { |
| @@ -686,8 +862,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) |
| } |
| |
| if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) |
| - mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, |
| - mode); |
| + mt7996_mac_decode_he_radiotap(skb, rxv, mode); |
| |
| if (!status->wcid || !ieee80211_is_data_qos(fc)) |
| return 0; |