diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc')
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_base.c | 29 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_base.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_defines.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 84 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_ptp.c | 24 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_tsn.c | 56 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_xdp.c | 5 | 
7 files changed, 154 insertions, 49 deletions
| diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index a15927e77272..a1d815af507d 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -396,6 +396,35 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw)  	rd32(IGC_MPC);  } +bool igc_is_device_id_i225(struct igc_hw *hw) +{ +	switch (hw->device_id) { +	case IGC_DEV_ID_I225_LM: +	case IGC_DEV_ID_I225_V: +	case IGC_DEV_ID_I225_I: +	case IGC_DEV_ID_I225_K: +	case IGC_DEV_ID_I225_K2: +	case IGC_DEV_ID_I225_LMVP: +	case IGC_DEV_ID_I225_IT: +		return true; +	default: +		return false; +	} +} + +bool igc_is_device_id_i226(struct igc_hw *hw) +{ +	switch (hw->device_id) { +	case IGC_DEV_ID_I226_LM: +	case IGC_DEV_ID_I226_V: +	case IGC_DEV_ID_I226_K: +	case IGC_DEV_ID_I226_IT: +		return true; +	default: +		return false; +	} +} +  static struct igc_mac_operations igc_mac_ops_base = {  	.init_hw		= igc_init_hw_base,  	.check_for_link		= igc_check_for_copper_link, diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index ce530f5fd7bd..7a992befca24 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -7,6 +7,8 @@  /* forward declaration */  void igc_rx_fifo_flush_base(struct igc_hw *hw);  void igc_power_down_phy_copper_base(struct igc_hw *hw); +bool igc_is_device_id_i225(struct igc_hw *hw); +bool igc_is_device_id_i226(struct igc_hw *hw);  /* Transmit Descriptor - Advanced */  union igc_adv_tx_desc { diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index a7b22639cfcd..9dec3563ce3a 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -475,7 +475,9 @@  #define IGC_TSAUXC_EN_TT0	BIT(0)  /* Enable target time 0. */  #define IGC_TSAUXC_EN_TT1	BIT(1)  /* Enable target time 1. */  #define IGC_TSAUXC_EN_CLK0	BIT(2)  /* Enable Configurable Frequency Clock 0. */ +#define IGC_TSAUXC_ST0		BIT(4)  /* Start Clock 0 Toggle on Target Time 0. */  #define IGC_TSAUXC_EN_CLK1	BIT(5)  /* Enable Configurable Frequency Clock 1. */ +#define IGC_TSAUXC_ST1		BIT(7)  /* Start Clock 1 Toggle on Target Time 1. */  #define IGC_TSAUXC_EN_TS0	BIT(8)  /* Enable hardware timestamp 0. */  #define IGC_TSAUXC_AUTT0	BIT(9)  /* Auxiliary Timestamp Taken. */  #define IGC_TSAUXC_EN_TS1	BIT(10) /* Enable hardware timestamp 0. */ @@ -522,6 +524,7 @@  /* Transmit Scheduling */  #define IGC_TQAVCTRL_TRANSMIT_MODE_TSN	0x00000001  #define IGC_TQAVCTRL_ENHANCED_QAV	0x00000008 +#define IGC_TQAVCTRL_FUTSCDDIS		0x00000080  #define IGC_TXQCTL_QUEUE_MODE_LAUNCHT	0x00000001  #define IGC_TXQCTL_STRICT_CYCLE		0x00000002 diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 44b1740dc098..25fc6c65209b 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2942,7 +2942,9 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)  		if (tx_buffer->next_to_watch &&  		    time_after(jiffies, tx_buffer->time_stamp +  		    (adapter->tx_timeout_factor * HZ)) && -		    !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF)) { +		    !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF) && +		    (rd32(IGC_TDH(tx_ring->reg_idx)) != +		     readl(tx_ring->tail))) {  			/* detected Tx unit hang */  			netdev_err(tx_ring->netdev,  				   "Detected Tx Unit Hang\n" @@ -5069,6 +5071,24 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu)  }  /** + * igc_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + * @txqueue: queue number that timed out + **/ +static void igc_tx_timeout(struct net_device *netdev, +			   unsigned int __always_unused txqueue) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct igc_hw *hw = &adapter->hw; + +	/* Do the reset outside of interrupt context */ +	adapter->tx_timeout_count++; +	schedule_work(&adapter->reset_task); +	wr32(IGC_EICS, +	     (adapter->eims_enable_mask & ~adapter->eims_other)); +} + +/**   * igc_get_stats64 - Get System Network Statistics   * @netdev: network interface device structure   * @stats: rtnl_link_stats64 pointer @@ -5495,7 +5515,7 @@ static void igc_watchdog_task(struct work_struct *work)  			case SPEED_100:  			case SPEED_1000:  			case SPEED_2500: -				adapter->tx_timeout_factor = 7; +				adapter->tx_timeout_factor = 1;  				break;  			} @@ -5958,6 +5978,7 @@ static bool validate_schedule(struct igc_adapter *adapter,  			      const struct tc_taprio_qopt_offload *qopt)  {  	int queue_uses[IGC_MAX_TX_QUEUES] = { }; +	struct igc_hw *hw = &adapter->hw;  	struct timespec64 now;  	size_t n; @@ -5970,8 +5991,10 @@ static bool validate_schedule(struct igc_adapter *adapter,  	 * in the future, it will hold all the packets until that  	 * time, causing a lot of TX Hangs, so to avoid that, we  	 * reject schedules that would start in the future. +	 * Note: Limitation above is no longer in i226.  	 */ -	if (!is_base_time_past(qopt->base_time, &now)) +	if (!is_base_time_past(qopt->base_time, &now) && +	    igc_is_device_id_i225(hw))  		return false;  	for (n = 0; n < qopt->num_entries; n++) { @@ -5987,18 +6010,18 @@ static bool validate_schedule(struct igc_adapter *adapter,  		if (e->command != TC_TAPRIO_CMD_SET_GATES)  			return false; -		for (i = 0; i < adapter->num_tx_queues; i++) { -			if (e->gate_mask & BIT(i)) +		for (i = 0; i < adapter->num_tx_queues; i++) +			if (e->gate_mask & BIT(i)) {  				queue_uses[i]++; -			/* There are limitations: A single queue cannot be -			 * opened and closed multiple times per cycle unless the -			 * gate stays open. Check for it. -			 */ -			if (queue_uses[i] > 1 && -			    !(prev->gate_mask & BIT(i))) -				return false; -		} +				/* There are limitations: A single queue cannot +				 * be opened and closed multiple times per cycle +				 * unless the gate stays open. Check for it. +				 */ +				if (queue_uses[i] > 1 && +				    !(prev->gate_mask & BIT(i))) +					return false; +			}  	}  	return true; @@ -6041,6 +6064,7 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,  				 struct tc_taprio_qopt_offload *qopt)  {  	bool queue_configured[IGC_MAX_TX_QUEUES] = { }; +	struct igc_hw *hw = &adapter->hw;  	u32 start_time = 0, end_time = 0;  	size_t n;  	int i; @@ -6053,7 +6077,7 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,  	if (qopt->base_time < 0)  		return -ERANGE; -	if (adapter->base_time) +	if (igc_is_device_id_i225(hw) && adapter->base_time)  		return -EALREADY;  	if (!validate_schedule(adapter, qopt)) @@ -6201,12 +6225,35 @@ static int igc_tsn_enable_cbs(struct igc_adapter *adapter,  	return igc_tsn_offload_apply(adapter);  } +static int igc_tc_query_caps(struct igc_adapter *adapter, +			     struct tc_query_caps_base *base) +{ +	struct igc_hw *hw = &adapter->hw; + +	switch (base->type) { +	case TC_SETUP_QDISC_TAPRIO: { +		struct tc_taprio_caps *caps = base->caps; + +		caps->broken_mqprio = true; + +		if (hw->mac.type == igc_i225) +			caps->gate_mask_per_txq = true; + +		return 0; +	} +	default: +		return -EOPNOTSUPP; +	} +} +  static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type,  			void *type_data)  {  	struct igc_adapter *adapter = netdev_priv(dev);  	switch (type) { +	case TC_QUERY_CAPS: +		return igc_tc_query_caps(adapter, type_data);  	case TC_SETUP_QDISC_TAPRIO:  		return igc_tsn_enable_qbv_scheduling(adapter, type_data); @@ -6320,6 +6367,7 @@ static const struct net_device_ops igc_netdev_ops = {  	.ndo_set_rx_mode	= igc_set_rx_mode,  	.ndo_set_mac_address	= igc_set_mac,  	.ndo_change_mtu		= igc_change_mtu, +	.ndo_tx_timeout		= igc_tx_timeout,  	.ndo_get_stats64	= igc_get_stats64,  	.ndo_fix_features	= igc_fix_features,  	.ndo_set_features	= igc_set_features, @@ -6430,8 +6478,6 @@ static int igc_probe(struct pci_dev *pdev,  	if (err)  		goto err_pci_reg; -	pci_enable_pcie_error_reporting(pdev); -  	err = pci_enable_ptm(pdev, NULL);  	if (err < 0)  		dev_info(&pdev->dev, "PCIe PTM not supported by PCIe bus/controller\n"); @@ -6529,6 +6575,9 @@ static int igc_probe(struct pci_dev *pdev,  	netdev->mpls_features |= NETIF_F_HW_CSUM;  	netdev->hw_enc_features |= netdev->vlan_features; +	netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | +			       NETDEV_XDP_ACT_XSK_ZEROCOPY; +  	/* MTU range: 68 - 9216 */  	netdev->min_mtu = ETH_MIN_MTU;  	netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; @@ -6636,7 +6685,6 @@ err_sw_init:  err_ioremap:  	free_netdev(netdev);  err_alloc_etherdev: -	pci_disable_pcie_error_reporting(pdev);  	pci_release_mem_regions(pdev);  err_pci_reg:  err_dma: @@ -6684,8 +6732,6 @@ static void igc_remove(struct pci_dev *pdev)  	free_netdev(netdev); -	pci_disable_pcie_error_reporting(pdev); -  	pci_disable_device(pdev);  } diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 8dbb9f903ca7..4e10ced736db 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -322,7 +322,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,  		ts = ns_to_timespec64(ns);  		if (rq->perout.index == 1) {  			if (use_freq) { -				tsauxc_mask = IGC_TSAUXC_EN_CLK1; +				tsauxc_mask = IGC_TSAUXC_EN_CLK1 | IGC_TSAUXC_ST1;  				tsim_mask = 0;  			} else {  				tsauxc_mask = IGC_TSAUXC_EN_TT1; @@ -333,7 +333,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,  			freqout = IGC_FREQOUT1;  		} else {  			if (use_freq) { -				tsauxc_mask = IGC_TSAUXC_EN_CLK0; +				tsauxc_mask = IGC_TSAUXC_EN_CLK0 | IGC_TSAUXC_ST0;  				tsim_mask = 0;  			} else {  				tsauxc_mask = IGC_TSAUXC_EN_TT0; @@ -347,10 +347,12 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,  		tsauxc = rd32(IGC_TSAUXC);  		tsim = rd32(IGC_TSIM);  		if (rq->perout.index == 1) { -			tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1); +			tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1 | +				    IGC_TSAUXC_ST1);  			tsim &= ~IGC_TSICR_TT1;  		} else { -			tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0); +			tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0 | +				    IGC_TSAUXC_ST0);  			tsim &= ~IGC_TSICR_TT0;  		}  		if (on) { @@ -415,10 +417,12 @@ static int igc_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,   *   * We need to convert the system time value stored in the RX/TXSTMP registers   * into a hwtstamp which can be used by the upper level timestamping functions. + * + * Returns 0 on success.   **/ -static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, -				       struct skb_shared_hwtstamps *hwtstamps, -				       u64 systim) +static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, +				      struct skb_shared_hwtstamps *hwtstamps, +				      u64 systim)  {  	switch (adapter->hw.mac.type) {  	case igc_i225: @@ -428,8 +432,9 @@ static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,  						systim & 0xFFFFFFFF);  		break;  	default: -		break; +		return -EINVAL;  	} +	return 0;  }  /** @@ -650,7 +655,8 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)  	regval = rd32(IGC_TXSTMPL);  	regval |= (u64)rd32(IGC_TXSTMPH) << 32; -	igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); +	if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval)) +		return;  	switch (adapter->link_speed) {  	case SPEED_10: diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c index bb10d7b65232..a386c8d61dbf 100644 --- a/drivers/net/ethernet/intel/igc/igc_tsn.c +++ b/drivers/net/ethernet/intel/igc/igc_tsn.c @@ -2,6 +2,7 @@  /* Copyright (c)  2019 Intel Corporation */  #include "igc.h" +#include "igc_hw.h"  #include "igc_tsn.h"  static bool is_any_launchtime(struct igc_adapter *adapter) @@ -92,7 +93,8 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)  	tqavctrl = rd32(IGC_TQAVCTRL);  	tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN | -		      IGC_TQAVCTRL_ENHANCED_QAV); +		      IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS); +  	wr32(IGC_TQAVCTRL, tqavctrl);  	for (i = 0; i < adapter->num_tx_queues; i++) { @@ -117,20 +119,10 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)  	ktime_t base_time, systim;  	int i; -	cycle = adapter->cycle_time; -	base_time = adapter->base_time; -  	wr32(IGC_TSAUXC, 0);  	wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);  	wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN); -	tqavctrl = rd32(IGC_TQAVCTRL); -	tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV; -	wr32(IGC_TQAVCTRL, tqavctrl); - -	wr32(IGC_QBVCYCLET_S, cycle); -	wr32(IGC_QBVCYCLET, cycle); -  	for (i = 0; i < adapter->num_tx_queues; i++) {  		struct igc_ring *ring = adapter->tx_ring[i];  		u32 txqctl = 0; @@ -233,21 +225,46 @@ skip_cbs:  		wr32(IGC_TXQCTL(i), txqctl);  	} +	tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS; +	tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV; + +	cycle = adapter->cycle_time; +	base_time = adapter->base_time; +  	nsec = rd32(IGC_SYSTIML);  	sec = rd32(IGC_SYSTIMH);  	systim = ktime_set(sec, nsec); -  	if (ktime_compare(systim, base_time) > 0) { -		s64 n; +		s64 n = div64_s64(ktime_sub_ns(systim, base_time), cycle); -		n = div64_s64(ktime_sub_ns(systim, base_time), cycle);  		base_time = ktime_add_ns(base_time, (n + 1) * cycle); +	} 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;  	} -	baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l); +	wr32(IGC_TQAVCTRL, tqavctrl); + +	wr32(IGC_QBVCYCLET_S, cycle); +	wr32(IGC_QBVCYCLET, cycle); +	baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);  	wr32(IGC_BASET_H, baset_h); + +	/* In i226, Future base time is only supported when FutScdDis bit +	 * is enabled and only active for re-configuration. +	 * In this case, initialize the base time with zero to create +	 * "re-configuration" scenario then only set the desired base time. +	 */ +	if (tqavctrl & IGC_TQAVCTRL_FUTSCDDIS) +		wr32(IGC_BASET_L, 0);  	wr32(IGC_BASET_L, baset_l);  	return 0; @@ -274,17 +291,14 @@ int igc_tsn_reset(struct igc_adapter *adapter)  int igc_tsn_offload_apply(struct igc_adapter *adapter)  { -	int err; +	struct igc_hw *hw = &adapter->hw; -	if (netif_running(adapter->netdev)) { +	if (netif_running(adapter->netdev) && igc_is_device_id_i225(hw)) {  		schedule_work(&adapter->reset_task);  		return 0;  	} -	err = igc_tsn_enable_offload(adapter); -	if (err < 0) -		return err; +	igc_tsn_reset(adapter); -	adapter->flags = igc_tsn_new_flags(adapter);  	return 0;  } diff --git a/drivers/net/ethernet/intel/igc/igc_xdp.c b/drivers/net/ethernet/intel/igc/igc_xdp.c index aeeb34e64610..e27af72aada8 100644 --- a/drivers/net/ethernet/intel/igc/igc_xdp.c +++ b/drivers/net/ethernet/intel/igc/igc_xdp.c @@ -29,6 +29,11 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,  	if (old_prog)  		bpf_prog_put(old_prog); +	if (prog) +		xdp_features_set_redirect_target(dev, true); +	else +		xdp_features_clear_redirect_target(dev); +  	if (if_running)  		igc_open(dev); |