diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc')
| -rw-r--r-- | drivers/net/ethernet/intel/igc/Makefile | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc.h | 47 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_base.c | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_defines.h | 102 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_ethtool.c | 34 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_hw.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 2945 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_phy.c | 16 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_ptp.c | 716 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_regs.h | 37 | 
10 files changed, 2619 insertions, 1284 deletions
| diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 88c6f88baac5..49fb1e1965cd 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -8,4 +8,4 @@  obj-$(CONFIG_IGC) += igc.o  igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \ -igc_ethtool.o +igc_ethtool.o igc_ptp.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 0868677d43ed..52066bdbbad0 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -10,6 +10,9 @@  #include <linux/vmalloc.h>  #include <linux/ethtool.h>  #include <linux/sctp.h> +#include <linux/ptp_clock_kernel.h> +#include <linux/timecounter.h> +#include <linux/net_tstamp.h>  #include "igc_hw.h" @@ -45,11 +48,15 @@ extern char igc_driver_version[];  #define IGC_REGS_LEN			740  #define IGC_RETA_SIZE			128 +/* flags controlling PTP/1588 function */ +#define IGC_PTP_ENABLED		BIT(0) +  /* Interrupt defines */  #define IGC_START_ITR			648 /* ~6000 ints/sec */  #define IGC_FLAG_HAS_MSI		BIT(0)  #define IGC_FLAG_QUEUE_PAIRS		BIT(3)  #define IGC_FLAG_DMAC			BIT(4) +#define IGC_FLAG_PTP			BIT(8)  #define IGC_FLAG_NEED_LINK_UPDATE	BIT(9)  #define IGC_FLAG_MEDIA_RESET		BIT(10)  #define IGC_FLAG_MAS_ENABLE		BIT(12) @@ -100,6 +107,20 @@ extern char igc_driver_version[];  #define AUTO_ALL_MODES		0  #define IGC_RX_HDR_LEN			IGC_RXBUFFER_256 +/* Transmit and receive latency (for PTP timestamps) */ +/* FIXME: These values were estimated using the ones that i210 has as + * basis, they seem to provide good numbers with ptp4l/phc2sys, but we + * need to confirm them. + */ +#define IGC_I225_TX_LATENCY_10		9542 +#define IGC_I225_TX_LATENCY_100		1024 +#define IGC_I225_TX_LATENCY_1000	178 +#define IGC_I225_TX_LATENCY_2500	64 +#define IGC_I225_RX_LATENCY_10		20662 +#define IGC_I225_RX_LATENCY_100		2213 +#define IGC_I225_RX_LATENCY_1000	448 +#define IGC_I225_RX_LATENCY_2500	160 +  /* RX and TX descriptor control thresholds.   * PTHRESH - MAC will consider prefetch if it has fewer than this number of   *           descriptors available in its onboard memory. @@ -370,6 +391,8 @@ struct igc_adapter {  	struct timer_list dma_err_timer;  	struct timer_list phy_info_timer; +	u32 wol; +	u32 en_mng_pt;  	u16 link_speed;  	u16 link_duplex; @@ -430,6 +453,20 @@ struct igc_adapter {  	unsigned long link_check_timeout;  	struct igc_info ei; + +	struct ptp_clock *ptp_clock; +	struct ptp_clock_info ptp_caps; +	struct work_struct ptp_tx_work; +	struct sk_buff *ptp_tx_skb; +	struct hwtstamp_config tstamp_config; +	unsigned long ptp_tx_start; +	unsigned long last_rx_ptp_check; +	unsigned long last_rx_timestamp; +	unsigned int ptp_flags; +	/* System time value lock */ +	spinlock_t tmreg_lock; +	struct cyclecounter cc; +	struct timecounter tc;  };  /* igc_desc_unused - calculate if we have unused descriptors */ @@ -513,6 +550,16 @@ int igc_add_filter(struct igc_adapter *adapter,  int igc_erase_filter(struct igc_adapter *adapter,  		     struct igc_nfc_filter *input); +void igc_ptp_init(struct igc_adapter *adapter); +void igc_ptp_reset(struct igc_adapter *adapter); +void igc_ptp_stop(struct igc_adapter *adapter); +void igc_ptp_rx_rgtstamp(struct igc_q_vector *q_vector, struct sk_buff *skb); +void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, void *va, +			 struct sk_buff *skb); +int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr); +int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr); +void igc_ptp_tx_hang(struct igc_adapter *adapter); +  #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))  #define IGC_TXD_DCMD	(IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS) diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index db289bcce21d..5a506440560a 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -212,6 +212,7 @@ static s32 igc_get_invariants_base(struct igc_hw *hw)  	case IGC_DEV_ID_I225_I:  	case IGC_DEV_ID_I220_V:  	case IGC_DEV_ID_I225_K: +	case IGC_DEV_ID_I225_BLANK_NVM:  		mac->type = igc_i225;  		break;  	default: diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index f3788f0b95b4..58efa7a02c68 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -10,6 +10,37 @@  #define IGC_CTRL_EXT_DRV_LOAD	0x10000000 /* Drv loaded bit for FW */ +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define IGC_WUC_PME_EN	0x00000002 /* PME Enable */ + +/* Wake Up Filter Control */ +#define IGC_WUFC_LNKC	0x00000001 /* Link Status Change Wakeup Enable */ +#define IGC_WUFC_MC	0x00000008 /* Directed Multicast Wakeup Enable */ + +#define IGC_CTRL_ADVD3WUC	0x00100000  /* D3 WUC */ + +/* Wake Up Status */ +#define IGC_WUS_EX	0x00000004 /* Directed Exact */ +#define IGC_WUS_ARPD	0x00000020 /* Directed ARP Request */ +#define IGC_WUS_IPV4	0x00000040 /* Directed IPv4 */ +#define IGC_WUS_IPV6	0x00000080 /* Directed IPv6 */ +#define IGC_WUS_NSD	0x00000400 /* Directed IPv6 Neighbor Solicitation */ + +/* Packet types that are enabled for wake packet delivery */ +#define WAKE_PKT_WUS ( \ +	IGC_WUS_EX   | \ +	IGC_WUS_ARPD | \ +	IGC_WUS_IPV4 | \ +	IGC_WUS_IPV6 | \ +	IGC_WUS_NSD) + +/* Wake Up Packet Length */ +#define IGC_WUPL_MASK	0x00000FFF + +/* Wake Up Packet Memory stores the first 128 bytes of the wake up packet */ +#define IGC_WUPM_BYTES	128 +  /* Physical Func Reset Done Indication */  #define IGC_CTRL_EXT_LINK_MODE_MASK	0x00C00000 @@ -187,6 +218,7 @@  #define IGC_ICR_RXDMT0		BIT(4)	/* Rx desc min. threshold (0) */  #define IGC_ICR_RXO		BIT(6)	/* Rx overrun */  #define IGC_ICR_RXT0		BIT(7)	/* Rx timer intr (ring 0) */ +#define IGC_ICR_TS		BIT(19)	/* Time Sync Interrupt */  #define IGC_ICR_DRSTA		BIT(30)	/* Device Reset Asserted */  /* If this bit asserted, the driver should claim the interrupt */ @@ -209,6 +241,7 @@  #define IGC_IMS_DRSTA		IGC_ICR_DRSTA	/* Device Reset Asserted */  #define IGC_IMS_RXT0		IGC_ICR_RXT0	/* Rx timer intr */  #define IGC_IMS_RXDMT0		IGC_ICR_RXDMT0	/* Rx desc min. threshold */ +#define IGC_IMS_TS		IGC_ICR_TS	/* Time Sync Interrupt */  #define IGC_QVECTOR_MASK	0x7FFC		/* Q-vector mask */  #define IGC_ITR_VAL_MASK	0x04		/* ITR value mask */ @@ -249,6 +282,10 @@  #define IGC_TXD_STAT_TC		0x00000004 /* Tx Underrun */  #define IGC_TXD_EXTCMD_TSTAMP	0x00000010 /* IEEE1588 Timestamp packet */ +/* IPSec Encrypt Enable */ +#define IGC_ADVTXD_L4LEN_SHIFT	8  /* Adv ctxt L4LEN shift */ +#define IGC_ADVTXD_MSS_SHIFT	16 /* Adv ctxt MSS shift */ +  /* Transmit Control */  #define IGC_TCTL_EN		0x00000002 /* enable Tx */  #define IGC_TCTL_PSP		0x00000008 /* pad short packets */ @@ -281,12 +318,21 @@  #define IGC_RCTL_RDMTS_HALF	0x00000000 /* Rx desc min thresh size */  #define IGC_RCTL_BAM		0x00008000 /* broadcast enable */ +/* Split Replication Receive Control */ +#define IGC_SRRCTL_TIMESTAMP		0x40000000 +#define IGC_SRRCTL_TIMER1SEL(timer)	(((timer) & 0x3) << 14) +#define IGC_SRRCTL_TIMER0SEL(timer)	(((timer) & 0x3) << 17) +  /* Receive Descriptor bit definitions */  #define IGC_RXD_STAT_EOP	0x02	/* End of Packet */  #define IGC_RXD_STAT_IXSM	0x04	/* Ignore checksum */  #define IGC_RXD_STAT_UDPCS	0x10	/* UDP xsum calculated */  #define IGC_RXD_STAT_TCPCS	0x20	/* TCP xsum calculated */ +/* Advanced Receive Descriptor bit definitions */ +#define IGC_RXDADV_STAT_TSIP	0x08000 /* timestamp in packet */ +#define IGC_RXDADV_STAT_TS	0x10000 /* Pkt was time stamped */ +  #define IGC_RXDEXT_STATERR_CE		0x01000000  #define IGC_RXDEXT_STATERR_SE		0x02000000  #define IGC_RXDEXT_STATERR_SEQ		0x04000000 @@ -323,6 +369,61 @@  #define I225_RXPBSIZE_DEFAULT	0x000000A2 /* RXPBSIZE default */  #define I225_TXPBSIZE_DEFAULT	0x04000014 /* TXPBSIZE default */ +#define IGC_RXPBS_CFG_TS_EN	0x80000000 /* Timestamp in Rx buffer */ + +/* Time Sync Interrupt Causes */ +#define IGC_TSICR_SYS_WRAP	BIT(0) /* SYSTIM Wrap around. */ +#define IGC_TSICR_TXTS		BIT(1) /* Transmit Timestamp. */ +#define IGC_TSICR_TT0		BIT(3) /* Target Time 0 Trigger. */ +#define IGC_TSICR_TT1		BIT(4) /* Target Time 1 Trigger. */ +#define IGC_TSICR_AUTT0		BIT(5) /* Auxiliary Timestamp 0 Taken. */ +#define IGC_TSICR_AUTT1		BIT(6) /* Auxiliary Timestamp 1 Taken. */ + +#define IGC_TSICR_INTERRUPTS	IGC_TSICR_TXTS + +/* PTP Queue Filter */ +#define IGC_ETQF_1588		BIT(30) + +#define IGC_FTQF_VF_BP		0x00008000 +#define IGC_FTQF_1588_TIME_STAMP	0x08000000 +#define IGC_FTQF_MASK			0xF0000000 +#define IGC_FTQF_MASK_PROTO_BP	0x10000000 + +/* Time Sync Receive Control bit definitions */ +#define IGC_TSYNCRXCTL_VALID		0x00000001  /* Rx timestamp valid */ +#define IGC_TSYNCRXCTL_TYPE_MASK	0x0000000E  /* Rx type mask */ +#define IGC_TSYNCRXCTL_TYPE_L2_V2	0x00 +#define IGC_TSYNCRXCTL_TYPE_L4_V1	0x02 +#define IGC_TSYNCRXCTL_TYPE_L2_L4_V2	0x04 +#define IGC_TSYNCRXCTL_TYPE_ALL		0x08 +#define IGC_TSYNCRXCTL_TYPE_EVENT_V2	0x0A +#define IGC_TSYNCRXCTL_ENABLED		0x00000010  /* enable Rx timestamping */ +#define IGC_TSYNCRXCTL_SYSCFI		0x00000020  /* Sys clock frequency */ +#define IGC_TSYNCRXCTL_RXSYNSIG		0x00000400  /* Sample RX tstamp in PHY sop */ + +/* Time Sync Receive Configuration */ +#define IGC_TSYNCRXCFG_PTP_V1_CTRLT_MASK	0x000000FF +#define IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE	0x00 +#define IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE	0x01 + +/* Immediate Interrupt Receive */ +#define IGC_IMIR_CLEAR_MASK	0xF001FFFF /* IMIR Reg Clear Mask */ +#define IGC_IMIR_PORT_BYPASS	0x20000 /* IMIR Port Bypass Bit */ +#define IGC_IMIR_PRIORITY_SHIFT	29 /* IMIR Priority Shift */ +#define IGC_IMIREXT_CLEAR_MASK	0x7FFFF /* IMIREXT Reg Clear Mask */ + +/* Immediate Interrupt Receive Extended */ +#define IGC_IMIREXT_CTRL_BP	0x00080000  /* Bypass check of ctrl bits */ +#define IGC_IMIREXT_SIZE_BP	0x00001000  /* Packet size bypass */ + +/* Time Sync Transmit Control bit definitions */ +#define IGC_TSYNCTXCTL_VALID			0x00000001  /* Tx timestamp valid */ +#define IGC_TSYNCTXCTL_ENABLED			0x00000010  /* enable Tx timestamping */ +#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK	0x0000F000  /* max delay */ +#define IGC_TSYNCTXCTL_SYNC_COMP_ERR		0x20000000  /* sync err */ +#define IGC_TSYNCTXCTL_SYNC_COMP		0x40000000  /* sync complete */ +#define IGC_TSYNCTXCTL_START_SYNC		0x80000000  /* initiate sync */ +#define IGC_TSYNCTXCTL_TXSYNSIG			0x00000020  /* Sample TX tstamp in PHY sop */  /* Receive Checksum Control */  #define IGC_RXCSUM_CRCOFL	0x00000800   /* CRC32 offload enable */ @@ -363,6 +464,7 @@  /* PHY Status Register */  #define MII_SR_LINK_STATUS	0x0004 /* Link Status 1 = link */  #define MII_SR_AUTONEG_COMPLETE	0x0020 /* Auto Neg Complete */ +#define IGC_PHY_RST_COMP	0x0100 /* Internal PHY reset completion */  /* PHY 1000 MII Register/Bit Definitions */  /* PHY Registers defined by IEEE */ diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 455c1cdceb6e..ee07011e13e9 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1600,6 +1600,39 @@ static int igc_set_channels(struct net_device *netdev,  	return 0;  } +static int igc_get_ts_info(struct net_device *dev, +			   struct ethtool_ts_info *info) +{ +	struct igc_adapter *adapter = netdev_priv(dev); + +	if (adapter->ptp_clock) +		info->phc_index = ptp_clock_index(adapter->ptp_clock); +	else +		info->phc_index = -1; + +	switch (adapter->hw.mac.type) { +	case igc_i225: +		info->so_timestamping = +			SOF_TIMESTAMPING_TX_SOFTWARE | +			SOF_TIMESTAMPING_RX_SOFTWARE | +			SOF_TIMESTAMPING_SOFTWARE | +			SOF_TIMESTAMPING_TX_HARDWARE | +			SOF_TIMESTAMPING_RX_HARDWARE | +			SOF_TIMESTAMPING_RAW_HARDWARE; + +		info->tx_types = +			BIT(HWTSTAMP_TX_OFF) | +			BIT(HWTSTAMP_TX_ON); + +		info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); +		info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL); + +		return 0; +	default: +		return -EOPNOTSUPP; +	} +} +  static u32 igc_get_priv_flags(struct net_device *netdev)  {  	struct igc_adapter *adapter = netdev_priv(netdev); @@ -1847,6 +1880,7 @@ static const struct ethtool_ops igc_ethtool_ops = {  	.get_rxfh_indir_size	= igc_get_rxfh_indir_size,  	.get_rxfh		= igc_get_rxfh,  	.set_rxfh		= igc_set_rxfh, +	.get_ts_info		= igc_get_ts_info,  	.get_channels		= igc_get_channels,  	.set_channels		= igc_set_channels,  	.get_priv_flags		= igc_get_priv_flags, diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 20f710645746..90ac0e0144d8 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -21,8 +21,7 @@  #define IGC_DEV_ID_I225_I			0x15F8  #define IGC_DEV_ID_I220_V			0x15F7  #define IGC_DEV_ID_I225_K			0x3100 - -#define IGC_FUNC_0				0 +#define IGC_DEV_ID_I225_BLANK_NVM		0x15FD  /* Function pointers for the MAC. */  struct igc_mac_operations { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 9700527dd797..d9d5425fe8d9 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -8,6 +8,7 @@  #include <linux/tcp.h>  #include <linux/udp.h>  #include <linux/ip.h> +#include <linux/pm_runtime.h>  #include <net/ipv6.h> @@ -44,31 +45,13 @@ static const struct pci_device_id igc_pci_tbl[] = {  	{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_I), board_base },  	{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I220_V), board_base },  	{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_K), board_base }, +	{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_BLANK_NVM), board_base },  	/* required last entry */  	{0, }  };  MODULE_DEVICE_TABLE(pci, igc_pci_tbl); -/* forward declaration */ -static void igc_clean_tx_ring(struct igc_ring *tx_ring); -static int igc_sw_init(struct igc_adapter *); -static void igc_configure(struct igc_adapter *adapter); -static void igc_power_down_link(struct igc_adapter *adapter); -static void igc_set_default_mac_filter(struct igc_adapter *adapter); -static void igc_set_rx_mode(struct net_device *netdev); -static void igc_write_itr(struct igc_q_vector *q_vector); -static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector); -static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx); -static void igc_set_interrupt_capability(struct igc_adapter *adapter, -					 bool msix); -static void igc_free_q_vectors(struct igc_adapter *adapter); -static void igc_irq_disable(struct igc_adapter *adapter); -static void igc_irq_enable(struct igc_adapter *adapter); -static void igc_configure_msix(struct igc_adapter *adapter); -static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, -				  struct igc_rx_buffer *bi); -  enum latency_range {  	lowest_latency = 0,  	low_latency = 1, @@ -76,6 +59,16 @@ enum latency_range {  	latency_invalid = 255  }; +/** + * igc_power_down_link - Power down the phy/serdes link + * @adapter: address of board private structure + */ +static void igc_power_down_link(struct igc_adapter *adapter) +{ +	if (adapter->hw.phy.media_type == igc_media_type_copper) +		igc_power_down_phy_copper_base(&adapter->hw); +} +  void igc_reset(struct igc_adapter *adapter)  {  	struct pci_dev *pdev = adapter->pdev; @@ -110,11 +103,14 @@ void igc_reset(struct igc_adapter *adapter)  	if (!netif_running(adapter->netdev))  		igc_power_down_link(adapter); +	/* Re-enable PTP, where applicable. */ +	igc_ptp_reset(adapter); +  	igc_get_phy_info(hw);  }  /** - * igc_power_up_link - Power up the phy/serdes link + * igc_power_up_link - Power up the phy link   * @adapter: address of board private structure   */  static void igc_power_up_link(struct igc_adapter *adapter) @@ -128,16 +124,6 @@ static void igc_power_up_link(struct igc_adapter *adapter)  }  /** - * igc_power_down_link - Power down the phy/serdes link - * @adapter: address of board private structure - */ -static void igc_power_down_link(struct igc_adapter *adapter) -{ -	if (adapter->hw.phy.media_type == igc_media_type_copper) -		igc_power_down_phy_copper_base(&adapter->hw); -} - -/**   * igc_release_hw_control - release control of the h/w to f/w   * @adapter: address of board private structure   * @@ -176,43 +162,6 @@ static void igc_get_hw_control(struct igc_adapter *adapter)  }  /** - * igc_free_tx_resources - Free Tx Resources per Queue - * @tx_ring: Tx descriptor ring for a specific queue - * - * Free all transmit software resources - */ -void igc_free_tx_resources(struct igc_ring *tx_ring) -{ -	igc_clean_tx_ring(tx_ring); - -	vfree(tx_ring->tx_buffer_info); -	tx_ring->tx_buffer_info = NULL; - -	/* if not set, then don't free */ -	if (!tx_ring->desc) -		return; - -	dma_free_coherent(tx_ring->dev, tx_ring->size, -			  tx_ring->desc, tx_ring->dma); - -	tx_ring->desc = NULL; -} - -/** - * igc_free_all_tx_resources - Free Tx Resources for All Queues - * @adapter: board private structure - * - * Free all transmit software resources - */ -static void igc_free_all_tx_resources(struct igc_adapter *adapter) -{ -	int i; - -	for (i = 0; i < adapter->num_tx_queues; i++) -		igc_free_tx_resources(adapter->tx_ring[i]); -} - -/**   * igc_clean_tx_ring - Free Tx Buffers   * @tx_ring: ring to be cleaned   */ @@ -274,6 +223,43 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)  }  /** + * igc_free_tx_resources - Free Tx Resources per Queue + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + */ +void igc_free_tx_resources(struct igc_ring *tx_ring) +{ +	igc_clean_tx_ring(tx_ring); + +	vfree(tx_ring->tx_buffer_info); +	tx_ring->tx_buffer_info = NULL; + +	/* if not set, then don't free */ +	if (!tx_ring->desc) +		return; + +	dma_free_coherent(tx_ring->dev, tx_ring->size, +			  tx_ring->desc, tx_ring->dma); + +	tx_ring->desc = NULL; +} + +/** + * igc_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + */ +static void igc_free_all_tx_resources(struct igc_adapter *adapter) +{ +	int i; + +	for (i = 0; i < adapter->num_tx_queues; i++) +		igc_free_tx_resources(adapter->tx_ring[i]); +} + +/**   * igc_clean_all_tx_rings - Free Tx Buffers for all queues   * @adapter: board private structure   */ @@ -771,6 +757,51 @@ static void igc_setup_tctl(struct igc_adapter *adapter)  }  /** + * igc_rar_set_index - Sync RAL[index] and RAH[index] registers with MAC table + * @adapter: address of board private structure + * @index: Index of the RAR entry which need to be synced with MAC table + */ +static void igc_rar_set_index(struct igc_adapter *adapter, u32 index) +{ +	u8 *addr = adapter->mac_table[index].addr; +	struct igc_hw *hw = &adapter->hw; +	u32 rar_low, rar_high; + +	/* HW expects these to be in network order when they are plugged +	 * into the registers which are little endian.  In order to guarantee +	 * that ordering we need to do an leXX_to_cpup here in order to be +	 * ready for the byteswap that occurs with writel +	 */ +	rar_low = le32_to_cpup((__le32 *)(addr)); +	rar_high = le16_to_cpup((__le16 *)(addr + 4)); + +	/* Indicate to hardware the Address is Valid. */ +	if (adapter->mac_table[index].state & IGC_MAC_STATE_IN_USE) { +		if (is_valid_ether_addr(addr)) +			rar_high |= IGC_RAH_AV; + +		rar_high |= IGC_RAH_POOL_1 << +			adapter->mac_table[index].queue; +	} + +	wr32(IGC_RAL(index), rar_low); +	wrfl(); +	wr32(IGC_RAH(index), rar_high); +	wrfl(); +} + +/* Set default MAC address for the PF in the first RAR entry */ +static void igc_set_default_mac_filter(struct igc_adapter *adapter) +{ +	struct igc_mac_addr *mac_table = &adapter->mac_table[0]; + +	ether_addr_copy(mac_table->addr, adapter->hw.mac.addr); +	mac_table->state = IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; + +	igc_rar_set_index(adapter, 0); +} + +/**   * igc_set_mac - Change the Ethernet Address of the NIC   * @netdev: network interface device structure   * @p: pointer to an address structure @@ -850,7 +881,7 @@ static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,  	/* set bits to identify this as an advanced context descriptor */  	type_tucmd |= IGC_TXD_CMD_DEXT | IGC_ADVTXD_DTYP_CTXT; -	/* For 82575, context index must be unique per ring. */ +	/* For i225, context index must be unique per ring. */  	if (test_bit(IGC_RING_FLAG_TX_CTX_IDX, &tx_ring->flags))  		mss_l4len_idx |= tx_ring->reg_idx << 4; @@ -957,6 +988,11 @@ static inline int igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size)  	return __igc_maybe_stop_tx(tx_ring, size);  } +#define IGC_SET_FLAG(_input, _flag, _result) \ +	(((_flag) <= (_result)) ?				\ +	 ((u32)((_input) & (_flag)) * ((_result) / (_flag))) :	\ +	 ((u32)((_input) & (_flag)) / ((_flag) / (_result)))) +  static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)  {  	/* set type for advanced descriptor with frame checksum insertion */ @@ -964,6 +1000,14 @@ static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)  		       IGC_ADVTXD_DCMD_DEXT |  		       IGC_ADVTXD_DCMD_IFCS; +	/* set segmentation bits for TSO */ +	cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO, +				 (IGC_ADVTXD_DCMD_TSE)); + +	/* set timestamp bit if present */ +	cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP, +				 (IGC_ADVTXD_MAC_TSTAMP)); +  	return cmd_type;  } @@ -1131,6 +1175,100 @@ dma_error:  	return -1;  } +static int igc_tso(struct igc_ring *tx_ring, +		   struct igc_tx_buffer *first, +		   u8 *hdr_len) +{ +	u32 vlan_macip_lens, type_tucmd, mss_l4len_idx; +	struct sk_buff *skb = first->skb; +	union { +		struct iphdr *v4; +		struct ipv6hdr *v6; +		unsigned char *hdr; +	} ip; +	union { +		struct tcphdr *tcp; +		struct udphdr *udp; +		unsigned char *hdr; +	} l4; +	u32 paylen, l4_offset; +	int err; + +	if (skb->ip_summed != CHECKSUM_PARTIAL) +		return 0; + +	if (!skb_is_gso(skb)) +		return 0; + +	err = skb_cow_head(skb, 0); +	if (err < 0) +		return err; + +	ip.hdr = skb_network_header(skb); +	l4.hdr = skb_checksum_start(skb); + +	/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ +	type_tucmd = IGC_ADVTXD_TUCMD_L4T_TCP; + +	/* initialize outer IP header fields */ +	if (ip.v4->version == 4) { +		unsigned char *csum_start = skb_checksum_start(skb); +		unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4); + +		/* IP header will have to cancel out any data that +		 * is not a part of the outer IP header +		 */ +		ip.v4->check = csum_fold(csum_partial(trans_start, +						      csum_start - trans_start, +						      0)); +		type_tucmd |= IGC_ADVTXD_TUCMD_IPV4; + +		ip.v4->tot_len = 0; +		first->tx_flags |= IGC_TX_FLAGS_TSO | +				   IGC_TX_FLAGS_CSUM | +				   IGC_TX_FLAGS_IPV4; +	} else { +		ip.v6->payload_len = 0; +		first->tx_flags |= IGC_TX_FLAGS_TSO | +				   IGC_TX_FLAGS_CSUM; +	} + +	/* determine offset of inner transport header */ +	l4_offset = l4.hdr - skb->data; + +	/* remove payload length from inner checksum */ +	paylen = skb->len - l4_offset; +	if (type_tucmd & IGC_ADVTXD_TUCMD_L4T_TCP) { +		/* compute length of segmentation header */ +		*hdr_len = (l4.tcp->doff * 4) + l4_offset; +		csum_replace_by_diff(&l4.tcp->check, +				     (__force __wsum)htonl(paylen)); +	} else { +		/* compute length of segmentation header */ +		*hdr_len = sizeof(*l4.udp) + l4_offset; +		csum_replace_by_diff(&l4.udp->check, +				     (__force __wsum)htonl(paylen)); +	} + +	/* update gso size and bytecount with header size */ +	first->gso_segs = skb_shinfo(skb)->gso_segs; +	first->bytecount += (first->gso_segs - 1) * *hdr_len; + +	/* MSS L4LEN IDX */ +	mss_l4len_idx = (*hdr_len - l4_offset) << IGC_ADVTXD_L4LEN_SHIFT; +	mss_l4len_idx |= skb_shinfo(skb)->gso_size << IGC_ADVTXD_MSS_SHIFT; + +	/* VLAN MACLEN IPLEN */ +	vlan_macip_lens = l4.hdr - ip.hdr; +	vlan_macip_lens |= (ip.hdr - skb->data) << IGC_ADVTXD_MACLEN_SHIFT; +	vlan_macip_lens |= first->tx_flags & IGC_TX_FLAGS_VLAN_MASK; + +	igc_tx_ctxtdesc(tx_ring, first, vlan_macip_lens, +			type_tucmd, mss_l4len_idx); + +	return 1; +} +  static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,  				       struct igc_ring *tx_ring)  { @@ -1140,6 +1278,7 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,  	u32 tx_flags = 0;  	unsigned short f;  	u8 hdr_len = 0; +	int tso = 0;  	/* need: 1 descriptor per page * PAGE_SIZE/IGC_MAX_DATA_PER_TXD,  	 *	+ 1 desc for skb_headlen/IGC_MAX_DATA_PER_TXD, @@ -1162,15 +1301,45 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,  	first->bytecount = skb->len;  	first->gso_segs = 1; +	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { +		struct igc_adapter *adapter = netdev_priv(tx_ring->netdev); + +		/* FIXME: add support for retrieving timestamps from +		 * the other timer registers before skipping the +		 * timestamping request. +		 */ +		if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && +		    !test_and_set_bit_lock(__IGC_PTP_TX_IN_PROGRESS, +					   &adapter->state)) { +			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; +			tx_flags |= IGC_TX_FLAGS_TSTAMP; + +			adapter->ptp_tx_skb = skb_get(skb); +			adapter->ptp_tx_start = jiffies; +		} else { +			adapter->tx_hwtstamp_skipped++; +		} +	} +  	/* record initial flags and protocol */  	first->tx_flags = tx_flags;  	first->protocol = protocol; -	igc_tx_csum(tx_ring, first); +	tso = igc_tso(tx_ring, first, &hdr_len); +	if (tso < 0) +		goto out_drop; +	else if (!tso) +		igc_tx_csum(tx_ring, first);  	igc_tx_map(tx_ring, first, hdr_len);  	return NETDEV_TX_OK; + +out_drop: +	dev_kfree_skb_any(first->skb); +	first->skb = NULL; + +	return NETDEV_TX_OK;  }  static inline struct igc_ring *igc_tx_queue_mapping(struct igc_adapter *adapter, @@ -1269,6 +1438,10 @@ static void igc_process_skb_fields(struct igc_ring *rx_ring,  	igc_rx_checksum(rx_ring, rx_desc, skb); +	if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TS) && +	    !igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP)) +		igc_ptp_rx_rgtstamp(rx_ring->q_vector, skb); +  	skb_record_rx_queue(skb, rx_ring->queue_index);  	skb->protocol = eth_type_trans(skb, rx_ring->netdev); @@ -1388,6 +1561,12 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,  	if (unlikely(!skb))  		return NULL; +	if (unlikely(igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP))) { +		igc_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); +		va += IGC_TS_HDR_LEN; +		size -= IGC_TS_HDR_LEN; +	} +  	/* Determine available headroom for copy */  	headlen = size;  	if (headlen > IGC_RX_HDR_LEN) @@ -1485,7 +1664,6 @@ static bool igc_can_reuse_rx_page(struct igc_rx_buffer *rx_buffer)   * igc_is_non_eop - process handling of non-EOP buffers   * @rx_ring: Rx ring being processed   * @rx_desc: Rx descriptor for current buffer - * @skb: current socket buffer containing buffer in progress   *   * This function updates next to clean.  If the buffer is an EOP buffer   * this function exits returning false, otherwise it will place the @@ -1565,9 +1743,56 @@ static void igc_put_rx_buffer(struct igc_ring *rx_ring,  	rx_buffer->page = NULL;  } +static inline unsigned int igc_rx_offset(struct igc_ring *rx_ring) +{ +	return ring_uses_build_skb(rx_ring) ? IGC_SKB_PAD : 0; +} + +static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, +				  struct igc_rx_buffer *bi) +{ +	struct page *page = bi->page; +	dma_addr_t dma; + +	/* since we are recycling buffers we should seldom need to alloc */ +	if (likely(page)) +		return true; + +	/* alloc new page for storage */ +	page = dev_alloc_pages(igc_rx_pg_order(rx_ring)); +	if (unlikely(!page)) { +		rx_ring->rx_stats.alloc_failed++; +		return false; +	} + +	/* map page for use */ +	dma = dma_map_page_attrs(rx_ring->dev, page, 0, +				 igc_rx_pg_size(rx_ring), +				 DMA_FROM_DEVICE, +				 IGC_RX_DMA_ATTR); + +	/* if mapping failed free memory back to system since +	 * there isn't much point in holding memory we can't use +	 */ +	if (dma_mapping_error(rx_ring->dev, dma)) { +		__free_page(page); + +		rx_ring->rx_stats.alloc_failed++; +		return false; +	} + +	bi->dma = dma; +	bi->page = page; +	bi->page_offset = igc_rx_offset(rx_ring); +	bi->pagecnt_bias = 1; + +	return true; +} +  /**   * igc_alloc_rx_buffers - Replace used receive buffers; packet split - * @adapter: address of board private structure + * @rx_ring: rx descriptor ring + * @cleaned_count: number of buffers to clean   */  static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)  { @@ -1725,52 +1950,6 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)  	return total_packets;  } -static inline unsigned int igc_rx_offset(struct igc_ring *rx_ring) -{ -	return ring_uses_build_skb(rx_ring) ? IGC_SKB_PAD : 0; -} - -static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, -				  struct igc_rx_buffer *bi) -{ -	struct page *page = bi->page; -	dma_addr_t dma; - -	/* since we are recycling buffers we should seldom need to alloc */ -	if (likely(page)) -		return true; - -	/* alloc new page for storage */ -	page = dev_alloc_pages(igc_rx_pg_order(rx_ring)); -	if (unlikely(!page)) { -		rx_ring->rx_stats.alloc_failed++; -		return false; -	} - -	/* map page for use */ -	dma = dma_map_page_attrs(rx_ring->dev, page, 0, -				 igc_rx_pg_size(rx_ring), -				 DMA_FROM_DEVICE, -				 IGC_RX_DMA_ATTR); - -	/* if mapping failed free memory back to system since -	 * there isn't much point in holding memory we can't use -	 */ -	if (dma_mapping_error(rx_ring->dev, dma)) { -		__free_page(page); - -		rx_ring->rx_stats.alloc_failed++; -		return false; -	} - -	bi->dma = dma; -	bi->page = page; -	bi->page_offset = igc_rx_offset(rx_ring); -	bi->pagecnt_bias = 1; - -	return true; -} -  /**   * igc_clean_tx_irq - Reclaim resources after transmit completes   * @q_vector: pointer to q_vector containing needed info @@ -1942,6 +2121,1128 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)  	return !!budget;  } +static void igc_nfc_filter_restore(struct igc_adapter *adapter) +{ +	struct igc_nfc_filter *rule; + +	spin_lock(&adapter->nfc_lock); + +	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) +		igc_add_filter(adapter, rule); + +	spin_unlock(&adapter->nfc_lock); +} + +/* If the filter to be added and an already existing filter express + * the same address and address type, it should be possible to only + * override the other configurations, for example the queue to steer + * traffic. + */ +static bool igc_mac_entry_can_be_used(const struct igc_mac_addr *entry, +				      const u8 *addr, const u8 flags) +{ +	if (!(entry->state & IGC_MAC_STATE_IN_USE)) +		return true; + +	if ((entry->state & IGC_MAC_STATE_SRC_ADDR) != +	    (flags & IGC_MAC_STATE_SRC_ADDR)) +		return false; + +	if (!ether_addr_equal(addr, entry->addr)) +		return false; + +	return true; +} + +/* Add a MAC filter for 'addr' directing matching traffic to 'queue', + * 'flags' is used to indicate what kind of match is made, match is by + * default for the destination address, if matching by source address + * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_add_mac_filter(struct igc_adapter *adapter, +			      const u8 *addr, const u8 queue) +{ +	struct igc_hw *hw = &adapter->hw; +	int rar_entries = hw->mac.rar_entry_count; +	int i; + +	if (is_zero_ether_addr(addr)) +		return -EINVAL; + +	/* Search for the first empty entry in the MAC table. +	 * Do not touch entries at the end of the table reserved for the VF MAC +	 * addresses. +	 */ +	for (i = 0; i < rar_entries; i++) { +		if (!igc_mac_entry_can_be_used(&adapter->mac_table[i], +					       addr, 0)) +			continue; + +		ether_addr_copy(adapter->mac_table[i].addr, addr); +		adapter->mac_table[i].queue = queue; +		adapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE; + +		igc_rar_set_index(adapter, i); +		return i; +	} + +	return -ENOSPC; +} + +/* Remove a MAC filter for 'addr' directing matching traffic to + * 'queue', 'flags' is used to indicate what kind of match need to be + * removed, match is by default for the destination address, if + * matching by source address is to be removed the flag + * IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_del_mac_filter(struct igc_adapter *adapter, +			      const u8 *addr, const u8 queue) +{ +	struct igc_hw *hw = &adapter->hw; +	int rar_entries = hw->mac.rar_entry_count; +	int i; + +	if (is_zero_ether_addr(addr)) +		return -EINVAL; + +	/* Search for matching entry in the MAC table based on given address +	 * and queue. Do not touch entries at the end of the table reserved +	 * for the VF MAC addresses. +	 */ +	for (i = 0; i < rar_entries; i++) { +		if (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE)) +			continue; +		if (adapter->mac_table[i].state != 0) +			continue; +		if (adapter->mac_table[i].queue != queue) +			continue; +		if (!ether_addr_equal(adapter->mac_table[i].addr, addr)) +			continue; + +		/* When a filter for the default address is "deleted", +		 * we return it to its initial configuration +		 */ +		if (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) { +			adapter->mac_table[i].state = +				IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; +			adapter->mac_table[i].queue = 0; +		} else { +			adapter->mac_table[i].state = 0; +			adapter->mac_table[i].queue = 0; +			memset(adapter->mac_table[i].addr, 0, ETH_ALEN); +		} + +		igc_rar_set_index(adapter, i); +		return 0; +	} + +	return -ENOENT; +} + +static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	int ret; + +	ret = igc_add_mac_filter(adapter, addr, adapter->num_rx_queues); + +	return min_t(int, ret, 0); +} + +static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); + +	igc_del_mac_filter(adapter, addr, adapter->num_rx_queues); + +	return 0; +} + +/** + * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_rx_mode entry point is called whenever the unicast or multicast + * address lists or the network interface flags are updated.  This routine is + * responsible for configuring the hardware for proper unicast, multicast, + * promiscuous mode, and all-multi behavior. + */ +static void igc_set_rx_mode(struct net_device *netdev) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct igc_hw *hw = &adapter->hw; +	u32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE; +	int count; + +	/* Check for Promiscuous and All Multicast modes */ +	if (netdev->flags & IFF_PROMISC) { +		rctl |= IGC_RCTL_UPE | IGC_RCTL_MPE; +	} else { +		if (netdev->flags & IFF_ALLMULTI) { +			rctl |= IGC_RCTL_MPE; +		} else { +			/* Write addresses to the MTA, if the attempt fails +			 * then we should just turn on promiscuous mode so +			 * that we can at least receive multicast traffic +			 */ +			count = igc_write_mc_addr_list(netdev); +			if (count < 0) +				rctl |= IGC_RCTL_MPE; +		} +	} + +	/* Write addresses to available RAR registers, if there is not +	 * sufficient space to store all the addresses then enable +	 * unicast promiscuous mode +	 */ +	if (__dev_uc_sync(netdev, igc_uc_sync, igc_uc_unsync)) +		rctl |= IGC_RCTL_UPE; + +	/* update state of unicast and multicast */ +	rctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE); +	wr32(IGC_RCTL, rctl); + +#if (PAGE_SIZE < 8192) +	if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB) +		rlpml = IGC_MAX_FRAME_BUILD_SKB; +#endif +	wr32(IGC_RLPML, rlpml); +} + +/** + * igc_configure - configure the hardware for RX and TX + * @adapter: private board structure + */ +static void igc_configure(struct igc_adapter *adapter) +{ +	struct net_device *netdev = adapter->netdev; +	int i = 0; + +	igc_get_hw_control(adapter); +	igc_set_rx_mode(netdev); + +	igc_setup_tctl(adapter); +	igc_setup_mrqc(adapter); +	igc_setup_rctl(adapter); + +	igc_nfc_filter_restore(adapter); +	igc_configure_tx(adapter); +	igc_configure_rx(adapter); + +	igc_rx_fifo_flush_base(&adapter->hw); + +	/* call igc_desc_unused which always leaves +	 * at least 1 descriptor unused to make sure +	 * next_to_use != next_to_clean +	 */ +	for (i = 0; i < adapter->num_rx_queues; i++) { +		struct igc_ring *ring = adapter->rx_ring[i]; + +		igc_alloc_rx_buffers(ring, igc_desc_unused(ring)); +	} +} + +/** + * igc_write_ivar - configure ivar for given MSI-X vector + * @hw: pointer to the HW structure + * @msix_vector: vector number we are allocating to a given ring + * @index: row index of IVAR register to write within IVAR table + * @offset: column offset of in IVAR, should be multiple of 8 + * + * The IVAR table consists of 2 columns, + * each containing an cause allocation for an Rx and Tx ring, and a + * variable number of rows depending on the number of queues supported. + */ +static void igc_write_ivar(struct igc_hw *hw, int msix_vector, +			   int index, int offset) +{ +	u32 ivar = array_rd32(IGC_IVAR0, index); + +	/* clear any bits that are currently set */ +	ivar &= ~((u32)0xFF << offset); + +	/* write vector and valid bit */ +	ivar |= (msix_vector | IGC_IVAR_VALID) << offset; + +	array_wr32(IGC_IVAR0, index, ivar); +} + +static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector) +{ +	struct igc_adapter *adapter = q_vector->adapter; +	struct igc_hw *hw = &adapter->hw; +	int rx_queue = IGC_N0_QUEUE; +	int tx_queue = IGC_N0_QUEUE; + +	if (q_vector->rx.ring) +		rx_queue = q_vector->rx.ring->reg_idx; +	if (q_vector->tx.ring) +		tx_queue = q_vector->tx.ring->reg_idx; + +	switch (hw->mac.type) { +	case igc_i225: +		if (rx_queue > IGC_N0_QUEUE) +			igc_write_ivar(hw, msix_vector, +				       rx_queue >> 1, +				       (rx_queue & 0x1) << 4); +		if (tx_queue > IGC_N0_QUEUE) +			igc_write_ivar(hw, msix_vector, +				       tx_queue >> 1, +				       ((tx_queue & 0x1) << 4) + 8); +		q_vector->eims_value = BIT(msix_vector); +		break; +	default: +		WARN_ONCE(hw->mac.type != igc_i225, "Wrong MAC type\n"); +		break; +	} + +	/* add q_vector eims value to global eims_enable_mask */ +	adapter->eims_enable_mask |= q_vector->eims_value; + +	/* configure q_vector to set itr on first interrupt */ +	q_vector->set_itr = 1; +} + +/** + * igc_configure_msix - Configure MSI-X hardware + * @adapter: Pointer to adapter structure + * + * igc_configure_msix sets up the hardware to properly + * generate MSI-X interrupts. + */ +static void igc_configure_msix(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; +	int i, vector = 0; +	u32 tmp; + +	adapter->eims_enable_mask = 0; + +	/* set vector for other causes, i.e. link changes */ +	switch (hw->mac.type) { +	case igc_i225: +		/* Turn on MSI-X capability first, or our settings +		 * won't stick.  And it will take days to debug. +		 */ +		wr32(IGC_GPIE, IGC_GPIE_MSIX_MODE | +		     IGC_GPIE_PBA | IGC_GPIE_EIAME | +		     IGC_GPIE_NSICR); + +		/* enable msix_other interrupt */ +		adapter->eims_other = BIT(vector); +		tmp = (vector++ | IGC_IVAR_VALID) << 8; + +		wr32(IGC_IVAR_MISC, tmp); +		break; +	default: +		/* do nothing, since nothing else supports MSI-X */ +		break; +	} /* switch (hw->mac.type) */ + +	adapter->eims_enable_mask |= adapter->eims_other; + +	for (i = 0; i < adapter->num_q_vectors; i++) +		igc_assign_vector(adapter->q_vector[i], vector++); + +	wrfl(); +} + +/** + * igc_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static void igc_irq_enable(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; + +	if (adapter->msix_entries) { +		u32 ims = IGC_IMS_LSC | IGC_IMS_DOUTSYNC | IGC_IMS_DRSTA; +		u32 regval = rd32(IGC_EIAC); + +		wr32(IGC_EIAC, regval | adapter->eims_enable_mask); +		regval = rd32(IGC_EIAM); +		wr32(IGC_EIAM, regval | adapter->eims_enable_mask); +		wr32(IGC_EIMS, adapter->eims_enable_mask); +		wr32(IGC_IMS, ims); +	} else { +		wr32(IGC_IMS, IMS_ENABLE_MASK | IGC_IMS_DRSTA); +		wr32(IGC_IAM, IMS_ENABLE_MASK | IGC_IMS_DRSTA); +	} +} + +/** + * igc_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static void igc_irq_disable(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; + +	if (adapter->msix_entries) { +		u32 regval = rd32(IGC_EIAM); + +		wr32(IGC_EIAM, regval & ~adapter->eims_enable_mask); +		wr32(IGC_EIMC, adapter->eims_enable_mask); +		regval = rd32(IGC_EIAC); +		wr32(IGC_EIAC, regval & ~adapter->eims_enable_mask); +	} + +	wr32(IGC_IAM, 0); +	wr32(IGC_IMC, ~0); +	wrfl(); + +	if (adapter->msix_entries) { +		int vector = 0, i; + +		synchronize_irq(adapter->msix_entries[vector++].vector); + +		for (i = 0; i < adapter->num_q_vectors; i++) +			synchronize_irq(adapter->msix_entries[vector++].vector); +	} else { +		synchronize_irq(adapter->pdev->irq); +	} +} + +void igc_set_flag_queue_pairs(struct igc_adapter *adapter, +			      const u32 max_rss_queues) +{ +	/* Determine if we need to pair queues. */ +	/* If rss_queues > half of max_rss_queues, pair the queues in +	 * order to conserve interrupts due to limited supply. +	 */ +	if (adapter->rss_queues > (max_rss_queues / 2)) +		adapter->flags |= IGC_FLAG_QUEUE_PAIRS; +	else +		adapter->flags &= ~IGC_FLAG_QUEUE_PAIRS; +} + +unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter) +{ +	unsigned int max_rss_queues; + +	/* Determine the maximum number of RSS queues supported. */ +	max_rss_queues = IGC_MAX_RX_QUEUES; + +	return max_rss_queues; +} + +static void igc_init_queue_configuration(struct igc_adapter *adapter) +{ +	u32 max_rss_queues; + +	max_rss_queues = igc_get_max_rss_queues(adapter); +	adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus()); + +	igc_set_flag_queue_pairs(adapter, max_rss_queues); +} + +/** + * igc_reset_q_vector - Reset config for interrupt vector + * @adapter: board private structure to initialize + * @v_idx: Index of vector to be reset + * + * If NAPI is enabled it will delete any references to the + * NAPI struct. This is preparation for igc_free_q_vector. + */ +static void igc_reset_q_vector(struct igc_adapter *adapter, int v_idx) +{ +	struct igc_q_vector *q_vector = adapter->q_vector[v_idx]; + +	/* if we're coming from igc_set_interrupt_capability, the vectors are +	 * not yet allocated +	 */ +	if (!q_vector) +		return; + +	if (q_vector->tx.ring) +		adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; + +	if (q_vector->rx.ring) +		adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL; + +	netif_napi_del(&q_vector->napi); +} + +/** + * igc_free_q_vector - Free memory allocated for specific interrupt vector + * @adapter: board private structure to initialize + * @v_idx: Index of vector to be freed + * + * This function frees the memory allocated to the q_vector. + */ +static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx) +{ +	struct igc_q_vector *q_vector = adapter->q_vector[v_idx]; + +	adapter->q_vector[v_idx] = NULL; + +	/* igc_get_stats64() might access the rings on this vector, +	 * we must wait a grace period before freeing it. +	 */ +	if (q_vector) +		kfree_rcu(q_vector, rcu); +} + +/** + * igc_free_q_vectors - Free memory allocated for interrupt vectors + * @adapter: board private structure to initialize + * + * This function frees the memory allocated to the q_vectors.  In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + */ +static void igc_free_q_vectors(struct igc_adapter *adapter) +{ +	int v_idx = adapter->num_q_vectors; + +	adapter->num_tx_queues = 0; +	adapter->num_rx_queues = 0; +	adapter->num_q_vectors = 0; + +	while (v_idx--) { +		igc_reset_q_vector(adapter, v_idx); +		igc_free_q_vector(adapter, v_idx); +	} +} + +/** + * igc_update_itr - update the dynamic ITR value based on statistics + * @q_vector: pointer to q_vector + * @ring_container: ring info to update the itr for + * + * Stores a new ITR value based on packets and byte + * counts during the last interrupt.  The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern.  Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. + * NOTE: These calculations are only valid when operating in a single- + * queue environment. + */ +static void igc_update_itr(struct igc_q_vector *q_vector, +			   struct igc_ring_container *ring_container) +{ +	unsigned int packets = ring_container->total_packets; +	unsigned int bytes = ring_container->total_bytes; +	u8 itrval = ring_container->itr; + +	/* no packets, exit with status unchanged */ +	if (packets == 0) +		return; + +	switch (itrval) { +	case lowest_latency: +		/* handle TSO and jumbo frames */ +		if (bytes / packets > 8000) +			itrval = bulk_latency; +		else if ((packets < 5) && (bytes > 512)) +			itrval = low_latency; +		break; +	case low_latency:  /* 50 usec aka 20000 ints/s */ +		if (bytes > 10000) { +			/* this if handles the TSO accounting */ +			if (bytes / packets > 8000) +				itrval = bulk_latency; +			else if ((packets < 10) || ((bytes / packets) > 1200)) +				itrval = bulk_latency; +			else if ((packets > 35)) +				itrval = lowest_latency; +		} else if (bytes / packets > 2000) { +			itrval = bulk_latency; +		} else if (packets <= 2 && bytes < 512) { +			itrval = lowest_latency; +		} +		break; +	case bulk_latency: /* 250 usec aka 4000 ints/s */ +		if (bytes > 25000) { +			if (packets > 35) +				itrval = low_latency; +		} else if (bytes < 1500) { +			itrval = low_latency; +		} +		break; +	} + +	/* clear work counters since we have the values we need */ +	ring_container->total_bytes = 0; +	ring_container->total_packets = 0; + +	/* write updated itr to ring container */ +	ring_container->itr = itrval; +} + +static void igc_set_itr(struct igc_q_vector *q_vector) +{ +	struct igc_adapter *adapter = q_vector->adapter; +	u32 new_itr = q_vector->itr_val; +	u8 current_itr = 0; + +	/* for non-gigabit speeds, just fix the interrupt rate at 4000 */ +	switch (adapter->link_speed) { +	case SPEED_10: +	case SPEED_100: +		current_itr = 0; +		new_itr = IGC_4K_ITR; +		goto set_itr_now; +	default: +		break; +	} + +	igc_update_itr(q_vector, &q_vector->tx); +	igc_update_itr(q_vector, &q_vector->rx); + +	current_itr = max(q_vector->rx.itr, q_vector->tx.itr); + +	/* conservative mode (itr 3) eliminates the lowest_latency setting */ +	if (current_itr == lowest_latency && +	    ((q_vector->rx.ring && adapter->rx_itr_setting == 3) || +	    (!q_vector->rx.ring && adapter->tx_itr_setting == 3))) +		current_itr = low_latency; + +	switch (current_itr) { +	/* counts and packets in update_itr are dependent on these numbers */ +	case lowest_latency: +		new_itr = IGC_70K_ITR; /* 70,000 ints/sec */ +		break; +	case low_latency: +		new_itr = IGC_20K_ITR; /* 20,000 ints/sec */ +		break; +	case bulk_latency: +		new_itr = IGC_4K_ITR;  /* 4,000 ints/sec */ +		break; +	default: +		break; +	} + +set_itr_now: +	if (new_itr != q_vector->itr_val) { +		/* this attempts to bias the interrupt rate towards Bulk +		 * by adding intermediate steps when interrupt rate is +		 * increasing +		 */ +		new_itr = new_itr > q_vector->itr_val ? +			  max((new_itr * q_vector->itr_val) / +			  (new_itr + (q_vector->itr_val >> 2)), +			  new_itr) : new_itr; +		/* Don't write the value here; it resets the adapter's +		 * internal timer, and causes us to delay far longer than +		 * we should between interrupts.  Instead, we write the ITR +		 * value at the beginning of the next interrupt so the timing +		 * ends up being correct. +		 */ +		q_vector->itr_val = new_itr; +		q_vector->set_itr = 1; +	} +} + +static void igc_reset_interrupt_capability(struct igc_adapter *adapter) +{ +	int v_idx = adapter->num_q_vectors; + +	if (adapter->msix_entries) { +		pci_disable_msix(adapter->pdev); +		kfree(adapter->msix_entries); +		adapter->msix_entries = NULL; +	} else if (adapter->flags & IGC_FLAG_HAS_MSI) { +		pci_disable_msi(adapter->pdev); +	} + +	while (v_idx--) +		igc_reset_q_vector(adapter, v_idx); +} + +/** + * igc_set_interrupt_capability - set MSI or MSI-X if supported + * @adapter: Pointer to adapter structure + * @msix: boolean value for MSI-X capability + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + */ +static void igc_set_interrupt_capability(struct igc_adapter *adapter, +					 bool msix) +{ +	int numvecs, i; +	int err; + +	if (!msix) +		goto msi_only; +	adapter->flags |= IGC_FLAG_HAS_MSIX; + +	/* Number of supported queues. */ +	adapter->num_rx_queues = adapter->rss_queues; + +	adapter->num_tx_queues = adapter->rss_queues; + +	/* start with one vector for every Rx queue */ +	numvecs = adapter->num_rx_queues; + +	/* if Tx handler is separate add 1 for every Tx queue */ +	if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS)) +		numvecs += adapter->num_tx_queues; + +	/* store the number of vectors reserved for queues */ +	adapter->num_q_vectors = numvecs; + +	/* add 1 vector for link status interrupts */ +	numvecs++; + +	adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), +					GFP_KERNEL); + +	if (!adapter->msix_entries) +		return; + +	/* populate entry values */ +	for (i = 0; i < numvecs; i++) +		adapter->msix_entries[i].entry = i; + +	err = pci_enable_msix_range(adapter->pdev, +				    adapter->msix_entries, +				    numvecs, +				    numvecs); +	if (err > 0) +		return; + +	kfree(adapter->msix_entries); +	adapter->msix_entries = NULL; + +	igc_reset_interrupt_capability(adapter); + +msi_only: +	adapter->flags &= ~IGC_FLAG_HAS_MSIX; + +	adapter->rss_queues = 1; +	adapter->flags |= IGC_FLAG_QUEUE_PAIRS; +	adapter->num_rx_queues = 1; +	adapter->num_tx_queues = 1; +	adapter->num_q_vectors = 1; +	if (!pci_enable_msi(adapter->pdev)) +		adapter->flags |= IGC_FLAG_HAS_MSI; +} + +/** + * igc_update_ring_itr - update the dynamic ITR value based on packet size + * @q_vector: pointer to q_vector + * + * Stores a new ITR value based on strictly on packet size.  This + * algorithm is less sophisticated than that used in igc_update_itr, + * due to the difficulty of synchronizing statistics across multiple + * receive rings.  The divisors and thresholds used by this function + * were determined based on theoretical maximum wire speed and testing + * data, in order to minimize response time while increasing bulk + * throughput. + * NOTE: This function is called only when operating in a multiqueue + * receive environment. + */ +static void igc_update_ring_itr(struct igc_q_vector *q_vector) +{ +	struct igc_adapter *adapter = q_vector->adapter; +	int new_val = q_vector->itr_val; +	int avg_wire_size = 0; +	unsigned int packets; + +	/* For non-gigabit speeds, just fix the interrupt rate at 4000 +	 * ints/sec - ITR timer value of 120 ticks. +	 */ +	switch (adapter->link_speed) { +	case SPEED_10: +	case SPEED_100: +		new_val = IGC_4K_ITR; +		goto set_itr_val; +	default: +		break; +	} + +	packets = q_vector->rx.total_packets; +	if (packets) +		avg_wire_size = q_vector->rx.total_bytes / packets; + +	packets = q_vector->tx.total_packets; +	if (packets) +		avg_wire_size = max_t(u32, avg_wire_size, +				      q_vector->tx.total_bytes / packets); + +	/* if avg_wire_size isn't set no work was done */ +	if (!avg_wire_size) +		goto clear_counts; + +	/* Add 24 bytes to size to account for CRC, preamble, and gap */ +	avg_wire_size += 24; + +	/* Don't starve jumbo frames */ +	avg_wire_size = min(avg_wire_size, 3000); + +	/* Give a little boost to mid-size frames */ +	if (avg_wire_size > 300 && avg_wire_size < 1200) +		new_val = avg_wire_size / 3; +	else +		new_val = avg_wire_size / 2; + +	/* conservative mode (itr 3) eliminates the lowest_latency setting */ +	if (new_val < IGC_20K_ITR && +	    ((q_vector->rx.ring && adapter->rx_itr_setting == 3) || +	    (!q_vector->rx.ring && adapter->tx_itr_setting == 3))) +		new_val = IGC_20K_ITR; + +set_itr_val: +	if (new_val != q_vector->itr_val) { +		q_vector->itr_val = new_val; +		q_vector->set_itr = 1; +	} +clear_counts: +	q_vector->rx.total_bytes = 0; +	q_vector->rx.total_packets = 0; +	q_vector->tx.total_bytes = 0; +	q_vector->tx.total_packets = 0; +} + +static void igc_ring_irq_enable(struct igc_q_vector *q_vector) +{ +	struct igc_adapter *adapter = q_vector->adapter; +	struct igc_hw *hw = &adapter->hw; + +	if ((q_vector->rx.ring && (adapter->rx_itr_setting & 3)) || +	    (!q_vector->rx.ring && (adapter->tx_itr_setting & 3))) { +		if (adapter->num_q_vectors == 1) +			igc_set_itr(q_vector); +		else +			igc_update_ring_itr(q_vector); +	} + +	if (!test_bit(__IGC_DOWN, &adapter->state)) { +		if (adapter->msix_entries) +			wr32(IGC_EIMS, q_vector->eims_value); +		else +			igc_irq_enable(adapter); +	} +} + +static void igc_add_ring(struct igc_ring *ring, +			 struct igc_ring_container *head) +{ +	head->ring = ring; +	head->count++; +} + +/** + * igc_cache_ring_register - Descriptor ring to register mapping + * @adapter: board private structure to initialize + * + * Once we know the feature-set enabled for the device, we'll cache + * the register offset the descriptor ring is assigned to. + */ +static void igc_cache_ring_register(struct igc_adapter *adapter) +{ +	int i = 0, j = 0; + +	switch (adapter->hw.mac.type) { +	case igc_i225: +	/* Fall through */ +	default: +		for (; i < adapter->num_rx_queues; i++) +			adapter->rx_ring[i]->reg_idx = i; +		for (; j < adapter->num_tx_queues; j++) +			adapter->tx_ring[j]->reg_idx = j; +		break; +	} +} + +/** + * igc_poll - NAPI Rx polling callback + * @napi: napi polling structure + * @budget: count of how many packets we should handle + */ +static int igc_poll(struct napi_struct *napi, int budget) +{ +	struct igc_q_vector *q_vector = container_of(napi, +						     struct igc_q_vector, +						     napi); +	bool clean_complete = true; +	int work_done = 0; + +	if (q_vector->tx.ring) +		clean_complete = igc_clean_tx_irq(q_vector, budget); + +	if (q_vector->rx.ring) { +		int cleaned = igc_clean_rx_irq(q_vector, budget); + +		work_done += cleaned; +		if (cleaned >= budget) +			clean_complete = false; +	} + +	/* If all work not completed, return budget and keep polling */ +	if (!clean_complete) +		return budget; + +	/* Exit the polling mode, but don't re-enable interrupts if stack might +	 * poll us due to busy-polling +	 */ +	if (likely(napi_complete_done(napi, work_done))) +		igc_ring_irq_enable(q_vector); + +	return min(work_done, budget - 1); +} + +/** + * igc_alloc_q_vector - Allocate memory for a single interrupt vector + * @adapter: board private structure to initialize + * @v_count: q_vectors allocated on adapter, used for ring interleaving + * @v_idx: index of vector in adapter struct + * @txr_count: total number of Tx rings to allocate + * @txr_idx: index of first Tx ring to allocate + * @rxr_count: total number of Rx rings to allocate + * @rxr_idx: index of first Rx ring to allocate + * + * We allocate one q_vector.  If allocation fails we return -ENOMEM. + */ +static int igc_alloc_q_vector(struct igc_adapter *adapter, +			      unsigned int v_count, unsigned int v_idx, +			      unsigned int txr_count, unsigned int txr_idx, +			      unsigned int rxr_count, unsigned int rxr_idx) +{ +	struct igc_q_vector *q_vector; +	struct igc_ring *ring; +	int ring_count; + +	/* igc only supports 1 Tx and/or 1 Rx queue per vector */ +	if (txr_count > 1 || rxr_count > 1) +		return -ENOMEM; + +	ring_count = txr_count + rxr_count; + +	/* allocate q_vector and rings */ +	q_vector = adapter->q_vector[v_idx]; +	if (!q_vector) +		q_vector = kzalloc(struct_size(q_vector, ring, ring_count), +				   GFP_KERNEL); +	else +		memset(q_vector, 0, struct_size(q_vector, ring, ring_count)); +	if (!q_vector) +		return -ENOMEM; + +	/* initialize NAPI */ +	netif_napi_add(adapter->netdev, &q_vector->napi, +		       igc_poll, 64); + +	/* tie q_vector and adapter together */ +	adapter->q_vector[v_idx] = q_vector; +	q_vector->adapter = adapter; + +	/* initialize work limits */ +	q_vector->tx.work_limit = adapter->tx_work_limit; + +	/* initialize ITR configuration */ +	q_vector->itr_register = adapter->io_addr + IGC_EITR(0); +	q_vector->itr_val = IGC_START_ITR; + +	/* initialize pointer to rings */ +	ring = q_vector->ring; + +	/* initialize ITR */ +	if (rxr_count) { +		/* rx or rx/tx vector */ +		if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3) +			q_vector->itr_val = adapter->rx_itr_setting; +	} else { +		/* tx only vector */ +		if (!adapter->tx_itr_setting || adapter->tx_itr_setting > 3) +			q_vector->itr_val = adapter->tx_itr_setting; +	} + +	if (txr_count) { +		/* assign generic ring traits */ +		ring->dev = &adapter->pdev->dev; +		ring->netdev = adapter->netdev; + +		/* configure backlink on ring */ +		ring->q_vector = q_vector; + +		/* update q_vector Tx values */ +		igc_add_ring(ring, &q_vector->tx); + +		/* apply Tx specific ring traits */ +		ring->count = adapter->tx_ring_count; +		ring->queue_index = txr_idx; + +		/* assign ring to adapter */ +		adapter->tx_ring[txr_idx] = ring; + +		/* push pointer to next ring */ +		ring++; +	} + +	if (rxr_count) { +		/* assign generic ring traits */ +		ring->dev = &adapter->pdev->dev; +		ring->netdev = adapter->netdev; + +		/* configure backlink on ring */ +		ring->q_vector = q_vector; + +		/* update q_vector Rx values */ +		igc_add_ring(ring, &q_vector->rx); + +		/* apply Rx specific ring traits */ +		ring->count = adapter->rx_ring_count; +		ring->queue_index = rxr_idx; + +		/* assign ring to adapter */ +		adapter->rx_ring[rxr_idx] = ring; +	} + +	return 0; +} + +/** + * igc_alloc_q_vectors - Allocate memory for interrupt vectors + * @adapter: board private structure to initialize + * + * We allocate one q_vector per queue interrupt.  If allocation fails we + * return -ENOMEM. + */ +static int igc_alloc_q_vectors(struct igc_adapter *adapter) +{ +	int rxr_remaining = adapter->num_rx_queues; +	int txr_remaining = adapter->num_tx_queues; +	int rxr_idx = 0, txr_idx = 0, v_idx = 0; +	int q_vectors = adapter->num_q_vectors; +	int err; + +	if (q_vectors >= (rxr_remaining + txr_remaining)) { +		for (; rxr_remaining; v_idx++) { +			err = igc_alloc_q_vector(adapter, q_vectors, v_idx, +						 0, 0, 1, rxr_idx); + +			if (err) +				goto err_out; + +			/* update counts and index */ +			rxr_remaining--; +			rxr_idx++; +		} +	} + +	for (; v_idx < q_vectors; v_idx++) { +		int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx); +		int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx); + +		err = igc_alloc_q_vector(adapter, q_vectors, v_idx, +					 tqpv, txr_idx, rqpv, rxr_idx); + +		if (err) +			goto err_out; + +		/* update counts and index */ +		rxr_remaining -= rqpv; +		txr_remaining -= tqpv; +		rxr_idx++; +		txr_idx++; +	} + +	return 0; + +err_out: +	adapter->num_tx_queues = 0; +	adapter->num_rx_queues = 0; +	adapter->num_q_vectors = 0; + +	while (v_idx--) +		igc_free_q_vector(adapter, v_idx); + +	return -ENOMEM; +} + +/** + * igc_init_interrupt_scheme - initialize interrupts, allocate queues/vectors + * @adapter: Pointer to adapter structure + * @msix: boolean for MSI-X capability + * + * This function initializes the interrupts and allocates all of the queues. + */ +static int igc_init_interrupt_scheme(struct igc_adapter *adapter, bool msix) +{ +	struct pci_dev *pdev = adapter->pdev; +	int err = 0; + +	igc_set_interrupt_capability(adapter, msix); + +	err = igc_alloc_q_vectors(adapter); +	if (err) { +		dev_err(&pdev->dev, "Unable to allocate memory for vectors\n"); +		goto err_alloc_q_vectors; +	} + +	igc_cache_ring_register(adapter); + +	return 0; + +err_alloc_q_vectors: +	igc_reset_interrupt_capability(adapter); +	return err; +} + +/** + * igc_sw_init - Initialize general software structures (struct igc_adapter) + * @adapter: board private structure to initialize + * + * igc_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + */ +static int igc_sw_init(struct igc_adapter *adapter) +{ +	struct net_device *netdev = adapter->netdev; +	struct pci_dev *pdev = adapter->pdev; +	struct igc_hw *hw = &adapter->hw; + +	int size = sizeof(struct igc_mac_addr) * hw->mac.rar_entry_count; + +	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + +	/* set default ring sizes */ +	adapter->tx_ring_count = IGC_DEFAULT_TXD; +	adapter->rx_ring_count = IGC_DEFAULT_RXD; + +	/* set default ITR values */ +	adapter->rx_itr_setting = IGC_DEFAULT_ITR; +	adapter->tx_itr_setting = IGC_DEFAULT_ITR; + +	/* set default work limits */ +	adapter->tx_work_limit = IGC_DEFAULT_TX_WORK; + +	/* adjust max frame to be at least the size of a standard frame */ +	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + +				VLAN_HLEN; +	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + +	spin_lock_init(&adapter->nfc_lock); +	spin_lock_init(&adapter->stats64_lock); +	/* Assume MSI-X interrupts, will be checked during IRQ allocation */ +	adapter->flags |= IGC_FLAG_HAS_MSIX; + +	adapter->mac_table = kzalloc(size, GFP_ATOMIC); +	if (!adapter->mac_table) +		return -ENOMEM; + +	igc_init_queue_configuration(adapter); + +	/* This call may decrease the number of queues */ +	if (igc_init_interrupt_scheme(adapter, true)) { +		dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); +		return -ENOMEM; +	} + +	/* Explicitly disable IRQ since the NIC can be in any state. */ +	igc_irq_disable(adapter); + +	set_bit(__IGC_DOWN, &adapter->state); + +	return 0; +} +  /**   * igc_up - Open the interface and prepare it to handle traffic   * @adapter: board private structure @@ -2163,18 +3464,6 @@ static void igc_nfc_filter_exit(struct igc_adapter *adapter)  	spin_unlock(&adapter->nfc_lock);  } -static void igc_nfc_filter_restore(struct igc_adapter *adapter) -{ -	struct igc_nfc_filter *rule; - -	spin_lock(&adapter->nfc_lock); - -	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) -		igc_add_filter(adapter, rule); - -	spin_unlock(&adapter->nfc_lock); -} -  /**   * igc_down - Close the interface   * @adapter: board private structure @@ -2398,105 +3687,6 @@ igc_features_check(struct sk_buff *skb, struct net_device *dev,  	return features;  } -/** - * igc_configure - configure the hardware for RX and TX - * @adapter: private board structure - */ -static void igc_configure(struct igc_adapter *adapter) -{ -	struct net_device *netdev = adapter->netdev; -	int i = 0; - -	igc_get_hw_control(adapter); -	igc_set_rx_mode(netdev); - -	igc_setup_tctl(adapter); -	igc_setup_mrqc(adapter); -	igc_setup_rctl(adapter); - -	igc_nfc_filter_restore(adapter); -	igc_configure_tx(adapter); -	igc_configure_rx(adapter); - -	igc_rx_fifo_flush_base(&adapter->hw); - -	/* call igc_desc_unused which always leaves -	 * at least 1 descriptor unused to make sure -	 * next_to_use != next_to_clean -	 */ -	for (i = 0; i < adapter->num_rx_queues; i++) { -		struct igc_ring *ring = adapter->rx_ring[i]; - -		igc_alloc_rx_buffers(ring, igc_desc_unused(ring)); -	} -} - -/** - * igc_rar_set_index - Sync RAL[index] and RAH[index] registers with MAC table - * @adapter: address of board private structure - * @index: Index of the RAR entry which need to be synced with MAC table - */ -static void igc_rar_set_index(struct igc_adapter *adapter, u32 index) -{ -	u8 *addr = adapter->mac_table[index].addr; -	struct igc_hw *hw = &adapter->hw; -	u32 rar_low, rar_high; - -	/* HW expects these to be in network order when they are plugged -	 * into the registers which are little endian.  In order to guarantee -	 * that ordering we need to do an leXX_to_cpup here in order to be -	 * ready for the byteswap that occurs with writel -	 */ -	rar_low = le32_to_cpup((__le32 *)(addr)); -	rar_high = le16_to_cpup((__le16 *)(addr + 4)); - -	/* Indicate to hardware the Address is Valid. */ -	if (adapter->mac_table[index].state & IGC_MAC_STATE_IN_USE) { -		if (is_valid_ether_addr(addr)) -			rar_high |= IGC_RAH_AV; - -		rar_high |= IGC_RAH_POOL_1 << -			adapter->mac_table[index].queue; -	} - -	wr32(IGC_RAL(index), rar_low); -	wrfl(); -	wr32(IGC_RAH(index), rar_high); -	wrfl(); -} - -/* Set default MAC address for the PF in the first RAR entry */ -static void igc_set_default_mac_filter(struct igc_adapter *adapter) -{ -	struct igc_mac_addr *mac_table = &adapter->mac_table[0]; - -	ether_addr_copy(mac_table->addr, adapter->hw.mac.addr); -	mac_table->state = IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; - -	igc_rar_set_index(adapter, 0); -} - -/* If the filter to be added and an already existing filter express - * the same address and address type, it should be possible to only - * override the other configurations, for example the queue to steer - * traffic. - */ -static bool igc_mac_entry_can_be_used(const struct igc_mac_addr *entry, -				      const u8 *addr, const u8 flags) -{ -	if (!(entry->state & IGC_MAC_STATE_IN_USE)) -		return true; - -	if ((entry->state & IGC_MAC_STATE_SRC_ADDR) != -	    (flags & IGC_MAC_STATE_SRC_ADDR)) -		return false; - -	if (!ether_addr_equal(addr, entry->addr)) -		return false; - -	return true; -} -  /* Add a MAC filter for 'addr' directing matching traffic to 'queue',   * 'flags' is used to indicate what kind of match is made, match is by   * default for the destination address, if matching by source address @@ -2597,159 +3787,20 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter,  					IGC_MAC_STATE_QUEUE_STEERING | flags);  } -/* Add a MAC filter for 'addr' directing matching traffic to 'queue', - * 'flags' is used to indicate what kind of match is made, match is by - * default for the destination address, if matching by source address - * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used. - */ -static int igc_add_mac_filter(struct igc_adapter *adapter, -			      const u8 *addr, const u8 queue) +static void igc_tsync_interrupt(struct igc_adapter *adapter)  {  	struct igc_hw *hw = &adapter->hw; -	int rar_entries = hw->mac.rar_entry_count; -	int i; - -	if (is_zero_ether_addr(addr)) -		return -EINVAL; - -	/* Search for the first empty entry in the MAC table. -	 * Do not touch entries at the end of the table reserved for the VF MAC -	 * addresses. -	 */ -	for (i = 0; i < rar_entries; i++) { -		if (!igc_mac_entry_can_be_used(&adapter->mac_table[i], -					       addr, 0)) -			continue; - -		ether_addr_copy(adapter->mac_table[i].addr, addr); -		adapter->mac_table[i].queue = queue; -		adapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE; - -		igc_rar_set_index(adapter, i); -		return i; -	} - -	return -ENOSPC; -} - -/* Remove a MAC filter for 'addr' directing matching traffic to - * 'queue', 'flags' is used to indicate what kind of match need to be - * removed, match is by default for the destination address, if - * matching by source address is to be removed the flag - * IGC_MAC_STATE_SRC_ADDR can be used. - */ -static int igc_del_mac_filter(struct igc_adapter *adapter, -			      const u8 *addr, const u8 queue) -{ -	struct igc_hw *hw = &adapter->hw; -	int rar_entries = hw->mac.rar_entry_count; -	int i; - -	if (is_zero_ether_addr(addr)) -		return -EINVAL; - -	/* Search for matching entry in the MAC table based on given address -	 * and queue. Do not touch entries at the end of the table reserved -	 * for the VF MAC addresses. -	 */ -	for (i = 0; i < rar_entries; i++) { -		if (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE)) -			continue; -		if (adapter->mac_table[i].state != 0) -			continue; -		if (adapter->mac_table[i].queue != queue) -			continue; -		if (!ether_addr_equal(adapter->mac_table[i].addr, addr)) -			continue; - -		/* When a filter for the default address is "deleted", -		 * we return it to its initial configuration -		 */ -		if (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) { -			adapter->mac_table[i].state = -				IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; -			adapter->mac_table[i].queue = 0; -		} else { -			adapter->mac_table[i].state = 0; -			adapter->mac_table[i].queue = 0; -			memset(adapter->mac_table[i].addr, 0, ETH_ALEN); -		} +	u32 tsicr = rd32(IGC_TSICR); +	u32 ack = 0; -		igc_rar_set_index(adapter, i); -		return 0; +	if (tsicr & IGC_TSICR_TXTS) { +		/* retrieve hardware timestamp */ +		schedule_work(&adapter->ptp_tx_work); +		ack |= IGC_TSICR_TXTS;  	} -	return -ENOENT; -} - -static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) -{ -	struct igc_adapter *adapter = netdev_priv(netdev); -	int ret; - -	ret = igc_add_mac_filter(adapter, addr, adapter->num_rx_queues); - -	return min_t(int, ret, 0); -} - -static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr) -{ -	struct igc_adapter *adapter = netdev_priv(netdev); - -	igc_del_mac_filter(adapter, addr, adapter->num_rx_queues); - -	return 0; -} - -/** - * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set - * @netdev: network interface device structure - * - * The set_rx_mode entry point is called whenever the unicast or multicast - * address lists or the network interface flags are updated.  This routine is - * responsible for configuring the hardware for proper unicast, multicast, - * promiscuous mode, and all-multi behavior. - */ -static void igc_set_rx_mode(struct net_device *netdev) -{ -	struct igc_adapter *adapter = netdev_priv(netdev); -	struct igc_hw *hw = &adapter->hw; -	u32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE; -	int count; - -	/* Check for Promiscuous and All Multicast modes */ -	if (netdev->flags & IFF_PROMISC) { -		rctl |= IGC_RCTL_UPE | IGC_RCTL_MPE; -	} else { -		if (netdev->flags & IFF_ALLMULTI) { -			rctl |= IGC_RCTL_MPE; -		} else { -			/* Write addresses to the MTA, if the attempt fails -			 * then we should just turn on promiscuous mode so -			 * that we can at least receive multicast traffic -			 */ -			count = igc_write_mc_addr_list(netdev); -			if (count < 0) -				rctl |= IGC_RCTL_MPE; -		} -	} - -	/* Write addresses to available RAR registers, if there is not -	 * sufficient space to store all the addresses then enable -	 * unicast promiscuous mode -	 */ -	if (__dev_uc_sync(netdev, igc_uc_sync, igc_uc_unsync)) -		rctl |= IGC_RCTL_UPE; - -	/* update state of unicast and multicast */ -	rctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE); -	wr32(IGC_RCTL, rctl); - -#if (PAGE_SIZE < 8192) -	if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB) -		rlpml = IGC_MAX_FRAME_BUILD_SKB; -#endif -	wr32(IGC_RLPML, rlpml); +	/* acknowledge the interrupts */ +	wr32(IGC_TSICR, ack);  }  /** @@ -2779,114 +3830,28 @@ static irqreturn_t igc_msix_other(int irq, void *data)  			mod_timer(&adapter->watchdog_timer, jiffies + 1);  	} +	if (icr & IGC_ICR_TS) +		igc_tsync_interrupt(adapter); +  	wr32(IGC_EIMS, adapter->eims_other);  	return IRQ_HANDLED;  } -/** - * igc_write_ivar - configure ivar for given MSI-X vector - * @hw: pointer to the HW structure - * @msix_vector: vector number we are allocating to a given ring - * @index: row index of IVAR register to write within IVAR table - * @offset: column offset of in IVAR, should be multiple of 8 - * - * The IVAR table consists of 2 columns, - * each containing an cause allocation for an Rx and Tx ring, and a - * variable number of rows depending on the number of queues supported. - */ -static void igc_write_ivar(struct igc_hw *hw, int msix_vector, -			   int index, int offset) -{ -	u32 ivar = array_rd32(IGC_IVAR0, index); - -	/* clear any bits that are currently set */ -	ivar &= ~((u32)0xFF << offset); - -	/* write vector and valid bit */ -	ivar |= (msix_vector | IGC_IVAR_VALID) << offset; - -	array_wr32(IGC_IVAR0, index, ivar); -} - -static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector) -{ -	struct igc_adapter *adapter = q_vector->adapter; -	struct igc_hw *hw = &adapter->hw; -	int rx_queue = IGC_N0_QUEUE; -	int tx_queue = IGC_N0_QUEUE; - -	if (q_vector->rx.ring) -		rx_queue = q_vector->rx.ring->reg_idx; -	if (q_vector->tx.ring) -		tx_queue = q_vector->tx.ring->reg_idx; - -	switch (hw->mac.type) { -	case igc_i225: -		if (rx_queue > IGC_N0_QUEUE) -			igc_write_ivar(hw, msix_vector, -				       rx_queue >> 1, -				       (rx_queue & 0x1) << 4); -		if (tx_queue > IGC_N0_QUEUE) -			igc_write_ivar(hw, msix_vector, -				       tx_queue >> 1, -				       ((tx_queue & 0x1) << 4) + 8); -		q_vector->eims_value = BIT(msix_vector); -		break; -	default: -		WARN_ONCE(hw->mac.type != igc_i225, "Wrong MAC type\n"); -		break; -	} - -	/* add q_vector eims value to global eims_enable_mask */ -	adapter->eims_enable_mask |= q_vector->eims_value; - -	/* configure q_vector to set itr on first interrupt */ -	q_vector->set_itr = 1; -} - -/** - * igc_configure_msix - Configure MSI-X hardware - * @adapter: Pointer to adapter structure - * - * igc_configure_msix sets up the hardware to properly - * generate MSI-X interrupts. - */ -static void igc_configure_msix(struct igc_adapter *adapter) +static void igc_write_itr(struct igc_q_vector *q_vector)  { -	struct igc_hw *hw = &adapter->hw; -	int i, vector = 0; -	u32 tmp; - -	adapter->eims_enable_mask = 0; - -	/* set vector for other causes, i.e. link changes */ -	switch (hw->mac.type) { -	case igc_i225: -		/* Turn on MSI-X capability first, or our settings -		 * won't stick.  And it will take days to debug. -		 */ -		wr32(IGC_GPIE, IGC_GPIE_MSIX_MODE | -		     IGC_GPIE_PBA | IGC_GPIE_EIAME | -		     IGC_GPIE_NSICR); - -		/* enable msix_other interrupt */ -		adapter->eims_other = BIT(vector); -		tmp = (vector++ | IGC_IVAR_VALID) << 8; +	u32 itr_val = q_vector->itr_val & IGC_QVECTOR_MASK; -		wr32(IGC_IVAR_MISC, tmp); -		break; -	default: -		/* do nothing, since nothing else supports MSI-X */ -		break; -	} /* switch (hw->mac.type) */ +	if (!q_vector->set_itr) +		return; -	adapter->eims_enable_mask |= adapter->eims_other; +	if (!itr_val) +		itr_val = IGC_ITR_VAL_MASK; -	for (i = 0; i < adapter->num_q_vectors; i++) -		igc_assign_vector(adapter->q_vector[i], vector++); +	itr_val |= IGC_EITR_CNT_IGNR; -	wrfl(); +	writel(itr_val, q_vector->itr_register); +	q_vector->set_itr = 0;  }  static irqreturn_t igc_msix_ring(int irq, void *data) @@ -2961,49 +3926,6 @@ err_out:  }  /** - * igc_reset_q_vector - Reset config for interrupt vector - * @adapter: board private structure to initialize - * @v_idx: Index of vector to be reset - * - * If NAPI is enabled it will delete any references to the - * NAPI struct. This is preparation for igc_free_q_vector. - */ -static void igc_reset_q_vector(struct igc_adapter *adapter, int v_idx) -{ -	struct igc_q_vector *q_vector = adapter->q_vector[v_idx]; - -	/* if we're coming from igc_set_interrupt_capability, the vectors are -	 * not yet allocated -	 */ -	if (!q_vector) -		return; - -	if (q_vector->tx.ring) -		adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; - -	if (q_vector->rx.ring) -		adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL; - -	netif_napi_del(&q_vector->napi); -} - -static void igc_reset_interrupt_capability(struct igc_adapter *adapter) -{ -	int v_idx = adapter->num_q_vectors; - -	if (adapter->msix_entries) { -		pci_disable_msix(adapter->pdev); -		kfree(adapter->msix_entries); -		adapter->msix_entries = NULL; -	} else if (adapter->flags & IGC_FLAG_HAS_MSI) { -		pci_disable_msi(adapter->pdev); -	} - -	while (v_idx--) -		igc_reset_q_vector(adapter, v_idx); -} - -/**   * igc_clear_interrupt_scheme - reset the device to a state of no interrupts   * @adapter: Pointer to adapter structure   * @@ -3016,48 +3938,6 @@ static void igc_clear_interrupt_scheme(struct igc_adapter *adapter)  	igc_reset_interrupt_capability(adapter);  } -/** - * igc_free_q_vectors - Free memory allocated for interrupt vectors - * @adapter: board private structure to initialize - * - * This function frees the memory allocated to the q_vectors.  In addition if - * NAPI is enabled it will delete any references to the NAPI struct prior - * to freeing the q_vector. - */ -static void igc_free_q_vectors(struct igc_adapter *adapter) -{ -	int v_idx = adapter->num_q_vectors; - -	adapter->num_tx_queues = 0; -	adapter->num_rx_queues = 0; -	adapter->num_q_vectors = 0; - -	while (v_idx--) { -		igc_reset_q_vector(adapter, v_idx); -		igc_free_q_vector(adapter, v_idx); -	} -} - -/** - * igc_free_q_vector - Free memory allocated for specific interrupt vector - * @adapter: board private structure to initialize - * @v_idx: Index of vector to be freed - * - * This function frees the memory allocated to the q_vector. - */ -static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx) -{ -	struct igc_q_vector *q_vector = adapter->q_vector[v_idx]; - -	adapter->q_vector[v_idx] = NULL; - -	/* igc_get_stats64() might access the rings on this vector, -	 * we must wait a grace period before freeing it. -	 */ -	if (q_vector) -		kfree_rcu(q_vector, rcu); -} -  /* Need to wait a few seconds after link up to get diagnostic information from   * the phy   */ @@ -3109,7 +3989,7 @@ bool igc_has_link(struct igc_adapter *adapter)  /**   * igc_watchdog - Timer Call-back - * @data: pointer to adapter cast into an unsigned long + * @t: timer for the watchdog   */  static void igc_watchdog(struct timer_list *t)  { @@ -3282,6 +4162,8 @@ no_wait:  		wr32(IGC_ICS, IGC_ICS_RXDMT0);  	} +	igc_ptp_tx_hang(adapter); +  	/* Reset the timer */  	if (!test_bit(__IGC_DOWN, &adapter->state)) {  		if (adapter->flags & IGC_FLAG_NEED_LINK_UPDATE) @@ -3294,149 +4176,6 @@ no_wait:  }  /** - * igc_update_ring_itr - update the dynamic ITR value based on packet size - * @q_vector: pointer to q_vector - * - * Stores a new ITR value based on strictly on packet size.  This - * algorithm is less sophisticated than that used in igc_update_itr, - * due to the difficulty of synchronizing statistics across multiple - * receive rings.  The divisors and thresholds used by this function - * were determined based on theoretical maximum wire speed and testing - * data, in order to minimize response time while increasing bulk - * throughput. - * NOTE: This function is called only when operating in a multiqueue - * receive environment. - */ -static void igc_update_ring_itr(struct igc_q_vector *q_vector) -{ -	struct igc_adapter *adapter = q_vector->adapter; -	int new_val = q_vector->itr_val; -	int avg_wire_size = 0; -	unsigned int packets; - -	/* For non-gigabit speeds, just fix the interrupt rate at 4000 -	 * ints/sec - ITR timer value of 120 ticks. -	 */ -	switch (adapter->link_speed) { -	case SPEED_10: -	case SPEED_100: -		new_val = IGC_4K_ITR; -		goto set_itr_val; -	default: -		break; -	} - -	packets = q_vector->rx.total_packets; -	if (packets) -		avg_wire_size = q_vector->rx.total_bytes / packets; - -	packets = q_vector->tx.total_packets; -	if (packets) -		avg_wire_size = max_t(u32, avg_wire_size, -				      q_vector->tx.total_bytes / packets); - -	/* if avg_wire_size isn't set no work was done */ -	if (!avg_wire_size) -		goto clear_counts; - -	/* Add 24 bytes to size to account for CRC, preamble, and gap */ -	avg_wire_size += 24; - -	/* Don't starve jumbo frames */ -	avg_wire_size = min(avg_wire_size, 3000); - -	/* Give a little boost to mid-size frames */ -	if (avg_wire_size > 300 && avg_wire_size < 1200) -		new_val = avg_wire_size / 3; -	else -		new_val = avg_wire_size / 2; - -	/* conservative mode (itr 3) eliminates the lowest_latency setting */ -	if (new_val < IGC_20K_ITR && -	    ((q_vector->rx.ring && adapter->rx_itr_setting == 3) || -	    (!q_vector->rx.ring && adapter->tx_itr_setting == 3))) -		new_val = IGC_20K_ITR; - -set_itr_val: -	if (new_val != q_vector->itr_val) { -		q_vector->itr_val = new_val; -		q_vector->set_itr = 1; -	} -clear_counts: -	q_vector->rx.total_bytes = 0; -	q_vector->rx.total_packets = 0; -	q_vector->tx.total_bytes = 0; -	q_vector->tx.total_packets = 0; -} - -/** - * igc_update_itr - update the dynamic ITR value based on statistics - * @q_vector: pointer to q_vector - * @ring_container: ring info to update the itr for - * - * Stores a new ITR value based on packets and byte - * counts during the last interrupt.  The advantage of per interrupt - * computation is faster updates and more accurate ITR for the current - * traffic pattern.  Constants in this function were computed - * based on theoretical maximum wire speed and thresholds were set based - * on testing data as well as attempting to minimize response time - * while increasing bulk throughput. - * NOTE: These calculations are only valid when operating in a single- - * queue environment. - */ -static void igc_update_itr(struct igc_q_vector *q_vector, -			   struct igc_ring_container *ring_container) -{ -	unsigned int packets = ring_container->total_packets; -	unsigned int bytes = ring_container->total_bytes; -	u8 itrval = ring_container->itr; - -	/* no packets, exit with status unchanged */ -	if (packets == 0) -		return; - -	switch (itrval) { -	case lowest_latency: -		/* handle TSO and jumbo frames */ -		if (bytes / packets > 8000) -			itrval = bulk_latency; -		else if ((packets < 5) && (bytes > 512)) -			itrval = low_latency; -		break; -	case low_latency:  /* 50 usec aka 20000 ints/s */ -		if (bytes > 10000) { -			/* this if handles the TSO accounting */ -			if (bytes / packets > 8000) -				itrval = bulk_latency; -			else if ((packets < 10) || ((bytes / packets) > 1200)) -				itrval = bulk_latency; -			else if ((packets > 35)) -				itrval = lowest_latency; -		} else if (bytes / packets > 2000) { -			itrval = bulk_latency; -		} else if (packets <= 2 && bytes < 512) { -			itrval = lowest_latency; -		} -		break; -	case bulk_latency: /* 250 usec aka 4000 ints/s */ -		if (bytes > 25000) { -			if (packets > 35) -				itrval = low_latency; -		} else if (bytes < 1500) { -			itrval = low_latency; -		} -		break; -	} - -	/* clear work counters since we have the values we need */ -	ring_container->total_bytes = 0; -	ring_container->total_packets = 0; - -	/* write updated itr to ring container */ -	ring_container->itr = itrval; -} - -/**   * igc_intr_msi - Interrupt Handler   * @irq: interrupt number   * @data: pointer to a network interface device structure @@ -3513,424 +4252,6 @@ static irqreturn_t igc_intr(int irq, void *data)  	return IRQ_HANDLED;  } -static void igc_set_itr(struct igc_q_vector *q_vector) -{ -	struct igc_adapter *adapter = q_vector->adapter; -	u32 new_itr = q_vector->itr_val; -	u8 current_itr = 0; - -	/* for non-gigabit speeds, just fix the interrupt rate at 4000 */ -	switch (adapter->link_speed) { -	case SPEED_10: -	case SPEED_100: -		current_itr = 0; -		new_itr = IGC_4K_ITR; -		goto set_itr_now; -	default: -		break; -	} - -	igc_update_itr(q_vector, &q_vector->tx); -	igc_update_itr(q_vector, &q_vector->rx); - -	current_itr = max(q_vector->rx.itr, q_vector->tx.itr); - -	/* conservative mode (itr 3) eliminates the lowest_latency setting */ -	if (current_itr == lowest_latency && -	    ((q_vector->rx.ring && adapter->rx_itr_setting == 3) || -	    (!q_vector->rx.ring && adapter->tx_itr_setting == 3))) -		current_itr = low_latency; - -	switch (current_itr) { -	/* counts and packets in update_itr are dependent on these numbers */ -	case lowest_latency: -		new_itr = IGC_70K_ITR; /* 70,000 ints/sec */ -		break; -	case low_latency: -		new_itr = IGC_20K_ITR; /* 20,000 ints/sec */ -		break; -	case bulk_latency: -		new_itr = IGC_4K_ITR;  /* 4,000 ints/sec */ -		break; -	default: -		break; -	} - -set_itr_now: -	if (new_itr != q_vector->itr_val) { -		/* this attempts to bias the interrupt rate towards Bulk -		 * by adding intermediate steps when interrupt rate is -		 * increasing -		 */ -		new_itr = new_itr > q_vector->itr_val ? -			  max((new_itr * q_vector->itr_val) / -			  (new_itr + (q_vector->itr_val >> 2)), -			  new_itr) : new_itr; -		/* Don't write the value here; it resets the adapter's -		 * internal timer, and causes us to delay far longer than -		 * we should between interrupts.  Instead, we write the ITR -		 * value at the beginning of the next interrupt so the timing -		 * ends up being correct. -		 */ -		q_vector->itr_val = new_itr; -		q_vector->set_itr = 1; -	} -} - -static void igc_ring_irq_enable(struct igc_q_vector *q_vector) -{ -	struct igc_adapter *adapter = q_vector->adapter; -	struct igc_hw *hw = &adapter->hw; - -	if ((q_vector->rx.ring && (adapter->rx_itr_setting & 3)) || -	    (!q_vector->rx.ring && (adapter->tx_itr_setting & 3))) { -		if (adapter->num_q_vectors == 1) -			igc_set_itr(q_vector); -		else -			igc_update_ring_itr(q_vector); -	} - -	if (!test_bit(__IGC_DOWN, &adapter->state)) { -		if (adapter->msix_entries) -			wr32(IGC_EIMS, q_vector->eims_value); -		else -			igc_irq_enable(adapter); -	} -} - -/** - * igc_poll - NAPI Rx polling callback - * @napi: napi polling structure - * @budget: count of how many packets we should handle - */ -static int igc_poll(struct napi_struct *napi, int budget) -{ -	struct igc_q_vector *q_vector = container_of(napi, -						     struct igc_q_vector, -						     napi); -	bool clean_complete = true; -	int work_done = 0; - -	if (q_vector->tx.ring) -		clean_complete = igc_clean_tx_irq(q_vector, budget); - -	if (q_vector->rx.ring) { -		int cleaned = igc_clean_rx_irq(q_vector, budget); - -		work_done += cleaned; -		if (cleaned >= budget) -			clean_complete = false; -	} - -	/* If all work not completed, return budget and keep polling */ -	if (!clean_complete) -		return budget; - -	/* Exit the polling mode, but don't re-enable interrupts if stack might -	 * poll us due to busy-polling -	 */ -	if (likely(napi_complete_done(napi, work_done))) -		igc_ring_irq_enable(q_vector); - -	return min(work_done, budget - 1); -} - -/** - * igc_set_interrupt_capability - set MSI or MSI-X if supported - * @adapter: Pointer to adapter structure - * - * Attempt to configure interrupts using the best available - * capabilities of the hardware and kernel. - */ -static void igc_set_interrupt_capability(struct igc_adapter *adapter, -					 bool msix) -{ -	int numvecs, i; -	int err; - -	if (!msix) -		goto msi_only; -	adapter->flags |= IGC_FLAG_HAS_MSIX; - -	/* Number of supported queues. */ -	adapter->num_rx_queues = adapter->rss_queues; - -	adapter->num_tx_queues = adapter->rss_queues; - -	/* start with one vector for every Rx queue */ -	numvecs = adapter->num_rx_queues; - -	/* if Tx handler is separate add 1 for every Tx queue */ -	if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS)) -		numvecs += adapter->num_tx_queues; - -	/* store the number of vectors reserved for queues */ -	adapter->num_q_vectors = numvecs; - -	/* add 1 vector for link status interrupts */ -	numvecs++; - -	adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), -					GFP_KERNEL); - -	if (!adapter->msix_entries) -		return; - -	/* populate entry values */ -	for (i = 0; i < numvecs; i++) -		adapter->msix_entries[i].entry = i; - -	err = pci_enable_msix_range(adapter->pdev, -				    adapter->msix_entries, -				    numvecs, -				    numvecs); -	if (err > 0) -		return; - -	kfree(adapter->msix_entries); -	adapter->msix_entries = NULL; - -	igc_reset_interrupt_capability(adapter); - -msi_only: -	adapter->flags &= ~IGC_FLAG_HAS_MSIX; - -	adapter->rss_queues = 1; -	adapter->flags |= IGC_FLAG_QUEUE_PAIRS; -	adapter->num_rx_queues = 1; -	adapter->num_tx_queues = 1; -	adapter->num_q_vectors = 1; -	if (!pci_enable_msi(adapter->pdev)) -		adapter->flags |= IGC_FLAG_HAS_MSI; -} - -static void igc_add_ring(struct igc_ring *ring, -			 struct igc_ring_container *head) -{ -	head->ring = ring; -	head->count++; -} - -/** - * igc_alloc_q_vector - Allocate memory for a single interrupt vector - * @adapter: board private structure to initialize - * @v_count: q_vectors allocated on adapter, used for ring interleaving - * @v_idx: index of vector in adapter struct - * @txr_count: total number of Tx rings to allocate - * @txr_idx: index of first Tx ring to allocate - * @rxr_count: total number of Rx rings to allocate - * @rxr_idx: index of first Rx ring to allocate - * - * We allocate one q_vector.  If allocation fails we return -ENOMEM. - */ -static int igc_alloc_q_vector(struct igc_adapter *adapter, -			      unsigned int v_count, unsigned int v_idx, -			      unsigned int txr_count, unsigned int txr_idx, -			      unsigned int rxr_count, unsigned int rxr_idx) -{ -	struct igc_q_vector *q_vector; -	struct igc_ring *ring; -	int ring_count; - -	/* igc only supports 1 Tx and/or 1 Rx queue per vector */ -	if (txr_count > 1 || rxr_count > 1) -		return -ENOMEM; - -	ring_count = txr_count + rxr_count; - -	/* allocate q_vector and rings */ -	q_vector = adapter->q_vector[v_idx]; -	if (!q_vector) -		q_vector = kzalloc(struct_size(q_vector, ring, ring_count), -				   GFP_KERNEL); -	else -		memset(q_vector, 0, struct_size(q_vector, ring, ring_count)); -	if (!q_vector) -		return -ENOMEM; - -	/* initialize NAPI */ -	netif_napi_add(adapter->netdev, &q_vector->napi, -		       igc_poll, 64); - -	/* tie q_vector and adapter together */ -	adapter->q_vector[v_idx] = q_vector; -	q_vector->adapter = adapter; - -	/* initialize work limits */ -	q_vector->tx.work_limit = adapter->tx_work_limit; - -	/* initialize ITR configuration */ -	q_vector->itr_register = adapter->io_addr + IGC_EITR(0); -	q_vector->itr_val = IGC_START_ITR; - -	/* initialize pointer to rings */ -	ring = q_vector->ring; - -	/* initialize ITR */ -	if (rxr_count) { -		/* rx or rx/tx vector */ -		if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3) -			q_vector->itr_val = adapter->rx_itr_setting; -	} else { -		/* tx only vector */ -		if (!adapter->tx_itr_setting || adapter->tx_itr_setting > 3) -			q_vector->itr_val = adapter->tx_itr_setting; -	} - -	if (txr_count) { -		/* assign generic ring traits */ -		ring->dev = &adapter->pdev->dev; -		ring->netdev = adapter->netdev; - -		/* configure backlink on ring */ -		ring->q_vector = q_vector; - -		/* update q_vector Tx values */ -		igc_add_ring(ring, &q_vector->tx); - -		/* apply Tx specific ring traits */ -		ring->count = adapter->tx_ring_count; -		ring->queue_index = txr_idx; - -		/* assign ring to adapter */ -		adapter->tx_ring[txr_idx] = ring; - -		/* push pointer to next ring */ -		ring++; -	} - -	if (rxr_count) { -		/* assign generic ring traits */ -		ring->dev = &adapter->pdev->dev; -		ring->netdev = adapter->netdev; - -		/* configure backlink on ring */ -		ring->q_vector = q_vector; - -		/* update q_vector Rx values */ -		igc_add_ring(ring, &q_vector->rx); - -		/* apply Rx specific ring traits */ -		ring->count = adapter->rx_ring_count; -		ring->queue_index = rxr_idx; - -		/* assign ring to adapter */ -		adapter->rx_ring[rxr_idx] = ring; -	} - -	return 0; -} - -/** - * igc_alloc_q_vectors - Allocate memory for interrupt vectors - * @adapter: board private structure to initialize - * - * We allocate one q_vector per queue interrupt.  If allocation fails we - * return -ENOMEM. - */ -static int igc_alloc_q_vectors(struct igc_adapter *adapter) -{ -	int rxr_remaining = adapter->num_rx_queues; -	int txr_remaining = adapter->num_tx_queues; -	int rxr_idx = 0, txr_idx = 0, v_idx = 0; -	int q_vectors = adapter->num_q_vectors; -	int err; - -	if (q_vectors >= (rxr_remaining + txr_remaining)) { -		for (; rxr_remaining; v_idx++) { -			err = igc_alloc_q_vector(adapter, q_vectors, v_idx, -						 0, 0, 1, rxr_idx); - -			if (err) -				goto err_out; - -			/* update counts and index */ -			rxr_remaining--; -			rxr_idx++; -		} -	} - -	for (; v_idx < q_vectors; v_idx++) { -		int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx); -		int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx); - -		err = igc_alloc_q_vector(adapter, q_vectors, v_idx, -					 tqpv, txr_idx, rqpv, rxr_idx); - -		if (err) -			goto err_out; - -		/* update counts and index */ -		rxr_remaining -= rqpv; -		txr_remaining -= tqpv; -		rxr_idx++; -		txr_idx++; -	} - -	return 0; - -err_out: -	adapter->num_tx_queues = 0; -	adapter->num_rx_queues = 0; -	adapter->num_q_vectors = 0; - -	while (v_idx--) -		igc_free_q_vector(adapter, v_idx); - -	return -ENOMEM; -} - -/** - * igc_cache_ring_register - Descriptor ring to register mapping - * @adapter: board private structure to initialize - * - * Once we know the feature-set enabled for the device, we'll cache - * the register offset the descriptor ring is assigned to. - */ -static void igc_cache_ring_register(struct igc_adapter *adapter) -{ -	int i = 0, j = 0; - -	switch (adapter->hw.mac.type) { -	case igc_i225: -	/* Fall through */ -	default: -		for (; i < adapter->num_rx_queues; i++) -			adapter->rx_ring[i]->reg_idx = i; -		for (; j < adapter->num_tx_queues; j++) -			adapter->tx_ring[j]->reg_idx = j; -		break; -	} -} - -/** - * igc_init_interrupt_scheme - initialize interrupts, allocate queues/vectors - * @adapter: Pointer to adapter structure - * - * This function initializes the interrupts and allocates all of the queues. - */ -static int igc_init_interrupt_scheme(struct igc_adapter *adapter, bool msix) -{ -	struct pci_dev *pdev = adapter->pdev; -	int err = 0; - -	igc_set_interrupt_capability(adapter, msix); - -	err = igc_alloc_q_vectors(adapter); -	if (err) { -		dev_err(&pdev->dev, "Unable to allocate memory for vectors\n"); -		goto err_alloc_q_vectors; -	} - -	igc_cache_ring_register(adapter); - -	return 0; - -err_alloc_q_vectors: -	igc_reset_interrupt_capability(adapter); -	return err; -} -  static void igc_free_irq(struct igc_adapter *adapter)  {  	if (adapter->msix_entries) { @@ -3947,62 +4268,6 @@ static void igc_free_irq(struct igc_adapter *adapter)  }  /** - * igc_irq_disable - Mask off interrupt generation on the NIC - * @adapter: board private structure - */ -static void igc_irq_disable(struct igc_adapter *adapter) -{ -	struct igc_hw *hw = &adapter->hw; - -	if (adapter->msix_entries) { -		u32 regval = rd32(IGC_EIAM); - -		wr32(IGC_EIAM, regval & ~adapter->eims_enable_mask); -		wr32(IGC_EIMC, adapter->eims_enable_mask); -		regval = rd32(IGC_EIAC); -		wr32(IGC_EIAC, regval & ~adapter->eims_enable_mask); -	} - -	wr32(IGC_IAM, 0); -	wr32(IGC_IMC, ~0); -	wrfl(); - -	if (adapter->msix_entries) { -		int vector = 0, i; - -		synchronize_irq(adapter->msix_entries[vector++].vector); - -		for (i = 0; i < adapter->num_q_vectors; i++) -			synchronize_irq(adapter->msix_entries[vector++].vector); -	} else { -		synchronize_irq(adapter->pdev->irq); -	} -} - -/** - * igc_irq_enable - Enable default interrupt generation settings - * @adapter: board private structure - */ -static void igc_irq_enable(struct igc_adapter *adapter) -{ -	struct igc_hw *hw = &adapter->hw; - -	if (adapter->msix_entries) { -		u32 ims = IGC_IMS_LSC | IGC_IMS_DOUTSYNC | IGC_IMS_DRSTA; -		u32 regval = rd32(IGC_EIAC); - -		wr32(IGC_EIAC, regval | adapter->eims_enable_mask); -		regval = rd32(IGC_EIAM); -		wr32(IGC_EIAM, regval | adapter->eims_enable_mask); -		wr32(IGC_EIMS, adapter->eims_enable_mask); -		wr32(IGC_IMS, ims); -	} else { -		wr32(IGC_IMS, IMS_ENABLE_MASK | IGC_IMS_DRSTA); -		wr32(IGC_IAM, IMS_ENABLE_MASK | IGC_IMS_DRSTA); -	} -} - -/**   * igc_request_irq - initialize interrupts   * @adapter: Pointer to adapter structure   * @@ -4056,25 +4321,10 @@ request_done:  	return err;  } -static void igc_write_itr(struct igc_q_vector *q_vector) -{ -	u32 itr_val = q_vector->itr_val & IGC_QVECTOR_MASK; - -	if (!q_vector->set_itr) -		return; - -	if (!itr_val) -		itr_val = IGC_ITR_VAL_MASK; - -	itr_val |= IGC_EITR_CNT_IGNR; - -	writel(itr_val, q_vector->itr_register); -	q_vector->set_itr = 0; -} -  /** - * igc_open - Called when a network interface is made active + * __igc_open - Called when a network interface is made active   * @netdev: network interface device structure + * @resuming: boolean indicating if the device is resuming   *   * Returns 0 on success, negative value on failure   * @@ -4164,8 +4414,9 @@ static int igc_open(struct net_device *netdev)  }  /** - * igc_close - Disables a network interface + * __igc_close - Disables a network interface   * @netdev: network interface device structure + * @suspending: boolean indicating the device is suspending   *   * Returns 0, this is not allowed to fail   * @@ -4199,6 +4450,24 @@ static int igc_close(struct net_device *netdev)  	return 0;  } +/** + * igc_ioctl - Access the hwtstamp interface + * @netdev: network interface device structure + * @ifreq: interface request data + * @cmd: ioctl command + **/ +static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ +	switch (cmd) { +	case SIOCGHWTSTAMP: +		return igc_ptp_get_ts_config(netdev, ifr); +	case SIOCSHWTSTAMP: +		return igc_ptp_set_ts_config(netdev, ifr); +	default: +		return -EOPNOTSUPP; +	} +} +  static const struct net_device_ops igc_netdev_ops = {  	.ndo_open		= igc_open,  	.ndo_stop		= igc_close, @@ -4210,6 +4479,7 @@ static const struct net_device_ops igc_netdev_ops = {  	.ndo_fix_features	= igc_fix_features,  	.ndo_set_features	= igc_set_features,  	.ndo_features_check	= igc_features_check, +	.ndo_do_ioctl		= igc_ioctl,  };  /* PCIe configuration access */ @@ -4345,32 +4615,26 @@ static int igc_probe(struct pci_dev *pdev,  	struct net_device *netdev;  	struct igc_hw *hw;  	const struct igc_info *ei = igc_info_tbl[ent->driver_data]; -	int err; +	int err, pci_using_dac;  	err = pci_enable_device_mem(pdev);  	if (err)  		return err; -	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); +	pci_using_dac = 0; +	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));  	if (!err) { -		err = dma_set_coherent_mask(&pdev->dev, -					    DMA_BIT_MASK(64)); +		pci_using_dac = 1;  	} else { -		err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); +		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));  		if (err) { -			err = dma_set_coherent_mask(&pdev->dev, -						    DMA_BIT_MASK(32)); -			if (err) { -				dev_err(&pdev->dev, "igc: Wrong DMA config\n"); -				goto err_dma; -			} +			dev_err(&pdev->dev, +				"No usable DMA configuration, aborting\n"); +			goto err_dma;  		}  	} -	err = pci_request_selected_regions(pdev, -					   pci_select_bars(pdev, -							   IORESOURCE_MEM), -					   igc_driver_name); +	err = pci_request_mem_regions(pdev, igc_driver_name);  	if (err)  		goto err_pci_reg; @@ -4433,6 +4697,9 @@ static int igc_probe(struct pci_dev *pdev,  		goto err_sw_init;  	/* Add supported features to the features list*/ +	netdev->features |= NETIF_F_SG; +	netdev->features |= NETIF_F_TSO; +	netdev->features |= NETIF_F_TSO6;  	netdev->features |= NETIF_F_RXCSUM;  	netdev->features |= NETIF_F_HW_CSUM;  	netdev->features |= NETIF_F_SCTP_CRC; @@ -4446,6 +4713,9 @@ static int igc_probe(struct pci_dev *pdev,  	netdev->hw_features |= NETIF_F_NTUPLE;  	netdev->hw_features |= netdev->features; +	if (pci_using_dac) +		netdev->features |= NETIF_F_HIGHDMA; +  	/* MTU range: 68 - 9216 */  	netdev->min_mtu = ETH_MIN_MTU;  	netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; @@ -4512,6 +4782,9 @@ static int igc_probe(struct pci_dev *pdev,  	 /* carrier off reporting is important to ethtool even BEFORE open */  	netif_carrier_off(netdev); +	/* do hw tstamp init after resetting */ +	igc_ptp_init(adapter); +  	/* Check if Media Autosense is enabled */  	adapter->ei = *ei; @@ -4532,8 +4805,7 @@ err_sw_init:  err_ioremap:  	free_netdev(netdev);  err_alloc_etherdev: -	pci_release_selected_regions(pdev, -				     pci_select_bars(pdev, IORESOURCE_MEM)); +	pci_release_mem_regions(pdev);  err_pci_reg:  err_dma:  	pci_disable_device(pdev); @@ -4554,6 +4826,8 @@ static void igc_remove(struct pci_dev *pdev)  	struct net_device *netdev = pci_get_drvdata(pdev);  	struct igc_adapter *adapter = netdev_priv(netdev); +	igc_ptp_stop(adapter); +  	set_bit(__IGC_DOWN, &adapter->state);  	del_timer_sync(&adapter->watchdog_timer); @@ -4580,105 +4854,216 @@ static void igc_remove(struct pci_dev *pdev)  	pci_disable_device(pdev);  } -static struct pci_driver igc_driver = { -	.name     = igc_driver_name, -	.id_table = igc_pci_tbl, -	.probe    = igc_probe, -	.remove   = igc_remove, -}; - -void igc_set_flag_queue_pairs(struct igc_adapter *adapter, -			      const u32 max_rss_queues) +static int __igc_shutdown(struct pci_dev *pdev, bool *enable_wake, +			  bool runtime)  { -	/* Determine if we need to pair queues. */ -	/* If rss_queues > half of max_rss_queues, pair the queues in -	 * order to conserve interrupts due to limited supply. -	 */ -	if (adapter->rss_queues > (max_rss_queues / 2)) -		adapter->flags |= IGC_FLAG_QUEUE_PAIRS; +	struct net_device *netdev = pci_get_drvdata(pdev); +	struct igc_adapter *adapter = netdev_priv(netdev); +	u32 wufc = runtime ? IGC_WUFC_LNKC : adapter->wol; +	struct igc_hw *hw = &adapter->hw; +	u32 ctrl, rctl, status; +	bool wake; + +	rtnl_lock(); +	netif_device_detach(netdev); + +	if (netif_running(netdev)) +		__igc_close(netdev, true); + +	igc_clear_interrupt_scheme(adapter); +	rtnl_unlock(); + +	status = rd32(IGC_STATUS); +	if (status & IGC_STATUS_LU) +		wufc &= ~IGC_WUFC_LNKC; + +	if (wufc) { +		igc_setup_rctl(adapter); +		igc_set_rx_mode(netdev); + +		/* turn on all-multi mode if wake on multicast is enabled */ +		if (wufc & IGC_WUFC_MC) { +			rctl = rd32(IGC_RCTL); +			rctl |= IGC_RCTL_MPE; +			wr32(IGC_RCTL, rctl); +		} + +		ctrl = rd32(IGC_CTRL); +		ctrl |= IGC_CTRL_ADVD3WUC; +		wr32(IGC_CTRL, ctrl); + +		/* Allow time for pending master requests to run */ +		igc_disable_pcie_master(hw); + +		wr32(IGC_WUC, IGC_WUC_PME_EN); +		wr32(IGC_WUFC, wufc); +	} else { +		wr32(IGC_WUC, 0); +		wr32(IGC_WUFC, 0); +	} + +	wake = wufc || adapter->en_mng_pt; +	if (!wake) +		igc_power_down_link(adapter);  	else -		adapter->flags &= ~IGC_FLAG_QUEUE_PAIRS; -} +		igc_power_up_link(adapter); -unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter) -{ -	unsigned int max_rss_queues; +	if (enable_wake) +		*enable_wake = wake; -	/* Determine the maximum number of RSS queues supported. */ -	max_rss_queues = IGC_MAX_RX_QUEUES; +	/* Release control of h/w to f/w.  If f/w is AMT enabled, this +	 * would have already happened in close and is redundant. +	 */ +	igc_release_hw_control(adapter); -	return max_rss_queues; +	pci_disable_device(pdev); + +	return 0;  } -static void igc_init_queue_configuration(struct igc_adapter *adapter) +#ifdef CONFIG_PM +static int __maybe_unused igc_runtime_suspend(struct device *dev)  { -	u32 max_rss_queues; - -	max_rss_queues = igc_get_max_rss_queues(adapter); -	adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus()); - -	igc_set_flag_queue_pairs(adapter, max_rss_queues); +	return __igc_shutdown(to_pci_dev(dev), NULL, 1);  } -/** - * igc_sw_init - Initialize general software structures (struct igc_adapter) - * @adapter: board private structure to initialize - * - * igc_sw_init initializes the Adapter private data structure. - * Fields are initialized based on PCI device information and - * OS network device settings (MTU size). - */ -static int igc_sw_init(struct igc_adapter *adapter) +static void igc_deliver_wake_packet(struct net_device *netdev)  { -	struct net_device *netdev = adapter->netdev; -	struct pci_dev *pdev = adapter->pdev; +	struct igc_adapter *adapter = netdev_priv(netdev);  	struct igc_hw *hw = &adapter->hw; +	struct sk_buff *skb; +	u32 wupl; -	int size = sizeof(struct igc_mac_addr) * hw->mac.rar_entry_count; +	wupl = rd32(IGC_WUPL) & IGC_WUPL_MASK; -	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); +	/* WUPM stores only the first 128 bytes of the wake packet. +	 * Read the packet only if we have the whole thing. +	 */ +	if (wupl == 0 || wupl > IGC_WUPM_BYTES) +		return; -	/* set default ring sizes */ -	adapter->tx_ring_count = IGC_DEFAULT_TXD; -	adapter->rx_ring_count = IGC_DEFAULT_RXD; +	skb = netdev_alloc_skb_ip_align(netdev, IGC_WUPM_BYTES); +	if (!skb) +		return; -	/* set default ITR values */ -	adapter->rx_itr_setting = IGC_DEFAULT_ITR; -	adapter->tx_itr_setting = IGC_DEFAULT_ITR; +	skb_put(skb, wupl); -	/* set default work limits */ -	adapter->tx_work_limit = IGC_DEFAULT_TX_WORK; +	/* Ensure reads are 32-bit aligned */ +	wupl = roundup(wupl, 4); -	/* adjust max frame to be at least the size of a standard frame */ -	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + -				VLAN_HLEN; -	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; +	memcpy_fromio(skb->data, hw->hw_addr + IGC_WUPM_REG(0), wupl); -	spin_lock_init(&adapter->nfc_lock); -	spin_lock_init(&adapter->stats64_lock); -	/* Assume MSI-X interrupts, will be checked during IRQ allocation */ -	adapter->flags |= IGC_FLAG_HAS_MSIX; +	skb->protocol = eth_type_trans(skb, netdev); +	netif_rx(skb); +} -	adapter->mac_table = kzalloc(size, GFP_ATOMIC); -	if (!adapter->mac_table) -		return -ENOMEM; +static int __maybe_unused igc_resume(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct net_device *netdev = pci_get_drvdata(pdev); +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct igc_hw *hw = &adapter->hw; +	u32 err, val; -	igc_init_queue_configuration(adapter); +	pci_set_power_state(pdev, PCI_D0); +	pci_restore_state(pdev); +	pci_save_state(pdev); + +	if (!pci_device_is_present(pdev)) +		return -ENODEV; +	err = pci_enable_device_mem(pdev); +	if (err) { +		dev_err(&pdev->dev, +			"igc: Cannot enable PCI device from suspend\n"); +		return err; +	} +	pci_set_master(pdev); + +	pci_enable_wake(pdev, PCI_D3hot, 0); +	pci_enable_wake(pdev, PCI_D3cold, 0); -	/* This call may decrease the number of queues */  	if (igc_init_interrupt_scheme(adapter, true)) {  		dev_err(&pdev->dev, "Unable to allocate memory for queues\n");  		return -ENOMEM;  	} -	/* Explicitly disable IRQ since the NIC can be in any state. */ -	igc_irq_disable(adapter); +	igc_reset(adapter); -	set_bit(__IGC_DOWN, &adapter->state); +	/* let the f/w know that the h/w is now under the control of the +	 * driver. +	 */ +	igc_get_hw_control(adapter); -	return 0; +	val = rd32(IGC_WUS); +	if (val & WAKE_PKT_WUS) +		igc_deliver_wake_packet(netdev); + +	wr32(IGC_WUS, ~0); + +	rtnl_lock(); +	if (!err && netif_running(netdev)) +		err = __igc_open(netdev, true); + +	if (!err) +		netif_device_attach(netdev); +	rtnl_unlock(); + +	return err; +} + +static int __maybe_unused igc_runtime_resume(struct device *dev) +{ +	return igc_resume(dev); +} + +static int __maybe_unused igc_suspend(struct device *dev) +{ +	return __igc_shutdown(to_pci_dev(dev), NULL, 0);  } +static int __maybe_unused igc_runtime_idle(struct device *dev) +{ +	struct net_device *netdev = dev_get_drvdata(dev); +	struct igc_adapter *adapter = netdev_priv(netdev); + +	if (!igc_has_link(adapter)) +		pm_schedule_suspend(dev, MSEC_PER_SEC * 5); + +	return -EBUSY; +} +#endif /* CONFIG_PM */ + +static void igc_shutdown(struct pci_dev *pdev) +{ +	bool wake; + +	__igc_shutdown(pdev, &wake, 0); + +	if (system_state == SYSTEM_POWER_OFF) { +		pci_wake_from_d3(pdev, wake); +		pci_set_power_state(pdev, PCI_D3hot); +	} +} + +#ifdef CONFIG_PM +static const struct dev_pm_ops igc_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(igc_suspend, igc_resume) +	SET_RUNTIME_PM_OPS(igc_runtime_suspend, igc_runtime_resume, +			   igc_runtime_idle) +}; +#endif + +static struct pci_driver igc_driver = { +	.name     = igc_driver_name, +	.id_table = igc_pci_tbl, +	.probe    = igc_probe, +	.remove   = igc_remove, +#ifdef CONFIG_PM +	.driver.pm = &igc_pm_ops, +#endif +	.shutdown = igc_shutdown, +}; +  /**   * igc_reinit_queues - return error   * @adapter: pointer to adapter structure diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index f4b05af0dd2f..8e1799508edc 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -173,6 +173,7 @@ s32 igc_check_downshift(struct igc_hw *hw)  s32 igc_phy_hw_reset(struct igc_hw *hw)  {  	struct igc_phy_info *phy = &hw->phy; +	u32 phpm = 0, timeout = 10000;  	s32  ret_val;  	u32 ctrl; @@ -186,6 +187,8 @@ s32 igc_phy_hw_reset(struct igc_hw *hw)  	if (ret_val)  		goto out; +	phpm = rd32(IGC_I225_PHPM); +  	ctrl = rd32(IGC_CTRL);  	wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);  	wrfl(); @@ -195,7 +198,18 @@ s32 igc_phy_hw_reset(struct igc_hw *hw)  	wr32(IGC_CTRL, ctrl);  	wrfl(); -	usleep_range(1500, 2000); +	/* SW should guarantee 100us for the completion of the PHY reset */ +	usleep_range(100, 150); +	do { +		phpm = rd32(IGC_I225_PHPM); +		timeout--; +		udelay(1); +	} while (!(phpm & IGC_PHY_RST_COMP) && timeout); + +	if (!timeout) +		hw_dbg("Timeout is expired after a phy reset\n"); + +	usleep_range(100, 150);  	phy->ops.release(hw); diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c new file mode 100644 index 000000000000..693506587198 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -0,0 +1,716 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c)  2019 Intel Corporation */ + +#include "igc.h" + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/pci.h> +#include <linux/ptp_classify.h> +#include <linux/clocksource.h> + +#define INCVALUE_MASK		0x7fffffff +#define ISGN			0x80000000 + +#define IGC_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 9) +#define IGC_PTP_TX_TIMEOUT		(HZ * 15) + +/* SYSTIM read access for I225 */ +static void igc_ptp_read_i225(struct igc_adapter *adapter, +			      struct timespec64 *ts) +{ +	struct igc_hw *hw = &adapter->hw; +	u32 sec, nsec; + +	/* The timestamp latches on lowest register read. For I210/I211, the +	 * lowest register is SYSTIMR. Since we only need to provide nanosecond +	 * resolution, we can ignore it. +	 */ +	rd32(IGC_SYSTIMR); +	nsec = rd32(IGC_SYSTIML); +	sec = rd32(IGC_SYSTIMH); + +	ts->tv_sec = sec; +	ts->tv_nsec = nsec; +} + +static void igc_ptp_write_i225(struct igc_adapter *adapter, +			       const struct timespec64 *ts) +{ +	struct igc_hw *hw = &adapter->hw; + +	/* Writing the SYSTIMR register is not necessary as it only +	 * provides sub-nanosecond resolution. +	 */ +	wr32(IGC_SYSTIML, ts->tv_nsec); +	wr32(IGC_SYSTIMH, ts->tv_sec); +} + +static int igc_ptp_adjfine_i225(struct ptp_clock_info *ptp, long scaled_ppm) +{ +	struct igc_adapter *igc = container_of(ptp, struct igc_adapter, +					       ptp_caps); +	struct igc_hw *hw = &igc->hw; +	int neg_adj = 0; +	u64 rate; +	u32 inca; + +	if (scaled_ppm < 0) { +		neg_adj = 1; +		scaled_ppm = -scaled_ppm; +	} +	rate = scaled_ppm; +	rate <<= 14; +	rate = div_u64(rate, 78125); + +	inca = rate & INCVALUE_MASK; +	if (neg_adj) +		inca |= ISGN; + +	wr32(IGC_TIMINCA, inca); + +	return 0; +} + +static int igc_ptp_adjtime_i225(struct ptp_clock_info *ptp, s64 delta) +{ +	struct igc_adapter *igc = container_of(ptp, struct igc_adapter, +					       ptp_caps); +	struct timespec64 now, then = ns_to_timespec64(delta); +	unsigned long flags; + +	spin_lock_irqsave(&igc->tmreg_lock, flags); + +	igc_ptp_read_i225(igc, &now); +	now = timespec64_add(now, then); +	igc_ptp_write_i225(igc, (const struct timespec64 *)&now); + +	spin_unlock_irqrestore(&igc->tmreg_lock, flags); + +	return 0; +} + +static int igc_ptp_gettimex64_i225(struct ptp_clock_info *ptp, +				   struct timespec64 *ts, +				   struct ptp_system_timestamp *sts) +{ +	struct igc_adapter *igc = container_of(ptp, struct igc_adapter, +					       ptp_caps); +	struct igc_hw *hw = &igc->hw; +	unsigned long flags; + +	spin_lock_irqsave(&igc->tmreg_lock, flags); + +	ptp_read_system_prets(sts); +	rd32(IGC_SYSTIMR); +	ptp_read_system_postts(sts); +	ts->tv_nsec = rd32(IGC_SYSTIML); +	ts->tv_sec = rd32(IGC_SYSTIMH); + +	spin_unlock_irqrestore(&igc->tmreg_lock, flags); + +	return 0; +} + +static int igc_ptp_settime_i225(struct ptp_clock_info *ptp, +				const struct timespec64 *ts) +{ +	struct igc_adapter *igc = container_of(ptp, struct igc_adapter, +					       ptp_caps); +	unsigned long flags; + +	spin_lock_irqsave(&igc->tmreg_lock, flags); + +	igc_ptp_write_i225(igc, ts); + +	spin_unlock_irqrestore(&igc->tmreg_lock, flags); + +	return 0; +} + +static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp, +				       struct ptp_clock_request *rq, int on) +{ +	return -EOPNOTSUPP; +} + +/** + * igc_ptp_systim_to_hwtstamp - convert system time value to HW timestamp + * @adapter: board private structure + * @hwtstamps: timestamp structure to update + * @systim: unsigned 64bit system time value + * + * 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. + **/ +static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, +				       struct skb_shared_hwtstamps *hwtstamps, +				       u64 systim) +{ +	switch (adapter->hw.mac.type) { +	case igc_i225: +		memset(hwtstamps, 0, sizeof(*hwtstamps)); +		/* Upper 32 bits contain s, lower 32 bits contain ns. */ +		hwtstamps->hwtstamp = ktime_set(systim >> 32, +						systim & 0xFFFFFFFF); +		break; +	default: +		break; +	} +} + +/** + * igc_ptp_rx_pktstamp - retrieve Rx per packet timestamp + * @q_vector: Pointer to interrupt specific structure + * @va: Pointer to address containing Rx buffer + * @skb: Buffer containing timestamp and packet + * + * This function is meant to retrieve the first timestamp from the + * first buffer of an incoming frame. The value is stored in little + * endian format starting on byte 0. There's a second timestamp + * starting on byte 8. + **/ +void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, void *va, +			 struct sk_buff *skb) +{ +	struct igc_adapter *adapter = q_vector->adapter; +	__le64 *regval = (__le64 *)va; +	int adjust = 0; + +	/* The timestamp is recorded in little endian format. +	 * DWORD: | 0          | 1           | 2          | 3 +	 * Field: | Timer0 Low | Timer0 High | Timer1 Low | Timer1 High +	 */ +	igc_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), +				   le64_to_cpu(regval[0])); + +	/* adjust timestamp for the RX latency based on link speed */ +	if (adapter->hw.mac.type == igc_i225) { +		switch (adapter->link_speed) { +		case SPEED_10: +			adjust = IGC_I225_RX_LATENCY_10; +			break; +		case SPEED_100: +			adjust = IGC_I225_RX_LATENCY_100; +			break; +		case SPEED_1000: +			adjust = IGC_I225_RX_LATENCY_1000; +			break; +		case SPEED_2500: +			adjust = IGC_I225_RX_LATENCY_2500; +			break; +		} +	} +	skb_hwtstamps(skb)->hwtstamp = +		ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); +} + +/** + * igc_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register + * @q_vector: Pointer to interrupt specific structure + * @skb: Buffer containing timestamp and packet + * + * This function is meant to retrieve a timestamp from the internal registers + * of the adapter and store it in the skb. + */ +void igc_ptp_rx_rgtstamp(struct igc_q_vector *q_vector, +			 struct sk_buff *skb) +{ +	struct igc_adapter *adapter = q_vector->adapter; +	struct igc_hw *hw = &adapter->hw; +	u64 regval; + +	/* If this bit is set, then the RX registers contain the time +	 * stamp. No other packet will be time stamped until we read +	 * these registers, so read the registers to make them +	 * available again. Because only one packet can be time +	 * stamped at a time, we know that the register values must +	 * belong to this one here and therefore we don't need to +	 * compare any of the additional attributes stored for it. +	 * +	 * If nothing went wrong, then it should have a shared +	 * tx_flags that we can turn into a skb_shared_hwtstamps. +	 */ +	if (!(rd32(IGC_TSYNCRXCTL) & IGC_TSYNCRXCTL_VALID)) +		return; + +	regval = rd32(IGC_RXSTMPL); +	regval |= (u64)rd32(IGC_RXSTMPH) << 32; + +	igc_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); + +	/* Update the last_rx_timestamp timer in order to enable watchdog check +	 * for error case of latched timestamp on a dropped packet. +	 */ +	adapter->last_rx_timestamp = jiffies; +} + +/** + * igc_ptp_enable_tstamp_rxqueue - Enable RX timestamp for a queue + * @rx_ring: Pointer to RX queue + * @timer: Index for timer + * + * This function enables RX timestamping for a queue, and selects + * which 1588 timer will provide the timestamp. + */ +static void igc_ptp_enable_tstamp_rxqueue(struct igc_adapter *adapter, +					  struct igc_ring *rx_ring, u8 timer) +{ +	struct igc_hw *hw = &adapter->hw; +	int reg_idx = rx_ring->reg_idx; +	u32 srrctl = rd32(IGC_SRRCTL(reg_idx)); + +	srrctl |= IGC_SRRCTL_TIMESTAMP; +	srrctl |= IGC_SRRCTL_TIMER1SEL(timer); +	srrctl |= IGC_SRRCTL_TIMER0SEL(timer); + +	wr32(IGC_SRRCTL(reg_idx), srrctl); +} + +static void igc_ptp_enable_tstamp_all_rxqueues(struct igc_adapter *adapter, +					       u8 timer) +{ +	int i; + +	for (i = 0; i < adapter->num_rx_queues; i++) { +		struct igc_ring *ring = adapter->rx_ring[i]; + +		igc_ptp_enable_tstamp_rxqueue(adapter, ring, timer); +	} +} + +/** + * igc_ptp_set_timestamp_mode - setup hardware for timestamping + * @adapter: networking device structure + * @config: hwtstamp configuration + * + * Outgoing time stamping can be enabled and disabled. Play nice and + * disable it when requested, although it shouldn't case any overhead + * when no packet needs it. At most one packet in the queue may be + * marked for time stamping, otherwise it would be impossible to tell + * for sure to which packet the hardware time stamp belongs. + * + * Incoming time stamping has to be configured via the hardware + * filters. Not all combinations are supported, in particular event + * type has to be specified. Matching the kind of event packet is + * not supported, with the exception of "all V2 events regardless of + * level 2 or 4". + * + */ +static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter, +				      struct hwtstamp_config *config) +{ +	u32 tsync_tx_ctl = IGC_TSYNCTXCTL_ENABLED; +	u32 tsync_rx_ctl = IGC_TSYNCRXCTL_ENABLED; +	struct igc_hw *hw = &adapter->hw; +	u32 tsync_rx_cfg = 0; +	bool is_l4 = false; +	bool is_l2 = false; +	u32 regval; + +	/* reserved for future extensions */ +	if (config->flags) +		return -EINVAL; + +	switch (config->tx_type) { +	case HWTSTAMP_TX_OFF: +		tsync_tx_ctl = 0; +	case HWTSTAMP_TX_ON: +		break; +	default: +		return -ERANGE; +	} + +	switch (config->rx_filter) { +	case HWTSTAMP_FILTER_NONE: +		tsync_rx_ctl = 0; +		break; +	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: +		tsync_rx_ctl |= IGC_TSYNCRXCTL_TYPE_L4_V1; +		tsync_rx_cfg = IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; +		is_l4 = true; +		break; +	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: +		tsync_rx_ctl |= IGC_TSYNCRXCTL_TYPE_L4_V1; +		tsync_rx_cfg = IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; +		is_l4 = true; +		break; +	case HWTSTAMP_FILTER_PTP_V2_EVENT: +	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: +	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: +	case HWTSTAMP_FILTER_PTP_V2_SYNC: +	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: +	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: +	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: +	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: +	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: +		tsync_rx_ctl |= IGC_TSYNCRXCTL_TYPE_EVENT_V2; +		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; +		is_l2 = true; +		is_l4 = true; +		break; +	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: +	case HWTSTAMP_FILTER_NTP_ALL: +	case HWTSTAMP_FILTER_ALL: +		tsync_rx_ctl |= IGC_TSYNCRXCTL_TYPE_ALL; +		config->rx_filter = HWTSTAMP_FILTER_ALL; +		break; +		/* fall through */ +	default: +		config->rx_filter = HWTSTAMP_FILTER_NONE; +		return -ERANGE; +	} + +	/* Per-packet timestamping only works if all packets are +	 * timestamped, so enable timestamping in all packets as long +	 * as one Rx filter was configured. +	 */ +	if (tsync_rx_ctl) { +		tsync_rx_ctl = IGC_TSYNCRXCTL_ENABLED; +		tsync_rx_ctl |= IGC_TSYNCRXCTL_TYPE_ALL; +		tsync_rx_ctl |= IGC_TSYNCRXCTL_RXSYNSIG; +		config->rx_filter = HWTSTAMP_FILTER_ALL; +		is_l2 = true; +		is_l4 = true; + +		if (hw->mac.type == igc_i225) { +			regval = rd32(IGC_RXPBS); +			regval |= IGC_RXPBS_CFG_TS_EN; +			wr32(IGC_RXPBS, regval); + +			/* FIXME: For now, only support retrieving RX +			 * timestamps from timer 0 +			 */ +			igc_ptp_enable_tstamp_all_rxqueues(adapter, 0); +		} +	} + +	if (tsync_tx_ctl) { +		tsync_tx_ctl = IGC_TSYNCTXCTL_ENABLED; +		tsync_tx_ctl |= IGC_TSYNCTXCTL_TXSYNSIG; +	} + +	/* enable/disable TX */ +	regval = rd32(IGC_TSYNCTXCTL); +	regval &= ~IGC_TSYNCTXCTL_ENABLED; +	regval |= tsync_tx_ctl; +	wr32(IGC_TSYNCTXCTL, regval); + +	/* enable/disable RX */ +	regval = rd32(IGC_TSYNCRXCTL); +	regval &= ~(IGC_TSYNCRXCTL_ENABLED | IGC_TSYNCRXCTL_TYPE_MASK); +	regval |= tsync_rx_ctl; +	wr32(IGC_TSYNCRXCTL, regval); + +	/* define which PTP packets are time stamped */ +	wr32(IGC_TSYNCRXCFG, tsync_rx_cfg); + +	/* define ethertype filter for timestamped packets */ +	if (is_l2) +		wr32(IGC_ETQF(3), +		     (IGC_ETQF_FILTER_ENABLE | /* enable filter */ +		     IGC_ETQF_1588 | /* enable timestamping */ +		     ETH_P_1588)); /* 1588 eth protocol type */ +	else +		wr32(IGC_ETQF(3), 0); + +	/* L4 Queue Filter[3]: filter by destination port and protocol */ +	if (is_l4) { +		u32 ftqf = (IPPROTO_UDP /* UDP */ +			    | IGC_FTQF_VF_BP /* VF not compared */ +			    | IGC_FTQF_1588_TIME_STAMP /* Enable Timestamp */ +			    | IGC_FTQF_MASK); /* mask all inputs */ +		ftqf &= ~IGC_FTQF_MASK_PROTO_BP; /* enable protocol check */ + +		wr32(IGC_IMIR(3), htons(PTP_EV_PORT)); +		wr32(IGC_IMIREXT(3), +		     (IGC_IMIREXT_SIZE_BP | IGC_IMIREXT_CTRL_BP)); +		wr32(IGC_FTQF(3), ftqf); +	} else { +		wr32(IGC_FTQF(3), IGC_FTQF_MASK); +	} +	wrfl(); + +	/* clear TX/RX time stamp registers, just to be sure */ +	regval = rd32(IGC_TXSTMPL); +	regval = rd32(IGC_TXSTMPH); +	regval = rd32(IGC_RXSTMPL); +	regval = rd32(IGC_RXSTMPH); + +	return 0; +} + +void igc_ptp_tx_hang(struct igc_adapter *adapter) +{ +	bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + +					      IGC_PTP_TX_TIMEOUT); +	struct igc_hw *hw = &adapter->hw; + +	if (!adapter->ptp_tx_skb) +		return; + +	if (!test_bit(__IGC_PTP_TX_IN_PROGRESS, &adapter->state)) +		return; + +	/* If we haven't received a timestamp within the timeout, it is +	 * reasonable to assume that it will never occur, so we can unlock the +	 * timestamp bit when this occurs. +	 */ +	if (timeout) { +		cancel_work_sync(&adapter->ptp_tx_work); +		dev_kfree_skb_any(adapter->ptp_tx_skb); +		adapter->ptp_tx_skb = NULL; +		clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); +		adapter->tx_hwtstamp_timeouts++; +		/* Clear the Tx valid bit in TSYNCTXCTL register to enable +		 * interrupt +		 */ +		rd32(IGC_TXSTMPH); +		dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); +	} +} + +/** + * igc_ptp_tx_hwtstamp - utility function which checks for TX time stamp + * @adapter: Board private structure + * + * If we were asked to do hardware stamping and such a time stamp is + * available, then it must have been for this skb here because we only + * allow only one such packet into the queue. + */ +static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) +{ +	struct sk_buff *skb = adapter->ptp_tx_skb; +	struct skb_shared_hwtstamps shhwtstamps; +	struct igc_hw *hw = &adapter->hw; +	u64 regval; + +	regval = rd32(IGC_TXSTMPL); +	regval |= (u64)rd32(IGC_TXSTMPH) << 32; +	igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); + +	/* Clear the lock early before calling skb_tstamp_tx so that +	 * applications are not woken up before the lock bit is clear. We use +	 * a copy of the skb pointer to ensure other threads can't change it +	 * while we're notifying the stack. +	 */ +	adapter->ptp_tx_skb = NULL; +	clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); + +	/* Notify the stack and free the skb after we've unlocked */ +	skb_tstamp_tx(skb, &shhwtstamps); +	dev_kfree_skb_any(skb); +} + +/** + * igc_ptp_tx_work + * @work: pointer to work struct + * + * This work function polls the TSYNCTXCTL valid bit to determine when a + * timestamp has been taken for the current stored skb. + */ +void igc_ptp_tx_work(struct work_struct *work) +{ +	struct igc_adapter *adapter = container_of(work, struct igc_adapter, +						   ptp_tx_work); +	struct igc_hw *hw = &adapter->hw; +	u32 tsynctxctl; + +	if (!adapter->ptp_tx_skb) +		return; + +	if (time_is_before_jiffies(adapter->ptp_tx_start + +				   IGC_PTP_TX_TIMEOUT)) { +		dev_kfree_skb_any(adapter->ptp_tx_skb); +		adapter->ptp_tx_skb = NULL; +		clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); +		adapter->tx_hwtstamp_timeouts++; +		/* Clear the tx valid bit in TSYNCTXCTL register to enable +		 * interrupt +		 */ +		rd32(IGC_TXSTMPH); +		dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); +		return; +	} + +	tsynctxctl = rd32(IGC_TSYNCTXCTL); +	if (tsynctxctl & IGC_TSYNCTXCTL_VALID) +		igc_ptp_tx_hwtstamp(adapter); +	else +		/* reschedule to check later */ +		schedule_work(&adapter->ptp_tx_work); +} + +/** + * igc_ptp_set_ts_config - set hardware time stamping config + * @netdev: network interface device structure + * @ifreq: interface request data + * + **/ +int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct hwtstamp_config config; +	int err; + +	if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) +		return -EFAULT; + +	err = igc_ptp_set_timestamp_mode(adapter, &config); +	if (err) +		return err; + +	/* save these settings for future reference */ +	memcpy(&adapter->tstamp_config, &config, +	       sizeof(adapter->tstamp_config)); + +	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? +		-EFAULT : 0; +} + +/** + * igc_ptp_get_ts_config - get hardware time stamping config + * @netdev: network interface device structure + * @ifreq: interface request data + * + * Get the hwtstamp_config settings to return to the user. Rather than attempt + * to deconstruct the settings from the registers, just return a shadow copy + * of the last known settings. + **/ +int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct hwtstamp_config *config = &adapter->tstamp_config; + +	return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? +		-EFAULT : 0; +} + +/** + * igc_ptp_init - Initialize PTP functionality + * @adapter: Board private structure + * + * This function is called at device probe to initialize the PTP + * functionality. + */ +void igc_ptp_init(struct igc_adapter *adapter) +{ +	struct net_device *netdev = adapter->netdev; +	struct igc_hw *hw = &adapter->hw; + +	switch (hw->mac.type) { +	case igc_i225: +		snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); +		adapter->ptp_caps.owner = THIS_MODULE; +		adapter->ptp_caps.max_adj = 62499999; +		adapter->ptp_caps.adjfine = igc_ptp_adjfine_i225; +		adapter->ptp_caps.adjtime = igc_ptp_adjtime_i225; +		adapter->ptp_caps.gettimex64 = igc_ptp_gettimex64_i225; +		adapter->ptp_caps.settime64 = igc_ptp_settime_i225; +		adapter->ptp_caps.enable = igc_ptp_feature_enable_i225; +		break; +	default: +		adapter->ptp_clock = NULL; +		return; +	} + +	spin_lock_init(&adapter->tmreg_lock); +	INIT_WORK(&adapter->ptp_tx_work, igc_ptp_tx_work); + +	adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; +	adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; + +	igc_ptp_reset(adapter); + +	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, +						&adapter->pdev->dev); +	if (IS_ERR(adapter->ptp_clock)) { +		adapter->ptp_clock = NULL; +		dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); +	} else if (adapter->ptp_clock) { +		dev_info(&adapter->pdev->dev, "added PHC on %s\n", +			 adapter->netdev->name); +		adapter->ptp_flags |= IGC_PTP_ENABLED; +	} +} + +/** + * igc_ptp_suspend - Disable PTP work items and prepare for suspend + * @adapter: Board private structure + * + * This function stops the overflow check work and PTP Tx timestamp work, and + * will prepare the device for OS suspend. + */ +void igc_ptp_suspend(struct igc_adapter *adapter) +{ +	if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) +		return; + +	cancel_work_sync(&adapter->ptp_tx_work); +	if (adapter->ptp_tx_skb) { +		dev_kfree_skb_any(adapter->ptp_tx_skb); +		adapter->ptp_tx_skb = NULL; +		clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); +	} +} + +/** + * igc_ptp_stop - Disable PTP device and stop the overflow check. + * @adapter: Board private structure. + * + * This function stops the PTP support and cancels the delayed work. + **/ +void igc_ptp_stop(struct igc_adapter *adapter) +{ +	igc_ptp_suspend(adapter); + +	if (adapter->ptp_clock) { +		ptp_clock_unregister(adapter->ptp_clock); +		dev_info(&adapter->pdev->dev, "removed PHC on %s\n", +			 adapter->netdev->name); +		adapter->ptp_flags &= ~IGC_PTP_ENABLED; +	} +} + +/** + * igc_ptp_reset - Re-enable the adapter for PTP following a reset. + * @adapter: Board private structure. + * + * This function handles the reset work required to re-enable the PTP device. + **/ +void igc_ptp_reset(struct igc_adapter *adapter) +{ +	struct igc_hw *hw = &adapter->hw; +	unsigned long flags; + +	/* reset the tstamp_config */ +	igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + +	spin_lock_irqsave(&adapter->tmreg_lock, flags); + +	switch (adapter->hw.mac.type) { +	case igc_i225: +		wr32(IGC_TSAUXC, 0x0); +		wr32(IGC_TSSDP, 0x0); +		wr32(IGC_TSIM, IGC_TSICR_INTERRUPTS); +		wr32(IGC_IMS, IGC_IMS_TS); +		break; +	default: +		/* No work to do. */ +		goto out; +	} + +	/* Re-initialize the timer. */ +	if (hw->mac.type == igc_i225) { +		struct timespec64 ts64 = ktime_to_timespec64(ktime_get_real()); + +		igc_ptp_write_i225(adapter, &ts64); +	} else { +		timecounter_init(&adapter->tc, &adapter->cc, +				 ktime_to_ns(ktime_get_real())); +	} +out: +	spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + +	wrfl(); +} diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index 50d7c04dccf5..c9029b549b90 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -12,6 +12,7 @@  #define IGC_MDIC		0x00020  /* MDI Control - RW */  #define IGC_MDICNFG		0x00E04  /* MDC/MDIO Configuration - RW */  #define IGC_CONNSW		0x00034  /* Copper/Fiber switch control - RW */ +#define IGC_I225_PHPM		0x00E14  /* I225 PHY Power Management */  /* Internal Packet Buffer Size Registers */  #define IGC_RXPBS		0x02404  /* Rx Packet Buffer Size - RW */ @@ -209,12 +210,48 @@  #define IGC_LENERRS	0x04138  /* Length Errors Count */  #define IGC_HRMPC	0x0A018  /* Header Redirection Missed Packet Count */ +/* Time sync registers */ +#define IGC_TSICR	0x0B66C  /* Time Sync Interrupt Cause */ +#define IGC_TSIM	0x0B674  /* Time Sync Interrupt Mask Register */ +#define IGC_TSAUXC	0x0B640  /* Timesync Auxiliary Control register */ +#define IGC_TSYNCRXCTL	0x0B620  /* Rx Time Sync Control register - RW */ +#define IGC_TSYNCTXCTL	0x0B614  /* Tx Time Sync Control register - RW */ +#define IGC_TSYNCRXCFG	0x05F50  /* Time Sync Rx Configuration - RW */ +#define IGC_TSSDP	0x0003C  /* Time Sync SDP Configuration Register - RW */ + +#define IGC_IMIR(_i)	(0x05A80 + ((_i) * 4))  /* Immediate Interrupt */ +#define IGC_IMIREXT(_i)	(0x05AA0 + ((_i) * 4))  /* Immediate INTR Ext*/ + +#define IGC_FTQF(_n)	(0x059E0 + (4 * (_n)))  /* 5-tuple Queue Fltr */ + +#define IGC_RXPBS	0x02404  /* Rx Packet Buffer Size - RW */ + +/* System Time Registers */ +#define IGC_SYSTIML	0x0B600  /* System time register Low - RO */ +#define IGC_SYSTIMH	0x0B604  /* System time register High - RO */ +#define IGC_SYSTIMR	0x0B6F8  /* System time register Residue */ +#define IGC_TIMINCA	0x0B608  /* Increment attributes register - RW */ + +#define IGC_RXSTMPL	0x0B624  /* Rx timestamp Low - RO */ +#define IGC_RXSTMPH	0x0B628  /* Rx timestamp High - RO */ +#define IGC_TXSTMPL	0x0B618  /* Tx timestamp value Low - RO */ +#define IGC_TXSTMPH	0x0B61C  /* Tx timestamp value High - RO */ +  /* Management registers */  #define IGC_MANC	0x05820  /* Management Control - RW */  /* Shadow Ram Write Register - RW */  #define IGC_SRWR	0x12018 +/* Wake Up registers */ +#define IGC_WUC		0x05800  /* Wakeup Control - RW */ +#define IGC_WUFC	0x05808  /* Wakeup Filter Control - RW */ +#define IGC_WUS		0x05810  /* Wakeup Status - R/W1C */ +#define IGC_WUPL	0x05900  /* Wakeup Packet Length - RW */ + +/* Wake Up packet memory */ +#define IGC_WUPM_REG(_i)	(0x05A00 + ((_i) * 4)) +  /* forward declaration */  struct igc_hw;  u32 igc_rd32(struct igc_hw *hw, u32 reg); | 
