diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_tsn.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_tsn.c | 76 | 
1 files changed, 62 insertions, 14 deletions
| diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c index 22cefb1eeedf..d68fa7f3d5f0 100644 --- a/drivers/net/ethernet/intel/igc/igc_tsn.c +++ b/drivers/net/ethernet/intel/igc/igc_tsn.c @@ -49,12 +49,19 @@ static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)  	return new_flags;  } +static bool igc_tsn_is_tx_mode_in_tsn(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; + +	return !!(rd32(IGC_TQAVCTRL) & IGC_TQAVCTRL_TRANSMIT_MODE_TSN); +} +  void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)  {  	struct igc_hw *hw = &adapter->hw;  	u16 txoffset; -	if (!is_any_launchtime(adapter)) +	if (!igc_tsn_is_tx_mode_in_tsn(adapter))  		return;  	switch (adapter->link_speed) { @@ -78,6 +85,23 @@ void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)  	wr32(IGC_GTXOFFSET, txoffset);  } +static void igc_tsn_restore_retx_default(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; +	u32 retxctl; + +	retxctl = rd32(IGC_RETX_CTL) & IGC_RETX_CTL_WATERMARK_MASK; +	wr32(IGC_RETX_CTL, retxctl); +} + +bool igc_tsn_is_taprio_activated_by_user(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; + +	return (rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) && +		adapter->taprio_offload_enable; +} +  /* Returns the TSN specific registers to their default values after   * the adapter is reset.   */ @@ -91,6 +115,9 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)  	wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);  	wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT); +	if (igc_is_device_id_i226(hw)) +		igc_tsn_restore_retx_default(adapter); +  	tqavctrl = rd32(IGC_TQAVCTRL);  	tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |  		      IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS); @@ -111,6 +138,25 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)  	return 0;  } +/* To partially fix i226 HW errata, reduce MAC internal buffering from 192 Bytes + * to 88 Bytes by setting RETX_CTL register using the recommendation from: + * a) Ethernet Controller I225/I226 Specification Update Rev 2.1 + *    Item 9: TSN: Packet Transmission Might Cross the Qbv Window + * b) I225/6 SW User Manual Rev 1.2.4: Section 8.11.5 Retry Buffer Control + */ +static void igc_tsn_set_retx_qbvfullthreshold(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; +	u32 retxctl, watermark; + +	retxctl = rd32(IGC_RETX_CTL); +	watermark = retxctl & IGC_RETX_CTL_WATERMARK_MASK; +	/* Set QBVFULLTH value using watermark and set QBVFULLEN */ +	retxctl |= (watermark << IGC_RETX_CTL_QBVFULLTH_SHIFT) | +		   IGC_RETX_CTL_QBVFULLEN; +	wr32(IGC_RETX_CTL, retxctl); +} +  static int igc_tsn_enable_offload(struct igc_adapter *adapter)  {  	struct igc_hw *hw = &adapter->hw; @@ -123,6 +169,9 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)  	wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);  	wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN); +	if (igc_is_device_id_i226(hw)) +		igc_tsn_set_retx_qbvfullthreshold(adapter); +  	for (i = 0; i < adapter->num_tx_queues; i++) {  		struct igc_ring *ring = adapter->tx_ring[i];  		u32 txqctl = 0; @@ -262,14 +311,6 @@ skip_cbs:  		s64 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);  		base_time = ktime_add_ns(base_time, (n + 1) * cycle); - -		/* Increase the counter if scheduling into the past while -		 * Gate Control List (GCL) is running. -		 */ -		if ((rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) && -		    (adapter->tc_setup_type == TC_SETUP_QDISC_TAPRIO) && -		    (adapter->qbv_count > 1)) -			adapter->qbv_config_change_errors++;  	} else {  		if (igc_is_device_id_i226(hw)) {  			ktime_t adjust_time, expires_time; @@ -331,15 +372,22 @@ int igc_tsn_reset(struct igc_adapter *adapter)  	return err;  } -int igc_tsn_offload_apply(struct igc_adapter *adapter) +static bool igc_tsn_will_tx_mode_change(struct igc_adapter *adapter)  { -	struct igc_hw *hw = &adapter->hw; +	bool any_tsn_enabled = !!(igc_tsn_new_flags(adapter) & +				  IGC_FLAG_TSN_ANY_ENABLED); -	/* Per I225/6 HW Design Section 7.5.2.1, transmit mode -	 * cannot be changed dynamically. Require reset the adapter. +	return (any_tsn_enabled && !igc_tsn_is_tx_mode_in_tsn(adapter)) || +	       (!any_tsn_enabled && igc_tsn_is_tx_mode_in_tsn(adapter)); +} + +int igc_tsn_offload_apply(struct igc_adapter *adapter) +{ +	/* Per I225/6 HW Design Section 7.5.2.1 guideline, if tx mode change +	 * from legacy->tsn or tsn->legacy, then reset adapter is needed.  	 */  	if (netif_running(adapter->netdev) && -	    (igc_is_device_id_i225(hw) || !adapter->qbv_count)) { +	    igc_tsn_will_tx_mode_change(adapter)) {  		schedule_work(&adapter->reset_task);  		return 0;  	} |