Search Linux Wireless

Re: [PATCH v2 15/15] wifi: mt76: connac: add connac3 mac library

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2023-06-09 at 10:15 +0200, Lorenzo Bianconi wrote:
>  	 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>  Introduce connac3_mac in mt76_connac library to reuse mac code
> shared
> between WiFi7 chipsets.
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx>
> ---
>  drivers/net/wireless/mediatek/mt76/Makefile   |   2 +-
>  .../net/wireless/mediatek/mt76/mt76_connac.h  |  19 +
>  .../wireless/mediatek/mt76/mt76_connac3_mac.c | 742
> +++++++++++++++++
>  .../wireless/mediatek/mt76/mt76_connac3_mac.h |  18 +
>  .../net/wireless/mediatek/mt76/mt7996/init.c  |   4 +-
>  .../net/wireless/mediatek/mt76/mt7996/mac.c   | 761 +---------------
> --
>  .../net/wireless/mediatek/mt76/mt7996/main.c  |   8 +-
>  .../net/wireless/mediatek/mt76/mt7996/mcu.c   |   9 +-
>  .../wireless/mediatek/mt76/mt7996/mt7996.h    |  28 +-
>  9 files changed, 807 insertions(+), 784 deletions(-)
>  create mode 100644
> drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/Makefile
> b/drivers/net/wireless/mediatek/mt76/Makefile
> index 84c99b7e57f9..d8e8079c8b54 100644
> --- a/drivers/net/wireless/mediatek/mt76/Makefile
> +++ b/drivers/net/wireless/mediatek/mt76/Makefile
> @@ -27,7 +27,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o
> mt76x02_mcu.o \
>  
>  mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
>  
> -mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
> +mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
> mt76_connac3_mac.o
>  
>  obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
>  obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> index 68bdeada1421..20111678537b 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
> @@ -415,4 +415,23 @@ void mt76_connac2_txwi_free(struct mt76_dev
> *dev, struct mt76_txwi_cache *t,
>  			    struct list_head *free_list);
>  void mt76_connac2_tx_token_put(struct mt76_dev *dev);
>  
> +/* connac3 */
> +void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32
> *txwi);
> +void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32
> *rxv,
> +					 u8 mode);
> +int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
> +				  struct mt76_rx_status *status,
> +				  struct ieee80211_supported_band
> *sband,
> +				  __le32 *rxv, u8 *mode);
> +void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
> +				 struct sk_buff *skb, struct mt76_wcid
> *wcid,
> +				 struct ieee80211_key_conf *key, int
> pid,
> +				 enum mt76_txq_id qid, u32 changed);
> +void mt76_connac3_txwi_free(struct mt76_dev *dev, struct
> mt76_txwi_cache *t,
> +			    struct ieee80211_sta *sta,
> +			    struct list_head *free_list);
> +void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
> +			      u32 max_wtbl_size);
> +void mt76_connac3_tx_token_put(struct mt76_dev *dev);
> +
>  #endif /* __MT76_CONNAC_H */
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
> b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
> new file mode 100644
> index 000000000000..4b745bb74ca0
> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
> @@ -0,0 +1,742 @@
> +// SPDX-License-Identifier: ISC
> +/* Copyright (C) 2023 MediaTek Inc. */
> +
> +#include "mt76_connac.h"
> +#include "mt76_connac3_mac.h"
> +#include "dma.h"
> +
> +#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)
> +
> +void mt76_connac3_tx_check_aggr(struct ieee80211_sta *sta, __le32
> *txwi)
> +{
> +	struct mt76_wcid *wcid;
> +	u16 fc, tid;
> +	u32 val;
> +
> +	if (!sta ||
> +	    !(sta->deflink.ht_cap.ht_supported || sta-
> >deflink.he_cap.has_he))
> +		return;
> +
> +	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
> +	if (tid >= 6) /* skip VO queue */
> +		return;
> +
> +	val = le32_to_cpu(txwi[2]);
> +	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
> +	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
> +	if (unlikely(fc != (IEEE80211_FTYPE_DATA |
> IEEE80211_STYPE_QOS_DATA)))
> +		return;
> +
> +	wcid = (struct mt76_wcid *)sta->drv_priv;
> +	if (!test_and_set_bit(tid, &wcid->ampdu_state))
> +		ieee80211_start_tx_ba_session(sta, tid, 0);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_tx_check_aggr);
> +
> +static void
> +mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status
> *status,
> +				       struct ieee80211_radiotap_he
> *he,
> +				       __le32 *rxv)
> +{
> +	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
> +
> +	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_OF
> FSET);
> +}
> +
> +#define MU_PREP(f, v)	le16_encode_bits(v,
> IEEE80211_RADIOTAP_HE_MU_##f)
> +static void
> +mt76_connac3_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;
> +
> +	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
> +
> +	he_mu = skb_push(skb, sizeof(mu_known));
> +	memcpy(he_mu, &mu_known, sizeof(mu_known));
> +
> +	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[4],
> MT_CRXV_HE_NUM_USER));
> +
> +	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) &
> 0xff;
> +
> +	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[16],
> MT_CRXV_HE_RU1) & 0xff;
> +	}
> +
> +	if (status->bw >= RATE_INFO_BW_80) {
> +		u32 ru_h, ru_l;
> +
> +		he_mu->ru_ch1[1] = le32_get_bits(rxv[16],
> MT_CRXV_HE_RU2) & 0xff;
> +
> +		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
> +		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
> +		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
> +	}
> +}
> +
> +void mt76_connac3_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),
> +	};
> +	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
> +	struct ieee80211_radiotap_he *he;
> +
> +	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[9]) |
> +		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
> +	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
> +	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
> +		    le16_encode_bits(ltf_size,
> +				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SI
> ZE);
> +	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
> +		he->data5 |= HE_BITS(DATA5_TXBF);
> +	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
> +		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
> +
> +	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[8]) |
> +			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
> +		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[5]);
> +		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[5]);
> +		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
> +
> +		mt76_connac3_mac_decode_he_radiotap_ru(status, he,
> rxv);
> +		mt76_connac3_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[13]) |
> +			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK,
> rxv[13]) |
> +			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK,
> rxv[13]) |
> +			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK,
> rxv[13]);
> +
> +		mt76_connac3_mac_decode_he_radiotap_ru(status, he,
> rxv);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
> +
> +int mt76_connac3_mac_fill_rx_rate(struct mt76_dev *dev,
> +				  struct mt76_rx_status *status,
> +				  struct ieee80211_supported_band
> *sband,
> +				  __le32 *rxv, u8 *mode)
> +{
> +	u8 stbc, gi, bw, dcm, nss;
> +	bool cck = false;
> +	u32 v0, v2;
> +	int i, idx;
> +
> +	v0 = le32_to_cpu(rxv[0]);
> +	v2 = le32_to_cpu(rxv[2]);
> +
> +	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
> +	i = idx;
> +	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
> +
> +	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
> +	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
> +	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
> +	dcm = FIELD_GET(MT_PRXV_DCM, v2);
> +	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
> +
> +	switch (*mode) {
> +	case MT_PHY_TYPE_CCK:
> +		cck = true;
> +		fallthrough;
> +	case MT_PHY_TYPE_OFDM:
> +		i = mt76_get_rate(dev, sband, i, cck);
> +		break;
> +	case MT_PHY_TYPE_HT_GF:
> +	case MT_PHY_TYPE_HT:
> +		status->encoding = RX_ENC_HT;
> +		if (gi)
> +			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
> +		if (i > 31)
> +			return -EINVAL;
> +		break;
> +	case MT_PHY_TYPE_VHT:
> +		status->nss = nss;
> +		status->encoding = RX_ENC_VHT;
> +		if (gi)
> +			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
> +		if (i > 11)
> +			return -EINVAL;
> +		break;
> +	case MT_PHY_TYPE_HE_MU:
> +	case MT_PHY_TYPE_HE_SU:
> +	case MT_PHY_TYPE_HE_EXT_SU:
> +	case MT_PHY_TYPE_HE_TB:
> +		status->nss = nss;
> +		status->encoding = RX_ENC_HE;
> +		i &= GENMASK(3, 0);
> +
> +		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
> +			status->he_gi = gi;
> +
> +		status->he_dcm = dcm;
> +		break;
> +	case MT_PHY_TYPE_EHT_SU:
> +	case MT_PHY_TYPE_EHT_TRIG:
> +	case MT_PHY_TYPE_EHT_MU:
> +		status->nss = nss;
> +		status->encoding = RX_ENC_EHT;
> +		i &= GENMASK(3, 0);
> +
> +		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
> +			status->eht.gi = gi;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	status->rate_idx = i;
> +
> +	switch (bw) {
> +	case IEEE80211_STA_RX_BW_20:
> +		break;
> +	case IEEE80211_STA_RX_BW_40:
> +		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
> +		    (idx & MT_PRXV_TX_ER_SU_106T)) {
> +			status->bw = RATE_INFO_BW_HE_RU;
> +			status->he_ru =
> +				NL80211_RATE_INFO_HE_RU_ALLOC_106;
> +		} else {
> +			status->bw = RATE_INFO_BW_40;
> +		}
> +		break;
> +	case IEEE80211_STA_RX_BW_80:
> +		status->bw = RATE_INFO_BW_80;
> +		break;
> +	case IEEE80211_STA_RX_BW_160:
> +		status->bw = RATE_INFO_BW_160;
> +		break;
> +	case IEEE80211_STA_RX_BW_320:
> +		status->bw = RATE_INFO_BW_320;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
> +	if (*mode < MT_PHY_TYPE_HE_SU && gi)
> +		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_mac_fill_rx_rate);
> +
> +static void
> +mt76_connac3_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,
> +				 struct mt76_wcid *wcid)
> +{
> +	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
> +	u8 fc_type, fc_stype;
> +	u16 ethertype;
> +	bool wmm = false;
> +	u32 val;
> +
> +	if (wcid->sta) {
> +		struct ieee80211_sta *sta;
> +
> +		sta = container_of((void *)wcid, struct ieee80211_sta,
> drv_priv);
> +		wmm = sta->wme;
> +	}
> +
> +	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
> +	      FIELD_PREP(MT_TXD1_TID, tid);
> +
> +	ethertype = get_unaligned_be16(&skb->data[12]);
> +	if (ethertype >= ETH_P_802_3_MIN)
> +		val |= MT_TXD1_ETH_802_3;
> +
> +	txwi[1] |= cpu_to_le32(val);
> +
> +	fc_type = IEEE80211_FTYPE_DATA >> 2;
> +	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
> +
> +	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
> +	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
> +
> +	txwi[2] |= cpu_to_le32(val);
> +}
> +
> +static void
> +mt76_connac3_mac_write_txwi_80211(struct mt76_dev *dev, __le32
> *txwi,
> +				  struct sk_buff *skb,
> +				  struct ieee80211_key_conf *key)
> +{
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb-
> >data;
> +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	bool multicast = is_multicast_ether_addr(hdr->addr1);
> +	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
> +	__le16 fc = hdr->frame_control;
> +	u8 fc_type, fc_stype;
> +	u32 val;
> +
> +	if (ieee80211_is_action(fc) &&
> +	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
> +	    mgmt->u.action.u.addba_req.action_code ==
> WLAN_ACTION_ADDBA_REQ)
> +		tid = MT_TX_ADDBA;
> +	else if (ieee80211_is_mgmt(hdr->frame_control))
> +		tid = MT_TX_NORMAL;
> +
> +	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
> +	      FIELD_PREP(MT_TXD1_HDR_INFO,
> +			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
> +	      FIELD_PREP(MT_TXD1_TID, tid);
> +
> +	if (!ieee80211_is_data(fc) || multicast ||
> +	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
> +		val |= MT_TXD1_FIXED_RATE;
> +
> +	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
> +	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
> +		val |= MT_TXD1_BIP;
> +		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
> +	}
> +
> +	txwi[1] |= cpu_to_le32(val);
> +
> +	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
> +	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
> +
> +	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
> +	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
> +
> +	txwi[2] |= cpu_to_le32(val);
> +
> +	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
> +	if (ieee80211_is_beacon(fc)) {
> +		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
> +		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
> +	}
> +
> +	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
> +		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
> +
> +		if (ieee80211_is_back_req(hdr->frame_control)) {
> +			struct ieee80211_bar *bar;
> +
> +			bar = (struct ieee80211_bar *)skb->data;
> +			seqno = le16_to_cpu(bar->start_seq_num);
> +		}
> +
> +		val = MT_TXD3_SN_VALID |
> +		      FIELD_PREP(MT_TXD3_SEQ,
> IEEE80211_SEQ_TO_SN(seqno));
> +		txwi[3] |= cpu_to_le32(val);
> +		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
> +	}
> +}
> +
> +void mt76_connac3_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
> +				 struct sk_buff *skb, struct mt76_wcid
> *wcid,
> +				 struct ieee80211_key_conf *key, int
> pid,
> +				 enum mt76_txq_id qid, u32 changed)
> +{
> +	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE :
> MT_SDIO_TXD_SIZE;
> +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct ieee80211_vif *vif = info->control.vif;
> +	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
> +	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
> +	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
> +	struct mt76_vif *mvif;
> +	u16 tx_count = 15;
> +	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
> +				    BSS_CHANGED_BEACON_ENABLED));
> +	bool inband_disc = !!(changed &
> (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
> +					 BSS_CHANGED_FILS_DISCOVERY));
> +
> +	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
> +	if (mvif) {
> +		omac_idx = mvif->omac_idx;
> +		wmm_idx = mvif->wmm_idx;
> +		band_idx = mvif->band_idx;
> +	}
> +
> +	if (inband_disc) {
> +		p_fmt = MT_TX_TYPE_FW;
> +		q_idx = MT_LMAC_ALTX0;
> +	} else if (beacon) {
> +		p_fmt = MT_TX_TYPE_FW;
> +		q_idx = MT_LMAC_BCN0;
> +	} else if (qid >= MT_TXQ_PSD) {
> +		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :
> MT_TX_TYPE_SF;
> +		q_idx = MT_LMAC_ALTX0;
> +	} else {
> +		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT :
> MT_TX_TYPE_SF;
> +		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
> +			mt76_connac_lmac_mapping(skb_get_queue_mapping(
> skb));
> +	}
> +
> +	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
> +	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
> +	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
> +	txwi[0] = cpu_to_le32(val);
> +
> +	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
> +	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
> +
> +	if (band_idx)
> +		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
> +
> +	txwi[1] = cpu_to_le32(val);
> +	txwi[2] = 0;
> +
> +	val = MT_TXD3_SW_POWER_MGMT |
> +	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
> +	if (key)
> +		val |= MT_TXD3_PROTECT_FRAME;
> +	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
> +		val |= MT_TXD3_NO_ACK;
> +	if (wcid->amsdu)
> +		val |= MT_TXD3_HW_AMSDU;
> +
> +	txwi[3] = cpu_to_le32(val);
> +	txwi[4] = 0;
> +
> +	val = FIELD_PREP(MT_TXD5_PID, pid);
> +	if (pid >= MT_PACKET_ID_FIRST)
> +		val |= MT_TXD5_TX_STATUS_HOST;
> +	txwi[5] = cpu_to_le32(val);
> +
> +	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
> +	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
> +	txwi[6] = cpu_to_le32(val);
> +	txwi[7] = 0;
> +
> +	if (is_8023)
> +		mt76_connac3_mac_write_txwi_8023(txwi, skb, wcid);
> +	else
> +		mt76_connac3_mac_write_txwi_80211(dev, txwi, skb, key);
> +
> +	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
> +		struct ieee80211_hdr *hdr = (struct ieee80211_hdr
> *)skb->data;
> +		bool mcast = ieee80211_is_data(hdr->frame_control) &&
> +			     is_multicast_ether_addr(hdr->addr1);
> +		u8 idx = MT76_CONNAC3_BASIC_RATES_TBL;
> +
> +		if (mvif) {
> +			if (mcast && mvif->mcast_rates_idx)
> +				idx = mvif->mcast_rates_idx;
> +			else if (beacon && mvif->beacon_rates_idx)
> +				idx = mvif->beacon_rates_idx;
> +			else
> +				idx = mvif->basic_rates_idx;
> +		}
> +
> +		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE,
> idx));
> +		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_mac_write_txwi);
> +
> +void mt76_connac3_txwi_free(struct mt76_dev *dev, struct
> mt76_txwi_cache *t,
> +			    struct ieee80211_sta *sta,
> +			    struct list_head *free_list)
> +{
> +	__le32 *txwi;
> +	u16 wcid_idx;
> +
> +	mt76_connac_txp_skb_unmap(dev, t);
> +	if (!t->skb)
> +		goto out;
> +
> +	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
> +	if (sta) {
> +		struct mt76_wcid *wcid = (struct mt76_wcid *)sta-
> >drv_priv;
> +
> +		wcid_idx = wcid->idx;
> +		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
> +			mt76_connac3_tx_check_aggr(sta, txwi);
> +	} else {
> +		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
> +	}
> +
> +	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
> +out:
> +	t->skb = NULL;
> +	mt76_put_txwi(dev, t);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_txwi_free);
> +
> +static bool
> +mt76_connac3_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid
> *wcid,
> +			     int pid, __le32 *txs_data)
> +{
> +	struct mt76_sta_stats *stats = &wcid->stats;
> +	struct ieee80211_supported_band *sband;
> +	struct ieee80211_tx_info *info;
> +	u32 txrate, txs, mode, stbc;
> +	struct rate_info rate = {};
> +	struct sk_buff_head list;
> +	struct mt76_phy *mphy;
> +	struct sk_buff *skb;
> +	bool cck = false;
> +
> +	mt76_tx_status_lock(dev, &list);
> +	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
> +	if (!skb)
> +		goto out_no_skb;
> +
> +	txs = le32_to_cpu(txs_data[0]);
> +
> +	info = IEEE80211_SKB_CB(skb);
> +	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
> +		info->flags |= IEEE80211_TX_STAT_ACK;
> +
> +	info->status.ampdu_len = 1;
> +	info->status.ampdu_ack_len = !!(info->flags &
> +					IEEE80211_TX_STAT_ACK);
> +	info->status.rates[0].idx = -1;
> +
> +	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
> +
> +	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
> +	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
> +	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
> +
> +	if (stbc && rate.nss > 1)
> +		rate.nss >>= 1;
> +
> +	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
> +		stats->tx_nss[rate.nss - 1]++;
> +	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
> +		stats->tx_mcs[rate.mcs]++;
> +
> +	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
> +	switch (mode) {
> +	case MT_PHY_TYPE_CCK:
> +		cck = true;
> +		fallthrough;
> +	case MT_PHY_TYPE_OFDM:
> +		mphy = mt76_dev_phy(dev, wcid->phy_idx);
> +
> +		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
> +			sband = &mphy->sband_5g.sband;
> +		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
> +			sband = &mphy->sband_6g.sband;
> +		else
> +			sband = &mphy->sband_2g.sband;
> +
> +		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs,
> cck);
> +		rate.legacy = sband->bitrates[rate.mcs].bitrate;
> +		break;
> +	case MT_PHY_TYPE_HT:
> +	case MT_PHY_TYPE_HT_GF:
> +		if (rate.mcs > 31)
> +			goto out;
> +
> +		rate.flags = RATE_INFO_FLAGS_MCS;
> +		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
> +			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
> +		break;
> +	case MT_PHY_TYPE_VHT:
> +		if (rate.mcs > 9)
> +			goto out;
> +
> +		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
> +		break;
> +	case MT_PHY_TYPE_HE_SU:
> +	case MT_PHY_TYPE_HE_EXT_SU:
> +	case MT_PHY_TYPE_HE_TB:
> +	case MT_PHY_TYPE_HE_MU:
> +		if (rate.mcs > 11)
> +			goto out;
> +
> +		rate.he_gi = wcid->rate.he_gi;
> +		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
> +		rate.flags = RATE_INFO_FLAGS_HE_MCS;
> +		break;
> +	case MT_PHY_TYPE_EHT_SU:
> +	case MT_PHY_TYPE_EHT_TRIG:
> +	case MT_PHY_TYPE_EHT_MU:
> +		if (rate.mcs > 13)
> +			goto out;
> +
> +		rate.eht_gi = wcid->rate.eht_gi;
> +		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
> +		break;
> +	default:
> +		goto out;
> +	}
> +
> +	stats->tx_mode[mode]++;
> +
> +	switch (FIELD_GET(MT_TXS0_BW, txs)) {
> +	case IEEE80211_STA_RX_BW_320:
> +		rate.bw = RATE_INFO_BW_320;
> +		stats->tx_bw[4]++;
> +		break;
> +	case IEEE80211_STA_RX_BW_160:
> +		rate.bw = RATE_INFO_BW_160;
> +		stats->tx_bw[3]++;
> +		break;
> +	case IEEE80211_STA_RX_BW_80:
> +		rate.bw = RATE_INFO_BW_80;
> +		stats->tx_bw[2]++;
> +		break;
> +	case IEEE80211_STA_RX_BW_40:
> +		rate.bw = RATE_INFO_BW_40;
> +		stats->tx_bw[1]++;
> +		break;
> +	default:
> +		rate.bw = RATE_INFO_BW_20;
> +		stats->tx_bw[0]++;
> +		break;
> +	}
> +	wcid->rate = rate;
> +
> +out:
> +	mt76_tx_status_skb_done(dev, skb, &list);
> +
> +out_no_skb:
> +	mt76_tx_status_unlock(dev, &list);
> +
> +	return !!skb;
> +}
> +
> +void mt76_connac3_mac_add_txs(struct mt76_dev *dev, void *data,
> +			      u32 max_wtbl_size)
> +{
> +	struct mt76_wcid *wcid;
> +	__le32 *txs_data = data;
> +	u16 wcidx;
> +	u8 pid;
> +
> +	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
> +		return;
> +
> +	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
> +	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
> +
> +	if (pid < MT_PACKET_ID_FIRST)
> +		return;
> +
> +	if (wcidx >= max_wtbl_size)
> +		return;
> +
> +	rcu_read_lock();
> +
> +	wcid = rcu_dereference(dev->wcid[wcidx]);
> +	if (!wcid)
> +		goto out;
> +
> +	mt76_connac3_mac_add_txs_skb(dev, wcid, pid, txs_data);
> +	if (!wcid->sta)
> +		goto out;
> +
> +	spin_lock_bh(&dev->sta_poll_lock);
> +	if (list_empty(&wcid->poll_list))
> +		list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
> +	spin_unlock_bh(&dev->sta_poll_lock);
> +
> +out:
> +	rcu_read_unlock();
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_mac_add_txs);
> +
> +void mt76_connac3_tx_token_put(struct mt76_dev *dev)
> +{
> +	struct mt76_txwi_cache *txwi;
> +	int id;
> +
> +	spin_lock_bh(&dev->token_lock);
> +	idr_for_each_entry(&dev->token, txwi, id) {
> +		mt76_connac3_txwi_free(dev, txwi, NULL, NULL);
> +		dev->token_count--;
> +	}
> +	spin_unlock_bh(&dev->token_lock);
> +	idr_destroy(&dev->token);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac3_tx_token_put);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
> b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
> index 6663a0b46541..bcc1d976b2b0 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
> @@ -4,6 +4,24 @@
>  #ifndef __MT76_CONNAC3_MAC_H
>  #define __MT76_CONNAC3_MAC_H
>  
> +/* NOTE: used to map mt76_rates. idx may change if firmware expands
> table */
> +#define MT76_CONNAC3_BASIC_RATES_TBL	11
> +#define MT76_CONNAC3_BEACON_RATES_TBL	25
> 

Different devices may have different defined value. 

I'm thinking if it's too early to create this patch for just moving
mt7996 to connac3_lib?

Ryder





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux