[PATCH 08/12] wifi: mt76: mt7996: set ifs time by mcu command

Lorenzo Bianconi lorenzo at kernel.org
Fri Jun 2 11:12:02 PDT 2023


> From: Peter Chiu <chui-hao.chiu at mediatek.com>
> 
> There's a race between driver and fw on some tx/rx control registers
> when setting ifs, which will cause accidental hw queue pause problems.
> Avoid this by setting ifs time with bss_info mcu command.
> 
> Reviewed-by: Shayne Chen <shayne.chen at mediatek.com>
> Signed-off-by: Peter Chiu <chui-hao.chiu at mediatek.com>
> Signed-off-by: Shayne Chen <shayne.chen at mediatek.com>
> ---
>  .../net/wireless/mediatek/mt76/mt7996/mac.c   | 27 +----------
>  .../net/wireless/mediatek/mt76/mt7996/main.c  |  5 +-
>  .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 47 +++++++++++++++++++
>  .../net/wireless/mediatek/mt76/mt7996/mcu.h   | 17 +++++++
>  .../wireless/mediatek/mt76/mt7996/mt7996.h    |  3 +-
>  5 files changed, 70 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> index 130eb7b4fd91..78d9127e63ab 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> @@ -1604,20 +1604,19 @@ void mt7996_mac_reset_counters(struct mt7996_phy *phy)
>  	mt7996_mcu_get_chan_mib_info(phy, true);
>  }
>  
> -void mt7996_mac_set_timing(struct mt7996_phy *phy)
> +void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
>  {
>  	s16 coverage_class = phy->coverage_class;
>  	struct mt7996_dev *dev = phy->dev;
>  	struct mt7996_phy *phy2 = mt7996_phy2(dev);
>  	struct mt7996_phy *phy3 = mt7996_phy3(dev);
> -	u32 val, reg_offset;
> +	u32 reg_offset;
>  	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
>  		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
>  	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
>  		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
>  	u8 band_idx = phy->mt76->band_idx;
>  	int offset;
> -	bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
>  
>  	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
>  		return;
> @@ -1630,34 +1629,12 @@ void mt7996_mac_set_timing(struct mt7996_phy *phy)
>  		coverage_class = max_t(s16, coverage_class,
>  				       phy3->coverage_class);
>  
> -	mt76_set(dev, MT_ARB_SCR(band_idx),
> -		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
> -	udelay(1);
> -
>  	offset = 3 * coverage_class;
>  	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
>  		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
>  
>  	mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
>  	mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
> -	mt76_wr(dev, MT_TMAC_ICR0(band_idx),
> -		FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) |
> -		FIELD_PREP(MT_IFS_RIFS, 2) |
> -		FIELD_PREP(MT_IFS_SIFS, 10) |
> -		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
> -
> -	if (!a_band)
> -		mt76_wr(dev, MT_TMAC_ICR1(band_idx),
> -			FIELD_PREP(MT_IFS_EIFS_CCK, 314));
> -
> -	if (phy->slottime < 20 || a_band)
> -		val = MT7996_CFEND_RATE_DEFAULT;
> -	else
> -		val = MT7996_CFEND_RATE_11B;
> -
> -	mt76_rmw_field(dev, MT_RATE_HRCR0(band_idx), MT_RATE_HRCR0_CFEND_RATE, val);
> -	mt76_clear(dev, MT_ARB_SCR(band_idx),
> -		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
>  }
>  
>  void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> index 8a1edc5c1288..6001b534b657 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
> @@ -287,7 +287,6 @@ int mt7996_set_channel(struct mt7996_phy *phy)
>  	if (ret)
>  		goto out;
>  
> -	mt7996_mac_set_timing(phy);
>  	ret = mt7996_dfs_init_radar_detector(phy);
>  	mt7996_mac_cca_stats_reset(phy);
>  
> @@ -565,7 +564,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
>  
>  		if (slottime != phy->slottime) {
>  			phy->slottime = slottime;
> -			mt7996_mac_set_timing(phy);
> +			mt7996_mcu_set_timing(phy, vif);
>  		}
>  	}
>  
> @@ -905,7 +904,7 @@ mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
>  
>  	mutex_lock(&dev->mt76.mutex);
>  	phy->coverage_class = max_t(s16, coverage_class, 0);
> -	mt7996_mac_set_timing(phy);
> +	mt7996_mac_set_coverage_class(phy);
>  	mutex_unlock(&dev->mt76.mutex);
>  }
>  
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> index db51b3023654..52c6c502e9b3 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
> @@ -701,6 +701,35 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
>  				 sizeof(req), true);
>  }
>  
> +static void
> +mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
> +{
> +	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
> +	struct mt7996_phy *phy = mvif->phy;
> +	struct bss_ifs_time_tlv *ifs_time;
> +	struct tlv *tlv;
> +	bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);

nit: I think it is better to do it in the other way around since the band can
be even 6GHz. Something like:

	bool is_2ghz_band = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ

or even just use phy->mt76->chandef.chan->band directly.

Regards,
Lorenzo

> +	u16 eifs_time = a_band ? 84 : 78;
> +
> +	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time));
> +
> +	ifs_time = (struct bss_ifs_time_tlv *)tlv;
> +	ifs_time->slot_valid = true;
> +	ifs_time->sifs_valid = true;
> +	ifs_time->rifs_valid = true;
> +	ifs_time->eifs_valid = true;
> +
> +	ifs_time->slot_time = cpu_to_le16(phy->slottime);
> +	ifs_time->sifs_time = cpu_to_le16(10);
> +	ifs_time->rifs_time = cpu_to_le16(2);
> +	ifs_time->eifs_time = cpu_to_le16(eifs_time);
> +
> +	if (!a_band) {
> +		ifs_time->eifs_cck_valid = true;
> +		ifs_time->eifs_cck_time = cpu_to_le16(314);
> +	}
> +}
> +
>  static int
>  mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
>  			 struct ieee80211_vif *vif,
> @@ -826,6 +855,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
>  		mt7996_mcu_bss_bmc_tlv(skb, vif, phy);
>  		mt7996_mcu_bss_ra_tlv(skb, vif, phy);
>  		mt7996_mcu_bss_txcmd_tlv(skb, true);
> +		mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
>  
>  		if (vif->bss_conf.he_support)
>  			mt7996_mcu_bss_he_tlv(skb, vif, phy);
> @@ -838,6 +868,23 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
>  				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
>  }
>  
> +int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
> +{
> +	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
> +	struct mt7996_dev *dev = phy->dev;
> +	struct sk_buff *skb;
> +
> +	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
> +					 MT7996_BSS_UPDATE_MAX_SIZE);
> +	if (IS_ERR(skb))
> +		return PTR_ERR(skb);
> +
> +	mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
> +
> +	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
> +				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
> +}
> +
>  static int
>  mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
>  		  struct ieee80211_ampdu_params *params,
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> index d7075a4d0667..078f82858621 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
> @@ -317,6 +317,22 @@ struct bss_sec_tlv {
>  	u8 __rsv2[1];
>  } __packed;
>  
> +struct bss_ifs_time_tlv {
> +	__le16 tag;
> +	__le16 len;
> +	u8 slot_valid;
> +	u8 sifs_valid;
> +	u8 rifs_valid;
> +	u8 eifs_valid;
> +	__le16 slot_time;
> +	__le16 sifs_time;
> +	__le16 rifs_time;
> +	__le16 eifs_time;
> +	u8 eifs_cck_valid;
> +	u8 rsv;
> +	__le16 eifs_cck_time;
> +} __packed;
> +
>  struct bss_power_save {
>  	__le16 tag;
>  	__le16 len;
> @@ -552,6 +568,7 @@ enum {
>  					 sizeof(struct bss_txcmd_tlv) +		\
>  					 sizeof(struct bss_power_save) +	\
>  					 sizeof(struct bss_sec_tlv) +		\
> +					 sizeof(struct bss_ifs_time_tlv) +	\
>  					 sizeof(struct bss_mld_tlv))
>  
>  #define MT7996_STA_UPDATE_MAX_SIZE	(sizeof(struct sta_req_hdr) +		\
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> index 7dfdc7384056..42892f06faa7 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> @@ -463,6 +463,7 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
>  			    const struct mt7996_dfs_pattern *pattern);
>  int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
>  int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
> +int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif);
>  int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
>  int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
>  		       u8 rx_sel, u8 val);
> @@ -526,7 +527,7 @@ void mt7996_mac_write_txwi(struct mt7996_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 mt7996_mac_set_timing(struct mt7996_phy *phy);
> +void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
>  int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
>  		       struct ieee80211_sta *sta);
>  void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
> -- 
> 2.39.2
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mediatek/attachments/20230602/c830cd62/attachment-0001.sig>


More information about the Linux-mediatek mailing list