diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_tsn.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_tsn.c | 68 | 
1 files changed, 51 insertions, 17 deletions
| diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c index 94a2b0dfb54d..a9c08321aca9 100644 --- a/drivers/net/ethernet/intel/igc/igc_tsn.c +++ b/drivers/net/ethernet/intel/igc/igc_tsn.c @@ -37,7 +37,7 @@ static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)  {  	unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED; -	if (adapter->qbv_enable) +	if (adapter->taprio_offload_enable)  		new_flags |= IGC_FLAG_TSN_QBV_ENABLED;  	if (is_any_launchtime(adapter)) @@ -114,7 +114,6 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)  static int igc_tsn_enable_offload(struct igc_adapter *adapter)  {  	struct igc_hw *hw = &adapter->hw; -	bool tsn_mode_reconfig = false;  	u32 tqavctrl, baset_l, baset_h;  	u32 sec, nsec, cycle;  	ktime_t base_time, systim; @@ -133,8 +132,28 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)  		wr32(IGC_STQT(i), ring->start_time);  		wr32(IGC_ENDQT(i), ring->end_time); -		txqctl |= IGC_TXQCTL_STRICT_CYCLE | -			IGC_TXQCTL_STRICT_END; +		if (adapter->taprio_offload_enable) { +			/* If taprio_offload_enable is set we are in "taprio" +			 * mode and we need to be strict about the +			 * cycles: only transmit a packet if it can be +			 * completed during that cycle. +			 * +			 * If taprio_offload_enable is NOT true when +			 * enabling TSN offload, the cycle should have +			 * no external effects, but is only used internally +			 * to adapt the base time register after a second +			 * has passed. +			 * +			 * Enabling strict mode in this case would +			 * unnecessarily prevent the transmission of +			 * certain packets (i.e. at the boundary of a +			 * second) and thus interfere with the launchtime +			 * feature that promises transmission at a +			 * certain point in time. +			 */ +			txqctl |= IGC_TXQCTL_STRICT_CYCLE | +				IGC_TXQCTL_STRICT_END; +		}  		if (ring->launchtime_enable)  			txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT; @@ -228,11 +247,10 @@ skip_cbs:  	tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS; -	if (tqavctrl & IGC_TQAVCTRL_TRANSMIT_MODE_TSN) -		tsn_mode_reconfig = true; -  	tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV; +	adapter->qbv_count++; +  	cycle = adapter->cycle_time;  	base_time = adapter->base_time; @@ -249,17 +267,29 @@ skip_cbs:  		 * Gate Control List (GCL) is running.  		 */  		if ((rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) && -		    tsn_mode_reconfig) +		    (adapter->tc_setup_type == TC_SETUP_QDISC_TAPRIO) && +		    (adapter->qbv_count > 1))  			adapter->qbv_config_change_errors++;  	} else { -		/* According to datasheet section 7.5.2.9.3.3, FutScdDis bit -		 * has to be configured before the cycle time and base time. -		 * Tx won't hang if there is a GCL is already running, -		 * so in this case we don't need to set FutScdDis. -		 */ -		if (igc_is_device_id_i226(hw) && -		    !(rd32(IGC_BASET_H) || rd32(IGC_BASET_L))) -			tqavctrl |= IGC_TQAVCTRL_FUTSCDDIS; +		if (igc_is_device_id_i226(hw)) { +			ktime_t adjust_time, expires_time; + +		       /* According to datasheet section 7.5.2.9.3.3, FutScdDis bit +			* has to be configured before the cycle time and base time. +			* Tx won't hang if a GCL is already running, +			* so in this case we don't need to set FutScdDis. +			*/ +			if (!(rd32(IGC_BASET_H) || rd32(IGC_BASET_L))) +				tqavctrl |= IGC_TQAVCTRL_FUTSCDDIS; + +			nsec = rd32(IGC_SYSTIML); +			sec = rd32(IGC_SYSTIMH); +			systim = ktime_set(sec, nsec); + +			adjust_time = adapter->base_time; +			expires_time = ktime_sub_ns(adjust_time, systim); +			hrtimer_start(&adapter->hrtimer, expires_time, HRTIMER_MODE_REL); +		}  	}  	wr32(IGC_TQAVCTRL, tqavctrl); @@ -305,7 +335,11 @@ int igc_tsn_offload_apply(struct igc_adapter *adapter)  {  	struct igc_hw *hw = &adapter->hw; -	if (netif_running(adapter->netdev) && igc_is_device_id_i225(hw)) { +	/* Per I225/6 HW Design Section 7.5.2.1, transmit mode +	 * cannot be changed dynamically. Require reset the adapter. +	 */ +	if (netif_running(adapter->netdev) && +	    (igc_is_device_id_i225(hw) || !adapter->qbv_count)) {  		schedule_work(&adapter->reset_task);  		return 0;  	} |