diff --git a/target/linux/x86/patches-5.4/500-backport-igc-5.15-driver.patch b/target/linux/x86/patches-5.4/500-backport-igc-5.15-driver.patch new file mode 100644 index 000000000..d4075f8d1 --- /dev/null +++ b/target/linux/x86/patches-5.4/500-backport-igc-5.15-driver.patch @@ -0,0 +1,9353 @@ +--- a/drivers/net/ethernet/intel/igc/igc_base.c 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_base.c 2022-03-10 14:51:05.326870558 +0800 +@@ -26,7 +26,7 @@ + */ + ret_val = igc_disable_pcie_master(hw); + if (ret_val) +- hw_dbg("PCI-E Master disable polling has failed.\n"); ++ hw_dbg("PCI-E Master disable polling has failed\n"); + + hw_dbg("Masking off all interrupts\n"); + wr32(IGC_IMC, 0xffffffff); +@@ -40,7 +40,7 @@ + ctrl = rd32(IGC_CTRL); + + hw_dbg("Issuing a global reset to MAC\n"); +- wr32(IGC_CTRL, ctrl | IGC_CTRL_DEV_RST); ++ wr32(IGC_CTRL, ctrl | IGC_CTRL_RST); + + ret_val = igc_get_auto_rd_done(hw); + if (ret_val) { +@@ -158,11 +158,6 @@ + struct igc_phy_info *phy = &hw->phy; + s32 ret_val = 0; + +- if (hw->phy.media_type != igc_media_type_copper) { +- phy->type = igc_phy_none; +- goto out; +- } +- + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500; + phy->reset_delay_us = 100; + +@@ -177,7 +172,7 @@ + */ + ret_val = hw->phy.ops.reset(hw); + if (ret_val) { +- hw_dbg("Error resetting the PHY.\n"); ++ hw_dbg("Error resetting the PHY\n"); + goto out; + } + +@@ -187,15 +182,7 @@ + + igc_check_for_copper_link(hw); + +- /* Verify phy id and set remaining function pointers */ +- switch (phy->id) { +- case I225_I_PHY_ID: +- phy->type = igc_phy_i225; +- break; +- default: +- ret_val = -IGC_ERR_PHY; +- goto out; +- } ++ phy->type = igc_phy_i225; + + out: + return ret_val; +@@ -212,6 +199,17 @@ + case IGC_DEV_ID_I225_I: + case IGC_DEV_ID_I220_V: + case IGC_DEV_ID_I225_K: ++ case IGC_DEV_ID_I225_K2: ++ case IGC_DEV_ID_I226_K: ++ case IGC_DEV_ID_I225_LMVP: ++ case IGC_DEV_ID_I226_LMVP: ++ case IGC_DEV_ID_I225_IT: ++ case IGC_DEV_ID_I226_LM: ++ case IGC_DEV_ID_I226_V: ++ case IGC_DEV_ID_I226_IT: ++ case IGC_DEV_ID_I221_V: ++ case IGC_DEV_ID_I226_BLANK_NVM: ++ case IGC_DEV_ID_I225_BLANK_NVM: + mac->type = igc_i225; + break; + default: +@@ -363,7 +361,7 @@ + } + + if (ms_wait == 10) +- pr_debug("Queue disable timed out after 10ms\n"); ++ hw_dbg("Queue disable timed out after 10ms\n"); + + /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all + * incoming packets are rejected. Set enable and wait 2ms so that + +--- a/drivers/net/ethernet/intel/igc/igc_defines.h 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_defines.h 2022-03-10 14:48:43.638939361 +0800 +@@ -10,13 +10,43 @@ + + #define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */ + +-/* Physical Func Reset Done Indication */ +-#define IGC_CTRL_EXT_LINK_MODE_MASK 0x00C00000 ++/* 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_MAG 0x00000002 /* Magic Packet Wakeup Enable */ ++#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ ++#define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ ++#define IGC_WUFC_BC 0x00000010 /* Broadcast 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 + + /* Loop limit on how long we wait for auto-negotiation to complete */ + #define COPPER_LINK_UP_LIMIT 10 + #define PHY_AUTO_NEG_LIMIT 45 +-#define PHY_FORCE_LIMIT 20 + + /* Number of 100 microseconds we wait for PCI Express master disable */ + #define MASTER_DISABLE_TIMEOUT 800 +@@ -32,8 +62,14 @@ + * (RAR[15]) for our directed address used by controllers with + * manageability enabled, allowing us room for 15 multicast addresses. + */ ++#define IGC_RAH_RAH_MASK 0x0000FFFF ++#define IGC_RAH_ASEL_MASK 0x00030000 ++#define IGC_RAH_ASEL_SRC_ADDR BIT(16) ++#define IGC_RAH_QSEL_MASK 0x000C0000 ++#define IGC_RAH_QSEL_SHIFT 18 ++#define IGC_RAH_QSEL_ENABLE BIT(28) + #define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */ +-#define IGC_RAH_POOL_1 0x00040000 ++ + #define IGC_RAL_MAC_ADDR_LEN 4 + #define IGC_RAH_MAC_ADDR_LEN 2 + +@@ -50,7 +86,7 @@ + #define IGC_ERR_SWFW_SYNC 13 + + /* Device Control */ +-#define IGC_CTRL_DEV_RST 0x20000000 /* Device reset */ ++#define IGC_CTRL_RST 0x04000000 /* Global reset */ + + #define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + #define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +@@ -60,8 +96,6 @@ + #define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ + #define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ + +-#define IGC_CONNSW_AUTOSENSE_EN 0x1 +- + /* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */ + #define MAX_JUMBO_FRAME_SIZE 0x2600 + +@@ -132,11 +166,6 @@ + + /* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ + #define NVM_SUM 0xBABA +- +-#define NVM_PBA_OFFSET_0 8 +-#define NVM_PBA_OFFSET_1 9 +-#define NVM_RESERVED_WORD 0xFFFF +-#define NVM_PBA_PTR_GUARD 0xFAFA + #define NVM_WORD_SIZE_BASE_SHIFT 6 + + /* Collision related configuration parameters */ +@@ -187,6 +216,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 +239,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 */ +@@ -216,7 +247,6 @@ + /* Interrupt Cause Set */ + #define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */ + #define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */ +-#define IGC_ICS_DRSTA IGC_ICR_DRSTA /* Device Reset Aserted */ + + #define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */ + #define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */ +@@ -226,29 +256,28 @@ + #define IGC_GPIE_EIAME 0x40000000 + #define IGC_GPIE_PBA 0x80000000 + ++/* Receive Descriptor bit definitions */ ++#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */ ++ + /* Transmit Descriptor bit definitions */ + #define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */ + #define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */ + #define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ + #define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ + #define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */ +-#define IGC_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ + #define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +-#define IGC_TXD_CMD_RS 0x08000000 /* Report Status */ +-#define IGC_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ + #define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */ + #define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +-#define IGC_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ + #define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +-#define IGC_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +-#define IGC_TXD_STAT_LC 0x00000004 /* Late Collisions */ +-#define IGC_TXD_STAT_TU 0x00000008 /* Transmit underrun */ + #define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */ + #define IGC_TXD_CMD_IP 0x02000000 /* IP packet */ + #define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +-#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,25 +310,24 @@ + #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_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 */ + +-#define IGC_RXDEXT_STATERR_CE 0x01000000 +-#define IGC_RXDEXT_STATERR_SE 0x02000000 +-#define IGC_RXDEXT_STATERR_SEQ 0x04000000 +-#define IGC_RXDEXT_STATERR_CXE 0x10000000 +-#define IGC_RXDEXT_STATERR_TCPE 0x20000000 ++/* Advanced Receive Descriptor bit definitions */ ++#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */ ++ ++#define IGC_RXDEXT_STATERR_L4E 0x20000000 + #define IGC_RXDEXT_STATERR_IPE 0x40000000 + #define IGC_RXDEXT_STATERR_RXE 0x80000000 + +-/* Same mask, but for extended and packet split descriptors */ +-#define IGC_RXDEXT_ERR_FRAME_ERR_MASK ( \ +- IGC_RXDEXT_STATERR_CE | \ +- IGC_RXDEXT_STATERR_SE | \ +- IGC_RXDEXT_STATERR_SEQ | \ +- IGC_RXDEXT_STATERR_CXE | \ +- IGC_RXDEXT_STATERR_RXE) +- + #define IGC_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 + #define IGC_MRQC_RSS_FIELD_IPV4 0x00020000 + #define IGC_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 +@@ -320,6 +348,70 @@ + + #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 */ ++ ++#define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */ ++ ++#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */ ++#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */ ++ ++/* 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 ++ ++#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_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_TXTT_0 0x00000001 /* Tx timestamp reg 0 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 */ ++ ++/* Transmit Scheduling */ ++#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001 ++#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008 ++ ++#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001 ++#define IGC_TXQCTL_STRICT_CYCLE 0x00000002 ++#define IGC_TXQCTL_STRICT_END 0x00000004 + + /* Receive Checksum Control */ + #define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ +@@ -347,7 +439,6 @@ + #define IGC_GEN_POLL_TIMEOUT 1920 + + /* PHY Control Register */ +-#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ + #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ + #define MII_CR_POWER_DOWN 0x0800 /* Power down */ + #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +@@ -360,6 +451,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 */ +@@ -372,9 +464,6 @@ + #define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ + #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ + +-/* Bit definitions for valid PHY IDs. I = Integrated E = External */ +-#define I225_I_PHY_ID 0x67C9DC00 +- + /* MDI Control */ + #define IGC_MDIC_DATA_MASK 0x0000FFFF + #define IGC_MDIC_REG_MASK 0x001F0000 +@@ -386,20 +475,59 @@ + #define IGC_MDIC_READY 0x10000000 + #define IGC_MDIC_INT_EN 0x20000000 + #define IGC_MDIC_ERROR 0x40000000 +-#define IGC_MDIC_DEST 0x80000000 + + #define IGC_N0_QUEUE -1 + + #define IGC_MAX_MAC_HDR_LEN 127 + #define IGC_MAX_NETWORK_HDR_LEN 511 + +-#define IGC_VLAPQF_QUEUE_SEL(_n, q_idx) ((q_idx) << ((_n) * 4)) +-#define IGC_VLAPQF_P_VALID(_n) (0x1 << (3 + (_n) * 4)) +-#define IGC_VLAPQF_QUEUE_MASK 0x03 ++#define IGC_VLANPQF_QSEL(_n, q_idx) ((q_idx) << ((_n) * 4)) ++#define IGC_VLANPQF_VALID(_n) (0x1 << (3 + (_n) * 4)) ++#define IGC_VLANPQF_QUEUE_MASK 0x03 + + #define IGC_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ + #define IGC_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type:1=IPv4 */ + #define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */ + #define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */ + ++/* Maximum size of the MTA register table in all supported adapters */ ++#define MAX_MTA_REG 128 ++ ++/* EEE defines */ ++#define IGC_IPCNFG_EEE_2_5G_AN 0x00000010 /* IPCNFG EEE Ena 2.5G AN */ ++#define IGC_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */ ++#define IGC_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */ ++#define IGC_EEER_EEE_NEG 0x20000000 /* EEE capability nego */ ++#define IGC_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */ ++#define IGC_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */ ++#define IGC_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */ ++#define IGC_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */ ++ ++/* LTR defines */ ++#define IGC_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */ ++#define IGC_RXPBS_SIZE_I225_MASK 0x0000003F /* Rx packet buffer size */ ++#define IGC_TW_SYSTEM_1000_MASK 0x000000FF ++/* Minimum time for 100BASE-T where no data will be transmit following move out ++ * of EEE LPI Tx state ++ */ ++#define IGC_TW_SYSTEM_100_MASK 0x0000FF00 ++#define IGC_TW_SYSTEM_100_SHIFT 8 ++#define IGC_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */ ++#define IGC_DMACR_DMACTHR_MASK 0x00FF0000 ++#define IGC_DMACR_DMACTHR_SHIFT 16 ++/* Reg val to set scale to 1024 nsec */ ++#define IGC_LTRMINV_SCALE_1024 2 ++/* Reg val to set scale to 32768 nsec */ ++#define IGC_LTRMINV_SCALE_32768 3 ++/* Reg val to set scale to 1024 nsec */ ++#define IGC_LTRMAXV_SCALE_1024 2 ++/* Reg val to set scale to 32768 nsec */ ++#define IGC_LTRMAXV_SCALE_32768 3 ++#define IGC_LTRMINV_LTRV_MASK 0x000003FF /* LTR minimum value */ ++#define IGC_LTRMAXV_LTRV_MASK 0x000003FF /* LTR maximum value */ ++#define IGC_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */ ++#define IGC_LTRMINV_SCALE_SHIFT 10 ++#define IGC_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */ ++#define IGC_LTRMAXV_SCALE_SHIFT 10 ++ + #endif /* _IGC_DEFINES_H_ */ + +--- a/drivers/net/ethernet/intel/igc/igc_diag.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_diag.c 2022-03-10 14:33:17.223213194 +0800 +@@ -0,0 +1,186 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (c) 2020 Intel Corporation */ ++ ++#include "igc.h" ++#include "igc_diag.h" ++ ++static struct igc_reg_test reg_test[] = { ++ { IGC_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, ++ { IGC_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, ++ { IGC_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, ++ { IGC_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, ++ { IGC_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, ++ { IGC_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, ++ { IGC_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, ++ { IGC_FCRTH, 1, PATTERN_TEST, 0x0003FFF0, 0x0003FFF0 }, ++ { IGC_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, ++ { IGC_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, ++ { IGC_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, ++ { IGC_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, ++ { IGC_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, ++ { IGC_TDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, ++ { IGC_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, ++ { IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0x003FFFFB }, ++ { IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0xFFFFFFFF }, ++ { IGC_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, ++ { IGC_RA, 16, TABLE64_TEST_LO, ++ 0xFFFFFFFF, 0xFFFFFFFF }, ++ { IGC_RA, 16, TABLE64_TEST_HI, ++ 0x900FFFFF, 0xFFFFFFFF }, ++ { IGC_MTA, 128, TABLE32_TEST, ++ 0xFFFFFFFF, 0xFFFFFFFF }, ++ { 0, 0, 0, 0} ++}; ++ ++static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg, ++ u32 mask, u32 write) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 pat, val, before; ++ static const u32 test_pattern[] = { ++ 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF ++ }; ++ ++ for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) { ++ before = rd32(reg); ++ wr32(reg, test_pattern[pat] & write); ++ val = rd32(reg); ++ if (val != (test_pattern[pat] & write & mask)) { ++ netdev_err(adapter->netdev, ++ "pattern test reg %04X failed: got 0x%08X expected 0x%08X", ++ reg, val, test_pattern[pat] & write & mask); ++ *data = reg; ++ wr32(reg, before); ++ return false; ++ } ++ wr32(reg, before); ++ } ++ return true; ++} ++ ++static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg, ++ u32 mask, u32 write) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 val, before; ++ ++ before = rd32(reg); ++ wr32(reg, write & mask); ++ val = rd32(reg); ++ if ((write & mask) != (val & mask)) { ++ netdev_err(adapter->netdev, ++ "set/check reg %04X test failed: got 0x%08X expected 0x%08X", ++ reg, (val & mask), (write & mask)); ++ *data = reg; ++ wr32(reg, before); ++ return false; ++ } ++ wr32(reg, before); ++ return true; ++} ++ ++bool igc_reg_test(struct igc_adapter *adapter, u64 *data) ++{ ++ struct igc_reg_test *test = reg_test; ++ struct igc_hw *hw = &adapter->hw; ++ u32 value, before, after; ++ u32 i, toggle, b = false; ++ ++ /* Because the status register is such a special case, ++ * we handle it separately from the rest of the register ++ * tests. Some bits are read-only, some toggle, and some ++ * are writeable. ++ */ ++ toggle = 0x6800D3; ++ before = rd32(IGC_STATUS); ++ value = before & toggle; ++ wr32(IGC_STATUS, toggle); ++ after = rd32(IGC_STATUS) & toggle; ++ if (value != after) { ++ netdev_err(adapter->netdev, ++ "failed STATUS register test got: 0x%08X expected: 0x%08X", ++ after, value); ++ *data = 1; ++ return false; ++ } ++ /* restore previous status */ ++ wr32(IGC_STATUS, before); ++ ++ /* Perform the remainder of the register test, looping through ++ * the test table until we either fail or reach the null entry. ++ */ ++ while (test->reg) { ++ for (i = 0; i < test->array_len; i++) { ++ switch (test->test_type) { ++ case PATTERN_TEST: ++ b = reg_pattern_test(adapter, data, ++ test->reg + (i * 0x40), ++ test->mask, ++ test->write); ++ break; ++ case SET_READ_TEST: ++ b = reg_set_and_check(adapter, data, ++ test->reg + (i * 0x40), ++ test->mask, ++ test->write); ++ break; ++ case TABLE64_TEST_LO: ++ b = reg_pattern_test(adapter, data, ++ test->reg + (i * 8), ++ test->mask, ++ test->write); ++ break; ++ case TABLE64_TEST_HI: ++ b = reg_pattern_test(adapter, data, ++ test->reg + 4 + (i * 8), ++ test->mask, ++ test->write); ++ break; ++ case TABLE32_TEST: ++ b = reg_pattern_test(adapter, data, ++ test->reg + (i * 4), ++ test->mask, ++ test->write); ++ break; ++ } ++ if (!b) ++ return false; ++ } ++ test++; ++ } ++ *data = 0; ++ return true; ++} ++ ++bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ ++ *data = 0; ++ ++ if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) { ++ *data = 1; ++ return false; ++ } ++ ++ return true; ++} ++ ++bool igc_link_test(struct igc_adapter *adapter, u64 *data) ++{ ++ bool link_up; ++ ++ *data = 0; ++ ++ /* add delay to give enough time for autonegotioation to finish */ ++ if (adapter->hw.mac.autoneg) ++ ssleep(5); ++ ++ link_up = igc_has_link(adapter); ++ if (!link_up) { ++ *data = 1; ++ return false; ++ } ++ ++ return true; ++} + +--- a/drivers/net/ethernet/intel/igc/igc_diag.h 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_diag.h 2022-03-10 14:33:17.223213194 +0800 +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2020 Intel Corporation */ ++ ++bool igc_reg_test(struct igc_adapter *adapter, u64 *data); ++bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data); ++bool igc_link_test(struct igc_adapter *adapter, u64 *data); ++ ++struct igc_reg_test { ++ u16 reg; ++ u8 array_len; ++ u8 test_type; ++ u32 mask; ++ u32 write; ++}; ++ ++/* In the hardware, registers are laid out either singly, in arrays ++ * spaced 0x40 bytes apart, or in contiguous tables. We assume ++ * most tests take place on arrays or single registers (handled ++ * as a single-element array) and special-case the tables. ++ * Table tests are always pattern tests. ++ * ++ * We also make provision for some required setup steps by specifying ++ * registers to be written without any read-back testing. ++ */ ++ ++#define PATTERN_TEST 1 ++#define SET_READ_TEST 2 ++#define TABLE32_TEST 3 ++#define TABLE64_TEST_LO 4 ++#define TABLE64_TEST_HI 5 + +--- a/drivers/net/ethernet/intel/igc/igc_dump.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_dump.c 2022-03-10 14:33:17.223213194 +0800 +@@ -0,0 +1,318 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (c) 2018 Intel Corporation */ ++ ++#include "igc.h" ++ ++struct igc_reg_info { ++ u32 ofs; ++ char *name; ++}; ++ ++static const struct igc_reg_info igc_reg_info_tbl[] = { ++ /* General Registers */ ++ {IGC_CTRL, "CTRL"}, ++ {IGC_STATUS, "STATUS"}, ++ {IGC_CTRL_EXT, "CTRL_EXT"}, ++ {IGC_MDIC, "MDIC"}, ++ ++ /* Interrupt Registers */ ++ {IGC_ICR, "ICR"}, ++ ++ /* RX Registers */ ++ {IGC_RCTL, "RCTL"}, ++ {IGC_RDLEN(0), "RDLEN"}, ++ {IGC_RDH(0), "RDH"}, ++ {IGC_RDT(0), "RDT"}, ++ {IGC_RXDCTL(0), "RXDCTL"}, ++ {IGC_RDBAL(0), "RDBAL"}, ++ {IGC_RDBAH(0), "RDBAH"}, ++ ++ /* TX Registers */ ++ {IGC_TCTL, "TCTL"}, ++ {IGC_TDBAL(0), "TDBAL"}, ++ {IGC_TDBAH(0), "TDBAH"}, ++ {IGC_TDLEN(0), "TDLEN"}, ++ {IGC_TDH(0), "TDH"}, ++ {IGC_TDT(0), "TDT"}, ++ {IGC_TXDCTL(0), "TXDCTL"}, ++ ++ /* List Terminator */ ++ {} ++}; ++ ++/* igc_regdump - register printout routine */ ++static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo) ++{ ++ struct net_device *dev = igc_get_hw_dev(hw); ++ int n = 0; ++ char rname[16]; ++ u32 regs[8]; ++ ++ switch (reginfo->ofs) { ++ case IGC_RDLEN(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RDLEN(n)); ++ break; ++ case IGC_RDH(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RDH(n)); ++ break; ++ case IGC_RDT(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RDT(n)); ++ break; ++ case IGC_RXDCTL(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RXDCTL(n)); ++ break; ++ case IGC_RDBAL(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RDBAL(n)); ++ break; ++ case IGC_RDBAH(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RDBAH(n)); ++ break; ++ case IGC_TDBAL(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_RDBAL(n)); ++ break; ++ case IGC_TDBAH(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_TDBAH(n)); ++ break; ++ case IGC_TDLEN(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_TDLEN(n)); ++ break; ++ case IGC_TDH(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_TDH(n)); ++ break; ++ case IGC_TDT(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_TDT(n)); ++ break; ++ case IGC_TXDCTL(0): ++ for (n = 0; n < 4; n++) ++ regs[n] = rd32(IGC_TXDCTL(n)); ++ break; ++ default: ++ netdev_info(dev, "%-15s %08x\n", reginfo->name, ++ rd32(reginfo->ofs)); ++ return; ++ } ++ ++ snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]"); ++ netdev_info(dev, "%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1], ++ regs[2], regs[3]); ++} ++ ++/* igc_rings_dump - Tx-rings and Rx-rings */ ++void igc_rings_dump(struct igc_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct my_u0 { u64 a; u64 b; } *u0; ++ union igc_adv_tx_desc *tx_desc; ++ union igc_adv_rx_desc *rx_desc; ++ struct igc_ring *tx_ring; ++ struct igc_ring *rx_ring; ++ u32 staterr; ++ u16 i, n; ++ ++ if (!netif_msg_hw(adapter)) ++ return; ++ ++ netdev_info(netdev, "Device info: state %016lX trans_start %016lX\n", ++ netdev->state, dev_trans_start(netdev)); ++ ++ /* Print TX Ring Summary */ ++ if (!netif_running(netdev)) ++ goto exit; ++ ++ netdev_info(netdev, "TX Rings Summary\n"); ++ netdev_info(netdev, "Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n"); ++ for (n = 0; n < adapter->num_tx_queues; n++) { ++ struct igc_tx_buffer *buffer_info; ++ ++ tx_ring = adapter->tx_ring[n]; ++ buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean]; ++ ++ netdev_info(netdev, "%5d %5X %5X %016llX %04X %p %016llX\n", ++ n, tx_ring->next_to_use, tx_ring->next_to_clean, ++ (u64)dma_unmap_addr(buffer_info, dma), ++ dma_unmap_len(buffer_info, len), ++ buffer_info->next_to_watch, ++ (u64)buffer_info->time_stamp); ++ } ++ ++ /* Print TX Rings */ ++ if (!netif_msg_tx_done(adapter)) ++ goto rx_ring_summary; ++ ++ netdev_info(netdev, "TX Rings Dump\n"); ++ ++ /* Transmit Descriptor Formats ++ * ++ * Advanced Transmit Descriptor ++ * +--------------------------------------------------------------+ ++ * 0 | Buffer Address [63:0] | ++ * +--------------------------------------------------------------+ ++ * 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN | ++ * +--------------------------------------------------------------+ ++ * 63 46 45 40 39 38 36 35 32 31 24 15 0 ++ */ ++ ++ for (n = 0; n < adapter->num_tx_queues; n++) { ++ tx_ring = adapter->tx_ring[n]; ++ netdev_info(netdev, "------------------------------------\n"); ++ netdev_info(netdev, "TX QUEUE INDEX = %d\n", ++ tx_ring->queue_index); ++ netdev_info(netdev, "------------------------------------\n"); ++ netdev_info(netdev, "T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n"); ++ ++ for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) { ++ const char *next_desc; ++ struct igc_tx_buffer *buffer_info; ++ ++ tx_desc = IGC_TX_DESC(tx_ring, i); ++ buffer_info = &tx_ring->tx_buffer_info[i]; ++ u0 = (struct my_u0 *)tx_desc; ++ if (i == tx_ring->next_to_use && ++ i == tx_ring->next_to_clean) ++ next_desc = " NTC/U"; ++ else if (i == tx_ring->next_to_use) ++ next_desc = " NTU"; ++ else if (i == tx_ring->next_to_clean) ++ next_desc = " NTC"; ++ else ++ next_desc = ""; ++ ++ netdev_info(netdev, "T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n", ++ i, le64_to_cpu(u0->a), ++ le64_to_cpu(u0->b), ++ (u64)dma_unmap_addr(buffer_info, dma), ++ dma_unmap_len(buffer_info, len), ++ buffer_info->next_to_watch, ++ (u64)buffer_info->time_stamp, ++ buffer_info->skb, next_desc); ++ ++ if (netif_msg_pktdata(adapter) && buffer_info->skb) ++ print_hex_dump(KERN_INFO, "", ++ DUMP_PREFIX_ADDRESS, ++ 16, 1, buffer_info->skb->data, ++ dma_unmap_len(buffer_info, len), ++ true); ++ } ++ } ++ ++ /* Print RX Rings Summary */ ++rx_ring_summary: ++ netdev_info(netdev, "RX Rings Summary\n"); ++ netdev_info(netdev, "Queue [NTU] [NTC]\n"); ++ for (n = 0; n < adapter->num_rx_queues; n++) { ++ rx_ring = adapter->rx_ring[n]; ++ netdev_info(netdev, "%5d %5X %5X\n", n, rx_ring->next_to_use, ++ rx_ring->next_to_clean); ++ } ++ ++ /* Print RX Rings */ ++ if (!netif_msg_rx_status(adapter)) ++ goto exit; ++ ++ netdev_info(netdev, "RX Rings Dump\n"); ++ ++ /* Advanced Receive Descriptor (Read) Format ++ * 63 1 0 ++ * +-----------------------------------------------------+ ++ * 0 | Packet Buffer Address [63:1] |A0/NSE| ++ * +----------------------------------------------+------+ ++ * 8 | Header Buffer Address [63:1] | DD | ++ * +-----------------------------------------------------+ ++ * ++ * ++ * Advanced Receive Descriptor (Write-Back) Format ++ * ++ * 63 48 47 32 31 30 21 20 17 16 4 3 0 ++ * +------------------------------------------------------+ ++ * 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS | ++ * | Checksum Ident | | | | Type | Type | ++ * +------------------------------------------------------+ ++ * 8 | VLAN Tag | Length | Extended Error | Extended Status | ++ * +------------------------------------------------------+ ++ * 63 48 47 32 31 20 19 0 ++ */ ++ ++ for (n = 0; n < adapter->num_rx_queues; n++) { ++ rx_ring = adapter->rx_ring[n]; ++ netdev_info(netdev, "------------------------------------\n"); ++ netdev_info(netdev, "RX QUEUE INDEX = %d\n", ++ rx_ring->queue_index); ++ netdev_info(netdev, "------------------------------------\n"); ++ netdev_info(netdev, "R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n"); ++ netdev_info(netdev, "RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n"); ++ ++ for (i = 0; i < rx_ring->count; i++) { ++ const char *next_desc; ++ struct igc_rx_buffer *buffer_info; ++ ++ buffer_info = &rx_ring->rx_buffer_info[i]; ++ rx_desc = IGC_RX_DESC(rx_ring, i); ++ u0 = (struct my_u0 *)rx_desc; ++ staterr = le32_to_cpu(rx_desc->wb.upper.status_error); ++ ++ if (i == rx_ring->next_to_use) ++ next_desc = " NTU"; ++ else if (i == rx_ring->next_to_clean) ++ next_desc = " NTC"; ++ else ++ next_desc = ""; ++ ++ if (staterr & IGC_RXD_STAT_DD) { ++ /* Descriptor Done */ ++ netdev_info(netdev, "%s[0x%03X] %016llX %016llX ---------------- %s\n", ++ "RWB", i, ++ le64_to_cpu(u0->a), ++ le64_to_cpu(u0->b), ++ next_desc); ++ } else { ++ netdev_info(netdev, "%s[0x%03X] %016llX %016llX %016llX %s\n", ++ "R ", i, ++ le64_to_cpu(u0->a), ++ le64_to_cpu(u0->b), ++ (u64)buffer_info->dma, ++ next_desc); ++ ++ if (netif_msg_pktdata(adapter) && ++ buffer_info->dma && buffer_info->page) { ++ print_hex_dump(KERN_INFO, "", ++ DUMP_PREFIX_ADDRESS, ++ 16, 1, ++ page_address ++ (buffer_info->page) + ++ buffer_info->page_offset, ++ igc_rx_bufsz(rx_ring), ++ true); ++ } ++ } ++ } ++ } ++ ++exit: ++ return; ++} ++ ++/* igc_regs_dump - registers dump */ ++void igc_regs_dump(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ struct igc_reg_info *reginfo; ++ ++ /* Print Registers */ ++ netdev_info(adapter->netdev, "Register Dump\n"); ++ netdev_info(adapter->netdev, "Register Name Value\n"); ++ for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl; ++ reginfo->name; reginfo++) { ++ igc_regdump(hw, reginfo); ++ } ++} + +--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c 2022-03-10 14:33:17.223213194 +0800 +@@ -4,8 +4,10 @@ + /* ethtool support for igc */ + #include + #include ++#include + + #include "igc.h" ++#include "igc_diag.h" + + /* forward declaration */ + struct igc_stats { +@@ -16,7 +18,7 @@ + + #define IGC_STAT(_name, _stat) { \ + .stat_string = _name, \ +- .sizeof_stat = FIELD_SIZEOF(struct igc_adapter, _stat), \ ++ .sizeof_stat = sizeof_field(struct igc_adapter, _stat), \ + .stat_offset = offsetof(struct igc_adapter, _stat) \ + } + +@@ -67,7 +69,7 @@ + + #define IGC_NETDEV_STAT(_net_stat) { \ + .stat_string = __stringify(_net_stat), \ +- .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \ ++ .sizeof_stat = sizeof_field(struct rtnl_link_stats64, _net_stat), \ + .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ + } + +@@ -123,13 +125,12 @@ + + #define IGC_PRIV_FLAGS_STR_LEN ARRAY_SIZE(igc_priv_flags_strings) + +-static void igc_get_drvinfo(struct net_device *netdev, +- struct ethtool_drvinfo *drvinfo) ++static void igc_ethtool_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) + { + struct igc_adapter *adapter = netdev_priv(netdev); + + strlcpy(drvinfo->driver, igc_driver_name, sizeof(drvinfo->driver)); +- strlcpy(drvinfo->version, igc_driver_version, sizeof(drvinfo->version)); + + /* add fw_version here */ + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), +@@ -138,13 +139,13 @@ + drvinfo->n_priv_flags = IGC_PRIV_FLAGS_STR_LEN; + } + +-static int igc_get_regs_len(struct net_device *netdev) ++static int igc_ethtool_get_regs_len(struct net_device *netdev) + { + return IGC_REGS_LEN * sizeof(u32); + } + +-static void igc_get_regs(struct net_device *netdev, +- struct ethtool_regs *regs, void *p) ++static void igc_ethtool_get_regs(struct net_device *netdev, ++ struct ethtool_regs *regs, void *p) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; +@@ -153,7 +154,7 @@ + + memset(p, 0, IGC_REGS_LEN * sizeof(u32)); + +- regs->version = (1u << 24) | (hw->revision_id << 16) | hw->device_id; ++ regs->version = (2u << 24) | (hw->revision_id << 16) | hw->device_id; + + /* General Registers */ + regs_buff[0] = rd32(IGC_CTRL); +@@ -306,23 +307,101 @@ + regs_buff[164 + i] = rd32(IGC_TDT(i)); + for (i = 0; i < 4; i++) + regs_buff[168 + i] = rd32(IGC_TXDCTL(i)); ++ ++ /* XXX: Due to a bug few lines above, RAL and RAH registers are ++ * overwritten. To preserve the ABI, we write these registers again in ++ * regs_buff. ++ */ ++ for (i = 0; i < 16; i++) ++ regs_buff[172 + i] = rd32(IGC_RAL(i)); ++ for (i = 0; i < 16; i++) ++ regs_buff[188 + i] = rd32(IGC_RAH(i)); ++ ++ regs_buff[204] = rd32(IGC_VLANPQF); ++ ++ for (i = 0; i < 8; i++) ++ regs_buff[205 + i] = rd32(IGC_ETQF(i)); ++ ++ regs_buff[213] = adapter->stats.tlpic; ++ regs_buff[214] = adapter->stats.rlpic; ++} ++ ++static void igc_ethtool_get_wol(struct net_device *netdev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ ++ wol->wolopts = 0; ++ ++ if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) ++ return; ++ ++ wol->supported = WAKE_UCAST | WAKE_MCAST | ++ WAKE_BCAST | WAKE_MAGIC | ++ WAKE_PHY; ++ ++ /* apply any specific unsupported masks here */ ++ switch (adapter->hw.device_id) { ++ default: ++ break; ++ } ++ ++ if (adapter->wol & IGC_WUFC_EX) ++ wol->wolopts |= WAKE_UCAST; ++ if (adapter->wol & IGC_WUFC_MC) ++ wol->wolopts |= WAKE_MCAST; ++ if (adapter->wol & IGC_WUFC_BC) ++ wol->wolopts |= WAKE_BCAST; ++ if (adapter->wol & IGC_WUFC_MAG) ++ wol->wolopts |= WAKE_MAGIC; ++ if (adapter->wol & IGC_WUFC_LNKC) ++ wol->wolopts |= WAKE_PHY; ++} ++ ++static int igc_ethtool_set_wol(struct net_device *netdev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ ++ if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER)) ++ return -EOPNOTSUPP; ++ ++ if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) ++ return wol->wolopts ? -EOPNOTSUPP : 0; ++ ++ /* these settings will always override what we currently have */ ++ adapter->wol = 0; ++ ++ if (wol->wolopts & WAKE_UCAST) ++ adapter->wol |= IGC_WUFC_EX; ++ if (wol->wolopts & WAKE_MCAST) ++ adapter->wol |= IGC_WUFC_MC; ++ if (wol->wolopts & WAKE_BCAST) ++ adapter->wol |= IGC_WUFC_BC; ++ if (wol->wolopts & WAKE_MAGIC) ++ adapter->wol |= IGC_WUFC_MAG; ++ if (wol->wolopts & WAKE_PHY) ++ adapter->wol |= IGC_WUFC_LNKC; ++ device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); ++ ++ return 0; + } + +-static u32 igc_get_msglevel(struct net_device *netdev) ++static u32 igc_ethtool_get_msglevel(struct net_device *netdev) + { + struct igc_adapter *adapter = netdev_priv(netdev); + + return adapter->msg_enable; + } + +-static void igc_set_msglevel(struct net_device *netdev, u32 data) ++static void igc_ethtool_set_msglevel(struct net_device *netdev, u32 data) + { + struct igc_adapter *adapter = netdev_priv(netdev); + + adapter->msg_enable = data; + } + +-static int igc_nway_reset(struct net_device *netdev) ++static int igc_ethtool_nway_reset(struct net_device *netdev) + { + struct igc_adapter *adapter = netdev_priv(netdev); + +@@ -331,7 +410,7 @@ + return 0; + } + +-static u32 igc_get_link(struct net_device *netdev) ++static u32 igc_ethtool_get_link(struct net_device *netdev) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_mac_info *mac = &adapter->hw.mac; +@@ -348,15 +427,15 @@ + return igc_has_link(adapter); + } + +-static int igc_get_eeprom_len(struct net_device *netdev) ++static int igc_ethtool_get_eeprom_len(struct net_device *netdev) + { + struct igc_adapter *adapter = netdev_priv(netdev); + + return adapter->hw.nvm.word_size * 2; + } + +-static int igc_get_eeprom(struct net_device *netdev, +- struct ethtool_eeprom *eeprom, u8 *bytes) ++static int igc_ethtool_get_eeprom(struct net_device *netdev, ++ struct ethtool_eeprom *eeprom, u8 *bytes) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; +@@ -402,8 +481,8 @@ + return ret_val; + } + +-static int igc_set_eeprom(struct net_device *netdev, +- struct ethtool_eeprom *eeprom, u8 *bytes) ++static int igc_ethtool_set_eeprom(struct net_device *netdev, ++ struct ethtool_eeprom *eeprom, u8 *bytes) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; +@@ -470,8 +549,8 @@ + return ret_val; + } + +-static void igc_get_ringparam(struct net_device *netdev, +- struct ethtool_ringparam *ring) ++static void igc_ethtool_get_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) + { + struct igc_adapter *adapter = netdev_priv(netdev); + +@@ -481,8 +560,8 @@ + ring->tx_pending = adapter->tx_ring_count; + } + +-static int igc_set_ringparam(struct net_device *netdev, +- struct ethtool_ringparam *ring) ++static int igc_ethtool_set_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_ring *temp_ring; +@@ -596,8 +675,8 @@ + return err; + } + +-static void igc_get_pauseparam(struct net_device *netdev, +- struct ethtool_pauseparam *pause) ++static void igc_ethtool_get_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; +@@ -615,8 +694,8 @@ + } + } + +-static int igc_set_pauseparam(struct net_device *netdev, +- struct ethtool_pauseparam *pause) ++static int igc_ethtool_set_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; +@@ -655,7 +734,8 @@ + return retval; + } + +-static void igc_get_strings(struct net_device *netdev, u32 stringset, u8 *data) ++static void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset, ++ u8 *data) + { + struct igc_adapter *adapter = netdev_priv(netdev); + u8 *p = data; +@@ -706,7 +786,7 @@ + } + } + +-static int igc_get_sset_count(struct net_device *netdev, int sset) ++static int igc_ethtool_get_sset_count(struct net_device *netdev, int sset) + { + switch (sset) { + case ETH_SS_STATS: +@@ -720,7 +800,7 @@ + } + } + +-static void igc_get_ethtool_stats(struct net_device *netdev, ++static void igc_ethtool_get_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) + { + struct igc_adapter *adapter = netdev_priv(netdev); +@@ -776,8 +856,8 @@ + spin_unlock(&adapter->stats64_lock); + } + +-static int igc_get_coalesce(struct net_device *netdev, +- struct ethtool_coalesce *ec) ++static int igc_ethtool_get_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) + { + struct igc_adapter *adapter = netdev_priv(netdev); + +@@ -796,33 +876,12 @@ + return 0; + } + +-static int igc_set_coalesce(struct net_device *netdev, +- struct ethtool_coalesce *ec) ++static int igc_ethtool_set_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) + { + struct igc_adapter *adapter = netdev_priv(netdev); + int i; + +- if (ec->rx_max_coalesced_frames || +- ec->rx_coalesce_usecs_irq || +- ec->rx_max_coalesced_frames_irq || +- ec->tx_max_coalesced_frames || +- ec->tx_coalesce_usecs_irq || +- ec->stats_block_coalesce_usecs || +- ec->use_adaptive_rx_coalesce || +- ec->use_adaptive_tx_coalesce || +- ec->pkt_rate_low || +- ec->rx_coalesce_usecs_low || +- ec->rx_max_coalesced_frames_low || +- ec->tx_coalesce_usecs_low || +- ec->tx_max_coalesced_frames_low || +- ec->pkt_rate_high || +- ec->rx_coalesce_usecs_high || +- ec->rx_max_coalesced_frames_high || +- ec->tx_coalesce_usecs_high || +- ec->tx_max_coalesced_frames_high || +- ec->rate_sample_interval) +- return -ENOTSUPP; +- + if (ec->rx_coalesce_usecs > IGC_MAX_ITR_USECS || + (ec->rx_coalesce_usecs > 3 && + ec->rx_coalesce_usecs < IGC_MIN_ITR_USECS) || +@@ -875,81 +934,83 @@ + } + + #define ETHER_TYPE_FULL_MASK ((__force __be16)~0) +-static int igc_get_ethtool_nfc_entry(struct igc_adapter *adapter, +- struct ethtool_rxnfc *cmd) ++static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, ++ struct ethtool_rxnfc *cmd) + { + struct ethtool_rx_flow_spec *fsp = &cmd->fs; +- struct igc_nfc_filter *rule = NULL; ++ struct igc_nfc_rule *rule = NULL; + +- /* report total rule count */ +- cmd->data = IGC_MAX_RXNFC_FILTERS; ++ cmd->data = IGC_MAX_RXNFC_RULES; + +- hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { +- if (fsp->location <= rule->sw_idx) +- break; ++ mutex_lock(&adapter->nfc_rule_lock); ++ ++ rule = igc_get_nfc_rule(adapter, fsp->location); ++ if (!rule) ++ goto out; ++ ++ fsp->flow_type = ETHER_FLOW; ++ fsp->ring_cookie = rule->action; ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { ++ fsp->h_u.ether_spec.h_proto = htons(rule->filter.etype); ++ fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK; + } + +- if (!rule || fsp->location != rule->sw_idx) +- return -EINVAL; ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { ++ fsp->flow_type |= FLOW_EXT; ++ fsp->h_ext.vlan_tci = htons(rule->filter.vlan_tci); ++ fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK); ++ } + +- if (rule->filter.match_flags) { +- fsp->flow_type = ETHER_FLOW; +- fsp->ring_cookie = rule->action; +- if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { +- fsp->h_u.ether_spec.h_proto = rule->filter.etype; +- fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK; +- } +- if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { +- fsp->flow_type |= FLOW_EXT; +- fsp->h_ext.vlan_tci = rule->filter.vlan_tci; +- fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK); +- } +- if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { +- ether_addr_copy(fsp->h_u.ether_spec.h_dest, +- rule->filter.dst_addr); +- /* As we only support matching by the full +- * mask, return the mask to userspace +- */ +- eth_broadcast_addr(fsp->m_u.ether_spec.h_dest); +- } +- if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { +- ether_addr_copy(fsp->h_u.ether_spec.h_source, +- rule->filter.src_addr); +- /* As we only support matching by the full +- * mask, return the mask to userspace +- */ +- eth_broadcast_addr(fsp->m_u.ether_spec.h_source); +- } ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { ++ ether_addr_copy(fsp->h_u.ether_spec.h_dest, ++ rule->filter.dst_addr); ++ eth_broadcast_addr(fsp->m_u.ether_spec.h_dest); ++ } + +- return 0; ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { ++ ether_addr_copy(fsp->h_u.ether_spec.h_source, ++ rule->filter.src_addr); ++ eth_broadcast_addr(fsp->m_u.ether_spec.h_source); + } ++ ++ mutex_unlock(&adapter->nfc_rule_lock); ++ return 0; ++ ++out: ++ mutex_unlock(&adapter->nfc_rule_lock); + return -EINVAL; + } + +-static int igc_get_ethtool_nfc_all(struct igc_adapter *adapter, +- struct ethtool_rxnfc *cmd, +- u32 *rule_locs) ++static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, ++ struct ethtool_rxnfc *cmd, ++ u32 *rule_locs) + { +- struct igc_nfc_filter *rule; ++ struct igc_nfc_rule *rule; + int cnt = 0; + +- /* report total rule count */ +- cmd->data = IGC_MAX_RXNFC_FILTERS; ++ cmd->data = IGC_MAX_RXNFC_RULES; ++ ++ mutex_lock(&adapter->nfc_rule_lock); + +- hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { +- if (cnt == cmd->rule_cnt) ++ list_for_each_entry(rule, &adapter->nfc_rule_list, list) { ++ if (cnt == cmd->rule_cnt) { ++ mutex_unlock(&adapter->nfc_rule_lock); + return -EMSGSIZE; +- rule_locs[cnt] = rule->sw_idx; ++ } ++ rule_locs[cnt] = rule->location; + cnt++; + } + ++ mutex_unlock(&adapter->nfc_rule_lock); ++ + cmd->rule_cnt = cnt; + + return 0; + } + +-static int igc_get_rss_hash_opts(struct igc_adapter *adapter, +- struct ethtool_rxnfc *cmd) ++static int igc_ethtool_get_rss_hash_opts(struct igc_adapter *adapter, ++ struct ethtool_rxnfc *cmd) + { + cmd->data = 0; + +@@ -957,37 +1018,29 @@ + switch (cmd->flow_type) { + case TCP_V4_FLOW: + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +- /* Fall through */ ++ fallthrough; + case UDP_V4_FLOW: + if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +- /* Fall through */ ++ fallthrough; + case SCTP_V4_FLOW: +- /* Fall through */ + case AH_ESP_V4_FLOW: +- /* Fall through */ + case AH_V4_FLOW: +- /* Fall through */ + case ESP_V4_FLOW: +- /* Fall through */ + case IPV4_FLOW: + cmd->data |= RXH_IP_SRC | RXH_IP_DST; + break; + case TCP_V6_FLOW: + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +- /* Fall through */ ++ fallthrough; + case UDP_V6_FLOW: + if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +- /* Fall through */ ++ fallthrough; + case SCTP_V6_FLOW: +- /* Fall through */ + case AH_ESP_V6_FLOW: +- /* Fall through */ + case AH_V6_FLOW: +- /* Fall through */ + case ESP_V6_FLOW: +- /* Fall through */ + case IPV6_FLOW: + cmd->data |= RXH_IP_SRC | RXH_IP_DST; + break; +@@ -998,41 +1051,33 @@ + return 0; + } + +-static int igc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, +- u32 *rule_locs) ++static int igc_ethtool_get_rxnfc(struct net_device *dev, ++ struct ethtool_rxnfc *cmd, u32 *rule_locs) + { + struct igc_adapter *adapter = netdev_priv(dev); +- int ret = -EOPNOTSUPP; + + switch (cmd->cmd) { + case ETHTOOL_GRXRINGS: + cmd->data = adapter->num_rx_queues; +- ret = 0; +- break; ++ return 0; + case ETHTOOL_GRXCLSRLCNT: +- cmd->rule_cnt = adapter->nfc_filter_count; +- ret = 0; +- break; ++ cmd->rule_cnt = adapter->nfc_rule_count; ++ return 0; + case ETHTOOL_GRXCLSRULE: +- ret = igc_get_ethtool_nfc_entry(adapter, cmd); +- break; ++ return igc_ethtool_get_nfc_rule(adapter, cmd); + case ETHTOOL_GRXCLSRLALL: +- ret = igc_get_ethtool_nfc_all(adapter, cmd, rule_locs); +- break; ++ return igc_ethtool_get_nfc_rules(adapter, cmd, rule_locs); + case ETHTOOL_GRXFH: +- ret = igc_get_rss_hash_opts(adapter, cmd); +- break; ++ return igc_ethtool_get_rss_hash_opts(adapter, cmd); + default: +- break; ++ return -EOPNOTSUPP; + } +- +- return ret; + } + + #define UDP_RSS_FLAGS (IGC_FLAG_RSS_FIELD_IPV4_UDP | \ + IGC_FLAG_RSS_FIELD_IPV6_UDP) +-static int igc_set_rss_hash_opt(struct igc_adapter *adapter, +- struct ethtool_rxnfc *nfc) ++static int igc_ethtool_set_rss_hash_opt(struct igc_adapter *adapter, ++ struct ethtool_rxnfc *nfc) + { + u32 flags = adapter->flags; + +@@ -1107,8 +1152,8 @@ + + if ((flags & UDP_RSS_FLAGS) && + !(adapter->flags & UDP_RSS_FLAGS)) +- dev_err(&adapter->pdev->dev, +- "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); ++ netdev_err(adapter->netdev, ++ "Enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n"); + + adapter->flags = flags; + +@@ -1133,344 +1178,184 @@ + return 0; + } + +-static int igc_rxnfc_write_etype_filter(struct igc_adapter *adapter, +- struct igc_nfc_filter *input) ++static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, ++ const struct ethtool_rx_flow_spec *fsp) + { +- struct igc_hw *hw = &adapter->hw; +- u8 i; +- u32 etqf; +- u16 etype; +- +- /* find an empty etype filter register */ +- for (i = 0; i < MAX_ETYPE_FILTER; ++i) { +- if (!adapter->etype_bitmap[i]) +- break; +- } +- if (i == MAX_ETYPE_FILTER) { +- dev_err(&adapter->pdev->dev, "ethtool -N: etype filters are all used.\n"); +- return -EINVAL; +- } +- +- adapter->etype_bitmap[i] = true; ++ INIT_LIST_HEAD(&rule->list); + +- etqf = rd32(IGC_ETQF(i)); +- etype = ntohs(input->filter.etype & ETHER_TYPE_FULL_MASK); ++ rule->action = fsp->ring_cookie; ++ rule->location = fsp->location; + +- etqf |= IGC_ETQF_FILTER_ENABLE; +- etqf &= ~IGC_ETQF_ETYPE_MASK; +- etqf |= (etype & IGC_ETQF_ETYPE_MASK); +- +- etqf &= ~IGC_ETQF_QUEUE_MASK; +- etqf |= ((input->action << IGC_ETQF_QUEUE_SHIFT) +- & IGC_ETQF_QUEUE_MASK); +- etqf |= IGC_ETQF_QUEUE_ENABLE; +- +- wr32(IGC_ETQF(i), etqf); +- +- input->etype_reg_index = i; +- +- return 0; +-} +- +-static int igc_rxnfc_write_vlan_prio_filter(struct igc_adapter *adapter, +- struct igc_nfc_filter *input) +-{ +- struct igc_hw *hw = &adapter->hw; +- u8 vlan_priority; +- u16 queue_index; +- u32 vlapqf; +- +- vlapqf = rd32(IGC_VLAPQF); +- vlan_priority = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK) +- >> VLAN_PRIO_SHIFT; +- queue_index = (vlapqf >> (vlan_priority * 4)) & IGC_VLAPQF_QUEUE_MASK; +- +- /* check whether this vlan prio is already set */ +- if (vlapqf & IGC_VLAPQF_P_VALID(vlan_priority) && +- queue_index != input->action) { +- dev_err(&adapter->pdev->dev, "ethtool rxnfc set vlan prio filter failed.\n"); +- return -EEXIST; ++ if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { ++ rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci); ++ rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI; + } + +- vlapqf |= IGC_VLAPQF_P_VALID(vlan_priority); +- vlapqf |= IGC_VLAPQF_QUEUE_SEL(vlan_priority, input->action); +- +- wr32(IGC_VLAPQF, vlapqf); +- +- return 0; +-} +- +-int igc_add_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input) +-{ +- struct igc_hw *hw = &adapter->hw; +- int err = -EINVAL; +- +- if (hw->mac.type == igc_i225 && +- !(input->filter.match_flags & ~IGC_FILTER_FLAG_SRC_MAC_ADDR)) { +- dev_err(&adapter->pdev->dev, +- "i225 doesn't support flow classification rules specifying only source addresses.\n"); +- return -EOPNOTSUPP; ++ if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { ++ rule->filter.etype = ntohs(fsp->h_u.ether_spec.h_proto); ++ rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE; + } + +- if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { +- err = igc_rxnfc_write_etype_filter(adapter, input); +- if (err) +- return err; +- } +- +- if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { +- err = igc_add_mac_steering_filter(adapter, +- input->filter.dst_addr, +- input->action, 0); +- err = min_t(int, err, 0); +- if (err) +- return err; +- } +- +- if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { +- err = igc_add_mac_steering_filter(adapter, +- input->filter.src_addr, +- input->action, +- IGC_MAC_STATE_SRC_ADDR); +- err = min_t(int, err, 0); +- if (err) +- return err; ++ /* Both source and destination address filters only support the full ++ * mask. ++ */ ++ if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) { ++ rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR; ++ ether_addr_copy(rule->filter.src_addr, ++ fsp->h_u.ether_spec.h_source); + } + +- if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) +- err = igc_rxnfc_write_vlan_prio_filter(adapter, input); +- +- return err; +-} +- +-static void igc_clear_etype_filter_regs(struct igc_adapter *adapter, +- u16 reg_index) +-{ +- struct igc_hw *hw = &adapter->hw; +- u32 etqf = rd32(IGC_ETQF(reg_index)); +- +- etqf &= ~IGC_ETQF_QUEUE_ENABLE; +- etqf &= ~IGC_ETQF_QUEUE_MASK; +- etqf &= ~IGC_ETQF_FILTER_ENABLE; +- +- wr32(IGC_ETQF(reg_index), etqf); +- +- adapter->etype_bitmap[reg_index] = false; +-} +- +-static void igc_clear_vlan_prio_filter(struct igc_adapter *adapter, +- u16 vlan_tci) +-{ +- struct igc_hw *hw = &adapter->hw; +- u8 vlan_priority; +- u32 vlapqf; +- +- vlan_priority = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; +- +- vlapqf = rd32(IGC_VLAPQF); +- vlapqf &= ~IGC_VLAPQF_P_VALID(vlan_priority); +- vlapqf &= ~IGC_VLAPQF_QUEUE_SEL(vlan_priority, +- IGC_VLAPQF_QUEUE_MASK); +- +- wr32(IGC_VLAPQF, vlapqf); ++ if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) { ++ rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR; ++ ether_addr_copy(rule->filter.dst_addr, ++ fsp->h_u.ether_spec.h_dest); ++ } + } + +-int igc_erase_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input) +-{ +- if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) +- igc_clear_etype_filter_regs(adapter, +- input->etype_reg_index); +- +- if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) +- igc_clear_vlan_prio_filter(adapter, +- ntohs(input->filter.vlan_tci)); ++/** ++ * igc_ethtool_check_nfc_rule() - Check if NFC rule is valid ++ * @adapter: Pointer to adapter ++ * @rule: Rule under evaluation ++ * ++ * The driver doesn't support rules with multiple matches so if more than ++ * one bit in filter flags is set, @rule is considered invalid. ++ * ++ * Also, if there is already another rule with the same filter in a different ++ * location, @rule is considered invalid. ++ * ++ * Context: Expects adapter->nfc_rule_lock to be held by caller. ++ * ++ * Return: 0 in case of success, negative errno code otherwise. ++ */ ++static int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter, ++ struct igc_nfc_rule *rule) ++{ ++ struct net_device *dev = adapter->netdev; ++ u8 flags = rule->filter.match_flags; ++ struct igc_nfc_rule *tmp; + +- if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) +- igc_del_mac_steering_filter(adapter, input->filter.src_addr, +- input->action, +- IGC_MAC_STATE_SRC_ADDR); +- +- if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) +- igc_del_mac_steering_filter(adapter, input->filter.dst_addr, +- input->action, 0); +- +- return 0; +-} +- +-static int igc_update_ethtool_nfc_entry(struct igc_adapter *adapter, +- struct igc_nfc_filter *input, +- u16 sw_idx) +-{ +- struct igc_nfc_filter *rule, *parent; +- int err = -EINVAL; +- +- parent = NULL; +- rule = NULL; +- +- hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { +- /* hash found, or no matching entry */ +- if (rule->sw_idx >= sw_idx) +- break; +- parent = rule; ++ if (!flags) { ++ netdev_dbg(dev, "Rule with no match\n"); ++ return -EINVAL; + } + +- /* if there is an old rule occupying our place remove it */ +- if (rule && rule->sw_idx == sw_idx) { +- if (!input) +- err = igc_erase_filter(adapter, rule); +- +- hlist_del(&rule->nfc_node); +- kfree(rule); +- adapter->nfc_filter_count--; ++ if (flags & (flags - 1)) { ++ netdev_dbg(dev, "Rule with multiple matches not supported\n"); ++ return -EOPNOTSUPP; + } + +- /* If no input this was a delete, err should be 0 if a rule was +- * successfully found and removed from the list else -EINVAL +- */ +- if (!input) +- return err; +- +- /* initialize node */ +- INIT_HLIST_NODE(&input->nfc_node); +- +- /* add filter to the list */ +- if (parent) +- hlist_add_behind(&input->nfc_node, &parent->nfc_node); +- else +- hlist_add_head(&input->nfc_node, &adapter->nfc_filter_list); +- +- /* update counts */ +- adapter->nfc_filter_count++; ++ list_for_each_entry(tmp, &adapter->nfc_rule_list, list) { ++ if (!memcmp(&rule->filter, &tmp->filter, ++ sizeof(rule->filter)) && ++ tmp->location != rule->location) { ++ netdev_dbg(dev, "Rule already exists\n"); ++ return -EEXIST; ++ } ++ } + + return 0; + } + +-static int igc_add_ethtool_nfc_entry(struct igc_adapter *adapter, +- struct ethtool_rxnfc *cmd) ++static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, ++ struct ethtool_rxnfc *cmd) + { + struct net_device *netdev = adapter->netdev; + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; +- struct igc_nfc_filter *input, *rule; +- int err = 0; ++ struct igc_nfc_rule *rule, *old_rule; ++ int err; + +- if (!(netdev->hw_features & NETIF_F_NTUPLE)) ++ if (!(netdev->hw_features & NETIF_F_NTUPLE)) { ++ netdev_dbg(netdev, "N-tuple filters disabled\n"); + return -EOPNOTSUPP; ++ } + +- /* Don't allow programming if the action is a queue greater than +- * the number of online Rx queues. +- */ +- if (fsp->ring_cookie == RX_CLS_FLOW_DISC || +- fsp->ring_cookie >= adapter->num_rx_queues) { +- dev_err(&adapter->pdev->dev, "ethtool -N: The specified action is invalid\n"); +- return -EINVAL; ++ if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) { ++ netdev_dbg(netdev, "Only ethernet flow type is supported\n"); ++ return -EOPNOTSUPP; + } + +- /* Don't allow indexes to exist outside of available space */ +- if (fsp->location >= IGC_MAX_RXNFC_FILTERS) { +- dev_err(&adapter->pdev->dev, "Location out of range\n"); +- return -EINVAL; ++ if ((fsp->flow_type & FLOW_EXT) && ++ fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) { ++ netdev_dbg(netdev, "VLAN mask not supported\n"); ++ return -EOPNOTSUPP; + } + +- if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) ++ if (fsp->ring_cookie >= adapter->num_rx_queues) { ++ netdev_dbg(netdev, "Invalid action\n"); + return -EINVAL; +- +- input = kzalloc(sizeof(*input), GFP_KERNEL); +- if (!input) +- return -ENOMEM; +- +- if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { +- input->filter.etype = fsp->h_u.ether_spec.h_proto; +- input->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE; + } + +- /* Only support matching addresses by the full mask */ +- if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) { +- input->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR; +- ether_addr_copy(input->filter.src_addr, +- fsp->h_u.ether_spec.h_source); ++ if (fsp->location >= IGC_MAX_RXNFC_RULES) { ++ netdev_dbg(netdev, "Invalid location\n"); ++ return -EINVAL; + } + +- /* Only support matching addresses by the full mask */ +- if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) { +- input->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR; +- ether_addr_copy(input->filter.dst_addr, +- fsp->h_u.ether_spec.h_dest); +- } ++ rule = kzalloc(sizeof(*rule), GFP_KERNEL); ++ if (!rule) ++ return -ENOMEM; + +- if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { +- if (fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) { +- err = -EINVAL; +- goto err_out; +- } +- input->filter.vlan_tci = fsp->h_ext.vlan_tci; +- input->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI; +- } ++ igc_ethtool_init_nfc_rule(rule, fsp); + +- input->action = fsp->ring_cookie; +- input->sw_idx = fsp->location; ++ mutex_lock(&adapter->nfc_rule_lock); + +- spin_lock(&adapter->nfc_lock); ++ err = igc_ethtool_check_nfc_rule(adapter, rule); ++ if (err) ++ goto err; + +- hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) { +- if (!memcmp(&input->filter, &rule->filter, +- sizeof(input->filter))) { +- err = -EEXIST; +- dev_err(&adapter->pdev->dev, +- "ethtool: this filter is already set\n"); +- goto err_out_w_lock; +- } +- } ++ old_rule = igc_get_nfc_rule(adapter, fsp->location); ++ if (old_rule) ++ igc_del_nfc_rule(adapter, old_rule); + +- err = igc_add_filter(adapter, input); ++ err = igc_add_nfc_rule(adapter, rule); + if (err) +- goto err_out_w_lock; +- +- igc_update_ethtool_nfc_entry(adapter, input, input->sw_idx); ++ goto err; + +- spin_unlock(&adapter->nfc_lock); ++ mutex_unlock(&adapter->nfc_rule_lock); + return 0; + +-err_out_w_lock: +- spin_unlock(&adapter->nfc_lock); +-err_out: +- kfree(input); ++err: ++ mutex_unlock(&adapter->nfc_rule_lock); ++ kfree(rule); + return err; + } + +-static int igc_del_ethtool_nfc_entry(struct igc_adapter *adapter, +- struct ethtool_rxnfc *cmd) ++static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter, ++ struct ethtool_rxnfc *cmd) + { + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; +- int err; ++ struct igc_nfc_rule *rule; + +- spin_lock(&adapter->nfc_lock); +- err = igc_update_ethtool_nfc_entry(adapter, NULL, fsp->location); +- spin_unlock(&adapter->nfc_lock); ++ mutex_lock(&adapter->nfc_rule_lock); + +- return err; ++ rule = igc_get_nfc_rule(adapter, fsp->location); ++ if (!rule) { ++ mutex_unlock(&adapter->nfc_rule_lock); ++ return -EINVAL; ++ } ++ ++ igc_del_nfc_rule(adapter, rule); ++ ++ mutex_unlock(&adapter->nfc_rule_lock); ++ return 0; + } + +-static int igc_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) ++static int igc_ethtool_set_rxnfc(struct net_device *dev, ++ struct ethtool_rxnfc *cmd) + { + struct igc_adapter *adapter = netdev_priv(dev); +- int ret = -EOPNOTSUPP; + + switch (cmd->cmd) { + case ETHTOOL_SRXFH: +- ret = igc_set_rss_hash_opt(adapter, cmd); +- break; ++ return igc_ethtool_set_rss_hash_opt(adapter, cmd); + case ETHTOOL_SRXCLSRLINS: +- ret = igc_add_ethtool_nfc_entry(adapter, cmd); +- break; ++ return igc_ethtool_add_nfc_rule(adapter, cmd); + case ETHTOOL_SRXCLSRLDEL: +- ret = igc_del_ethtool_nfc_entry(adapter, cmd); ++ return igc_ethtool_del_nfc_rule(adapter, cmd); + default: +- break; ++ return -EOPNOTSUPP; + } +- +- return ret; + } + + void igc_write_rss_indir_tbl(struct igc_adapter *adapter) +@@ -1495,13 +1380,13 @@ + } + } + +-static u32 igc_get_rxfh_indir_size(struct net_device *netdev) ++static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev) + { + return IGC_RETA_SIZE; + } + +-static int igc_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, +- u8 *hfunc) ++static int igc_ethtool_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, ++ u8 *hfunc) + { + struct igc_adapter *adapter = netdev_priv(netdev); + int i; +@@ -1516,8 +1401,8 @@ + return 0; + } + +-static int igc_set_rxfh(struct net_device *netdev, const u32 *indir, +- const u8 *key, const u8 hfunc) ++static int igc_ethtool_set_rxfh(struct net_device *netdev, const u32 *indir, ++ const u8 *key, const u8 hfunc) + { + struct igc_adapter *adapter = netdev_priv(netdev); + u32 num_queues; +@@ -1545,18 +1430,13 @@ + return 0; + } + +-static unsigned int igc_max_channels(struct igc_adapter *adapter) +-{ +- return igc_get_max_rss_queues(adapter); +-} +- +-static void igc_get_channels(struct net_device *netdev, +- struct ethtool_channels *ch) ++static void igc_ethtool_get_channels(struct net_device *netdev, ++ struct ethtool_channels *ch) + { + struct igc_adapter *adapter = netdev_priv(netdev); + + /* Report maximum channels */ +- ch->max_combined = igc_max_channels(adapter); ++ ch->max_combined = igc_get_max_rss_queues(adapter); + + /* Report info for other vector */ + if (adapter->flags & IGC_FLAG_HAS_MSIX) { +@@ -1567,8 +1447,8 @@ + ch->combined_count = adapter->rss_queues; + } + +-static int igc_set_channels(struct net_device *netdev, +- struct ethtool_channels *ch) ++static int igc_ethtool_set_channels(struct net_device *netdev, ++ struct ethtool_channels *ch) + { + struct igc_adapter *adapter = netdev_priv(netdev); + unsigned int count = ch->combined_count; +@@ -1583,7 +1463,7 @@ + return -EINVAL; + + /* Verify the number of channels doesn't exceed hw limits */ +- max_combined = igc_max_channels(adapter); ++ max_combined = igc_get_max_rss_queues(adapter); + if (count > max_combined) + return -EINVAL; + +@@ -1600,7 +1480,40 @@ + return 0; + } + +-static u32 igc_get_priv_flags(struct net_device *netdev) ++static int igc_ethtool_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_ethtool_get_priv_flags(struct net_device *netdev) + { + struct igc_adapter *adapter = netdev_priv(netdev); + u32 priv_flags = 0; +@@ -1611,7 +1524,7 @@ + return priv_flags; + } + +-static int igc_set_priv_flags(struct net_device *netdev, u32 priv_flags) ++static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags) + { + struct igc_adapter *adapter = netdev_priv(netdev); + unsigned int flags = adapter->flags; +@@ -1631,6 +1544,98 @@ + return 0; + } + ++static int igc_ethtool_get_eee(struct net_device *netdev, ++ struct ethtool_eee *edata) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ struct igc_hw *hw = &adapter->hw; ++ u32 eeer; ++ ++ if (hw->dev_spec._base.eee_enable) ++ edata->advertised = ++ mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); ++ ++ *edata = adapter->eee; ++ edata->supported = SUPPORTED_Autoneg; ++ ++ eeer = rd32(IGC_EEER); ++ ++ /* EEE status on negotiated link */ ++ if (eeer & IGC_EEER_EEE_NEG) ++ edata->eee_active = true; ++ ++ if (eeer & IGC_EEER_TX_LPI_EN) ++ edata->tx_lpi_enabled = true; ++ ++ edata->eee_enabled = hw->dev_spec._base.eee_enable; ++ ++ edata->advertised = SUPPORTED_Autoneg; ++ edata->lp_advertised = SUPPORTED_Autoneg; ++ ++ /* Report correct negotiated EEE status for devices that ++ * wrongly report EEE at half-duplex ++ */ ++ if (adapter->link_duplex == HALF_DUPLEX) { ++ edata->eee_enabled = false; ++ edata->eee_active = false; ++ edata->tx_lpi_enabled = false; ++ edata->advertised &= ~edata->advertised; ++ } ++ ++ return 0; ++} ++ ++static int igc_ethtool_set_eee(struct net_device *netdev, ++ struct ethtool_eee *edata) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ struct igc_hw *hw = &adapter->hw; ++ struct ethtool_eee eee_curr; ++ s32 ret_val; ++ ++ memset(&eee_curr, 0, sizeof(struct ethtool_eee)); ++ ++ ret_val = igc_ethtool_get_eee(netdev, &eee_curr); ++ if (ret_val) { ++ netdev_err(netdev, ++ "Problem setting EEE advertisement options\n"); ++ return -EINVAL; ++ } ++ ++ if (eee_curr.eee_enabled) { ++ if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) { ++ netdev_err(netdev, ++ "Setting EEE tx-lpi is not supported\n"); ++ return -EINVAL; ++ } ++ ++ /* Tx LPI timer is not implemented currently */ ++ if (edata->tx_lpi_timer) { ++ netdev_err(netdev, ++ "Setting EEE Tx LPI timer is not supported\n"); ++ return -EINVAL; ++ } ++ } else if (!edata->eee_enabled) { ++ netdev_err(netdev, ++ "Setting EEE options are not supported with EEE disabled\n"); ++ return -EINVAL; ++ } ++ ++ adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); ++ if (hw->dev_spec._base.eee_enable != edata->eee_enabled) { ++ hw->dev_spec._base.eee_enable = edata->eee_enabled; ++ adapter->flags |= IGC_FLAG_EEE; ++ ++ /* reset link */ ++ if (netif_running(netdev)) ++ igc_reinit_locked(adapter); ++ else ++ igc_reset(adapter); ++ } ++ ++ return 0; ++} ++ + static int igc_ethtool_begin(struct net_device *netdev) + { + struct igc_adapter *adapter = netdev_priv(netdev); +@@ -1646,8 +1651,8 @@ + pm_runtime_put(&adapter->pdev->dev); + } + +-static int igc_get_link_ksettings(struct net_device *netdev, +- struct ethtool_link_ksettings *cmd) ++static int igc_ethtool_get_link_ksettings(struct net_device *netdev, ++ struct ethtool_link_ksettings *cmd) + { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; +@@ -1761,10 +1766,12 @@ + return 0; + } + +-static int igc_set_link_ksettings(struct net_device *netdev, +- const struct ethtool_link_ksettings *cmd) ++static int ++igc_ethtool_set_link_ksettings(struct net_device *netdev, ++ const struct ethtool_link_ksettings *cmd) + { + struct igc_adapter *adapter = netdev_priv(netdev); ++ struct net_device *dev = adapter->netdev; + struct igc_hw *hw = &adapter->hw; + u32 advertising; + +@@ -1772,8 +1779,7 @@ + * cannot be changed + */ + if (igc_check_reset_block(hw)) { +- dev_err(&adapter->pdev->dev, +- "Cannot change link characteristics when reset is active.\n"); ++ netdev_err(dev, "Cannot change link characteristics when reset is active\n"); + return -EINVAL; + } + +@@ -1784,7 +1790,7 @@ + if (cmd->base.eth_tp_mdix_ctrl) { + if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO && + cmd->base.autoneg != AUTONEG_ENABLE) { +- dev_err(&adapter->pdev->dev, "forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); ++ netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); + return -EINVAL; + } + } +@@ -1807,9 +1813,7 @@ + if (adapter->fc_autoneg) + hw->fc.requested_mode = igc_fc_default; + } else { +- /* calling this overrides forced MDI setting */ +- dev_info(&adapter->pdev->dev, +- "Force mode currently not supported\n"); ++ netdev_info(dev, "Force mode currently not supported\n"); + } + + /* MDI-X => 2; MDI => 1; Auto => 3 */ +@@ -1836,42 +1840,106 @@ + return 0; + } + ++static void igc_ethtool_diag_test(struct net_device *netdev, ++ struct ethtool_test *eth_test, u64 *data) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ bool if_running = netif_running(netdev); ++ ++ if (eth_test->flags == ETH_TEST_FL_OFFLINE) { ++ netdev_info(adapter->netdev, "Offline testing starting"); ++ set_bit(__IGC_TESTING, &adapter->state); ++ ++ /* Link test performed before hardware reset so autoneg doesn't ++ * interfere with test result ++ */ ++ if (!igc_link_test(adapter, &data[TEST_LINK])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ if (if_running) ++ igc_close(netdev); ++ else ++ igc_reset(adapter); ++ ++ netdev_info(adapter->netdev, "Register testing starting"); ++ if (!igc_reg_test(adapter, &data[TEST_REG])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ igc_reset(adapter); ++ ++ netdev_info(adapter->netdev, "EEPROM testing starting"); ++ if (!igc_eeprom_test(adapter, &data[TEST_EEP])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ ++ igc_reset(adapter); ++ ++ /* loopback and interrupt tests ++ * will be implemented in the future ++ */ ++ data[TEST_LOOP] = 0; ++ data[TEST_IRQ] = 0; ++ ++ clear_bit(__IGC_TESTING, &adapter->state); ++ if (if_running) ++ igc_open(netdev); ++ } else { ++ netdev_info(adapter->netdev, "Online testing starting"); ++ ++ /* register, eeprom, intr and loopback tests not run online */ ++ data[TEST_REG] = 0; ++ data[TEST_EEP] = 0; ++ data[TEST_IRQ] = 0; ++ data[TEST_LOOP] = 0; ++ ++ if (!igc_link_test(adapter, &data[TEST_LINK])) ++ eth_test->flags |= ETH_TEST_FL_FAILED; ++ } ++ ++ msleep_interruptible(4 * 1000); ++} ++ + static const struct ethtool_ops igc_ethtool_ops = { +- .get_drvinfo = igc_get_drvinfo, +- .get_regs_len = igc_get_regs_len, +- .get_regs = igc_get_regs, +- .get_msglevel = igc_get_msglevel, +- .set_msglevel = igc_set_msglevel, +- .nway_reset = igc_nway_reset, +- .get_link = igc_get_link, +- .get_eeprom_len = igc_get_eeprom_len, +- .get_eeprom = igc_get_eeprom, +- .set_eeprom = igc_set_eeprom, +- .get_ringparam = igc_get_ringparam, +- .set_ringparam = igc_set_ringparam, +- .get_pauseparam = igc_get_pauseparam, +- .set_pauseparam = igc_set_pauseparam, +- .get_strings = igc_get_strings, +- .get_sset_count = igc_get_sset_count, +- .get_ethtool_stats = igc_get_ethtool_stats, +- .get_coalesce = igc_get_coalesce, +- .set_coalesce = igc_set_coalesce, +- .get_rxnfc = igc_get_rxnfc, +- .set_rxnfc = igc_set_rxnfc, +- .get_rxfh_indir_size = igc_get_rxfh_indir_size, +- .get_rxfh = igc_get_rxfh, +- .set_rxfh = igc_set_rxfh, +- .get_channels = igc_get_channels, +- .set_channels = igc_set_channels, +- .get_priv_flags = igc_get_priv_flags, +- .set_priv_flags = igc_set_priv_flags, ++ .get_drvinfo = igc_ethtool_get_drvinfo, ++ .get_regs_len = igc_ethtool_get_regs_len, ++ .get_regs = igc_ethtool_get_regs, ++ .get_wol = igc_ethtool_get_wol, ++ .set_wol = igc_ethtool_set_wol, ++ .get_msglevel = igc_ethtool_get_msglevel, ++ .set_msglevel = igc_ethtool_set_msglevel, ++ .nway_reset = igc_ethtool_nway_reset, ++ .get_link = igc_ethtool_get_link, ++ .get_eeprom_len = igc_ethtool_get_eeprom_len, ++ .get_eeprom = igc_ethtool_get_eeprom, ++ .set_eeprom = igc_ethtool_set_eeprom, ++ .get_ringparam = igc_ethtool_get_ringparam, ++ .set_ringparam = igc_ethtool_set_ringparam, ++ .get_pauseparam = igc_ethtool_get_pauseparam, ++ .set_pauseparam = igc_ethtool_set_pauseparam, ++ .get_strings = igc_ethtool_get_strings, ++ .get_sset_count = igc_ethtool_get_sset_count, ++ .get_ethtool_stats = igc_ethtool_get_stats, ++ .get_coalesce = igc_ethtool_get_coalesce, ++ .set_coalesce = igc_ethtool_set_coalesce, ++ .get_rxnfc = igc_ethtool_get_rxnfc, ++ .set_rxnfc = igc_ethtool_set_rxnfc, ++ .get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size, ++ .get_rxfh = igc_ethtool_get_rxfh, ++ .set_rxfh = igc_ethtool_set_rxfh, ++ .get_ts_info = igc_ethtool_get_ts_info, ++ .get_channels = igc_ethtool_get_channels, ++ .set_channels = igc_ethtool_set_channels, ++ .get_priv_flags = igc_ethtool_get_priv_flags, ++ .set_priv_flags = igc_ethtool_set_priv_flags, ++ .get_eee = igc_ethtool_get_eee, ++ .set_eee = igc_ethtool_set_eee, + .begin = igc_ethtool_begin, + .complete = igc_ethtool_complete, +- .get_link_ksettings = igc_get_link_ksettings, +- .set_link_ksettings = igc_set_link_ksettings, ++ .get_link_ksettings = igc_ethtool_get_link_ksettings, ++ .set_link_ksettings = igc_ethtool_set_link_ksettings, ++ .self_test = igc_ethtool_diag_test, + }; + +-void igc_set_ethtool_ops(struct net_device *netdev) ++void igc_ethtool_set_ops(struct net_device *netdev) + { + netdev->ethtool_ops = &igc_ethtool_ops; + } + +--- a/drivers/net/ethernet/intel/igc/igc.h 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc.h 2022-03-10 14:33:17.223213194 +0800 +@@ -10,17 +10,219 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "igc_hw.h" + +-/* forward declaration */ +-void igc_set_ethtool_ops(struct net_device *); ++void igc_ethtool_set_ops(struct net_device *); + +-struct igc_adapter; +-struct igc_ring; ++/* Transmit and receive queues */ ++#define IGC_MAX_RX_QUEUES 4 ++#define IGC_MAX_TX_QUEUES 4 ++ ++#define MAX_Q_VECTORS 8 ++#define MAX_STD_JUMBO_FRAME_SIZE 9216 ++ ++#define MAX_ETYPE_FILTER 8 ++#define IGC_RETA_SIZE 128 ++ ++enum igc_mac_filter_type { ++ IGC_MAC_FILTER_TYPE_DST = 0, ++ IGC_MAC_FILTER_TYPE_SRC ++}; ++ ++struct igc_tx_queue_stats { ++ u64 packets; ++ u64 bytes; ++ u64 restart_queue; ++ u64 restart_queue2; ++}; ++ ++struct igc_rx_queue_stats { ++ u64 packets; ++ u64 bytes; ++ u64 drops; ++ u64 csum_err; ++ u64 alloc_failed; ++}; ++ ++struct igc_rx_packet_stats { ++ u64 ipv4_packets; /* IPv4 headers processed */ ++ u64 ipv4e_packets; /* IPv4E headers with extensions processed */ ++ u64 ipv6_packets; /* IPv6 headers processed */ ++ u64 ipv6e_packets; /* IPv6E headers with extensions processed */ ++ u64 tcp_packets; /* TCP headers processed */ ++ u64 udp_packets; /* UDP headers processed */ ++ u64 sctp_packets; /* SCTP headers processed */ ++ u64 nfs_packets; /* NFS headers processe */ ++ u64 other_packets; ++}; ++ ++struct igc_ring_container { ++ struct igc_ring *ring; /* pointer to linked list of rings */ ++ unsigned int total_bytes; /* total bytes processed this int */ ++ unsigned int total_packets; /* total packets processed this int */ ++ u16 work_limit; /* total work allowed per interrupt */ ++ u8 count; /* total number of rings in vector */ ++ u8 itr; /* current ITR setting for ring */ ++}; ++ ++struct igc_ring { ++ struct igc_q_vector *q_vector; /* backlink to q_vector */ ++ struct net_device *netdev; /* back pointer to net_device */ ++ struct device *dev; /* device for dma mapping */ ++ union { /* array of buffer info structs */ ++ struct igc_tx_buffer *tx_buffer_info; ++ struct igc_rx_buffer *rx_buffer_info; ++ }; ++ void *desc; /* descriptor ring memory */ ++ unsigned long flags; /* ring specific flags */ ++ void __iomem *tail; /* pointer to ring tail register */ ++ dma_addr_t dma; /* phys address of the ring */ ++ unsigned int size; /* length of desc. ring in bytes */ ++ ++ u16 count; /* number of desc. in the ring */ ++ u8 queue_index; /* logical index of the ring*/ ++ u8 reg_idx; /* physical index of the ring */ ++ bool launchtime_enable; /* true if LaunchTime is enabled */ ++ ++ u32 start_time; ++ u32 end_time; ++ ++ /* everything past this point are written often */ ++ u16 next_to_clean; ++ u16 next_to_use; ++ u16 next_to_alloc; ++ ++ union { ++ /* TX */ ++ struct { ++ struct igc_tx_queue_stats tx_stats; ++ struct u64_stats_sync tx_syncp; ++ struct u64_stats_sync tx_syncp2; ++ }; ++ /* RX */ ++ struct { ++ struct igc_rx_queue_stats rx_stats; ++ struct igc_rx_packet_stats pkt_stats; ++ struct u64_stats_sync rx_syncp; ++ struct sk_buff *skb; ++ }; ++ }; ++} ____cacheline_internodealigned_in_smp; ++ ++/* Board specific private data structure */ ++struct igc_adapter { ++ struct net_device *netdev; ++ ++ struct ethtool_eee eee; ++ u16 eee_advert; ++ ++ unsigned long state; ++ unsigned int flags; ++ unsigned int num_q_vectors; ++ ++ struct msix_entry *msix_entries; ++ ++ /* TX */ ++ u16 tx_work_limit; ++ u32 tx_timeout_count; ++ int num_tx_queues; ++ struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES]; ++ ++ /* RX */ ++ int num_rx_queues; ++ struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES]; ++ ++ struct timer_list watchdog_timer; ++ struct timer_list dma_err_timer; ++ struct timer_list phy_info_timer; ++ ++ u32 wol; ++ u32 en_mng_pt; ++ u16 link_speed; ++ u16 link_duplex; ++ ++ u8 port_num; ++ ++ u8 __iomem *io_addr; ++ /* Interrupt Throttle Rate */ ++ u32 rx_itr_setting; ++ u32 tx_itr_setting; ++ ++ struct work_struct reset_task; ++ struct work_struct watchdog_task; ++ struct work_struct dma_err_task; ++ bool fc_autoneg; ++ ++ u8 tx_timeout_factor; ++ ++ int msg_enable; ++ u32 max_frame_size; ++ u32 min_frame_size; ++ ++ ktime_t base_time; ++ ktime_t cycle_time; ++ ++ /* OS defined structs */ ++ struct pci_dev *pdev; ++ /* lock for statistics */ ++ spinlock_t stats64_lock; ++ struct rtnl_link_stats64 stats64; ++ ++ /* structs defined in igc_hw.h */ ++ struct igc_hw hw; ++ struct igc_hw_stats stats; ++ ++ struct igc_q_vector *q_vector[MAX_Q_VECTORS]; ++ u32 eims_enable_mask; ++ u32 eims_other; ++ ++ u16 tx_ring_count; ++ u16 rx_ring_count; ++ ++ u32 tx_hwtstamp_timeouts; ++ u32 tx_hwtstamp_skipped; ++ u32 rx_hwtstamp_cleared; ++ ++ u32 rss_queues; ++ u32 rss_indir_tbl_init; ++ ++ /* Any access to elements in nfc_rule_list is protected by the ++ * nfc_rule_lock. ++ */ ++ struct mutex nfc_rule_lock; ++ struct list_head nfc_rule_list; ++ unsigned int nfc_rule_count; ++ ++ u8 rss_indir_tbl[IGC_RETA_SIZE]; ++ ++ unsigned long link_check_timeout; ++ struct igc_info ei; ++ ++ u32 test_icr; ++ ++ 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 int ptp_flags; ++ /* System time value lock */ ++ spinlock_t tmreg_lock; ++ struct cyclecounter cc; ++ struct timecounter tc; ++ struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */ ++ ktime_t ptp_reset_start; /* Reset time in clock mono */ ++}; + + void igc_up(struct igc_adapter *adapter); + void igc_down(struct igc_adapter *adapter); ++int igc_open(struct net_device *netdev); ++int igc_close(struct net_device *netdev); + int igc_setup_tx_resources(struct igc_ring *ring); + int igc_setup_rx_resources(struct igc_ring *ring); + void igc_free_tx_resources(struct igc_ring *ring); +@@ -33,29 +235,33 @@ + bool igc_has_link(struct igc_adapter *adapter); + void igc_reset(struct igc_adapter *adapter); + int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx); +-int igc_add_mac_steering_filter(struct igc_adapter *adapter, +- const u8 *addr, u8 queue, u8 flags); +-int igc_del_mac_steering_filter(struct igc_adapter *adapter, +- const u8 *addr, u8 queue, u8 flags); + void igc_update_stats(struct igc_adapter *adapter); + ++/* igc_dump declarations */ ++void igc_rings_dump(struct igc_adapter *adapter); ++void igc_regs_dump(struct igc_adapter *adapter); ++ + extern char igc_driver_name[]; +-extern char igc_driver_version[]; + + #define IGC_REGS_LEN 740 +-#define IGC_RETA_SIZE 128 + +-/* Interrupt defines */ +-#define IGC_START_ITR 648 /* ~6000 ints/sec */ ++/* flags controlling PTP/1588 function */ ++#define IGC_PTP_ENABLED BIT(0) ++ ++/* Flags definitions */ + #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_WOL_SUPPORTED BIT(8) + #define IGC_FLAG_NEED_LINK_UPDATE BIT(9) + #define IGC_FLAG_MEDIA_RESET BIT(10) + #define IGC_FLAG_MAS_ENABLE BIT(12) + #define IGC_FLAG_HAS_MSIX BIT(13) ++#define IGC_FLAG_EEE BIT(14) + #define IGC_FLAG_VLAN_PROMISC BIT(15) + #define IGC_FLAG_RX_LEGACY BIT(16) ++#define IGC_FLAG_TSN_QBV_ENABLED BIT(17) + + #define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6) + #define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7) +@@ -64,6 +270,7 @@ + #define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 + #define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 + ++/* Interrupt defines */ + #define IGC_START_ITR 648 /* ~6000 ints/sec */ + #define IGC_4K_ITR 980 + #define IGC_20K_ITR 196 +@@ -85,13 +292,6 @@ + #define IGC_MIN_RXD 80 + #define IGC_MAX_RXD 4096 + +-/* Transmit and receive queues */ +-#define IGC_MAX_RX_QUEUES 4 +-#define IGC_MAX_TX_QUEUES 4 +- +-#define MAX_Q_VECTORS 8 +-#define MAX_STD_JUMBO_FRAME_SIZE 9216 +- + /* Supported Rx Buffer Sizes */ + #define IGC_RXBUFFER_256 256 + #define IGC_RXBUFFER_2048 2048 +@@ -100,6 +300,16 @@ + #define AUTO_ALL_MODES 0 + #define IGC_RX_HDR_LEN IGC_RXBUFFER_256 + ++/* Transmit and receive latency (for PTP timestamps) */ ++#define IGC_I225_TX_LATENCY_10 240 ++#define IGC_I225_TX_LATENCY_100 58 ++#define IGC_I225_TX_LATENCY_1000 80 ++#define IGC_I225_TX_LATENCY_2500 1325 ++#define IGC_I225_RX_LATENCY_10 6450 ++#define IGC_I225_RX_LATENCY_100 185 ++#define IGC_I225_RX_LATENCY_1000 300 ++#define IGC_I225_RX_LATENCY_2500 1485 ++ + /* 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. +@@ -204,83 +414,6 @@ + __u16 pagecnt_bias; + }; + +-struct igc_tx_queue_stats { +- u64 packets; +- u64 bytes; +- u64 restart_queue; +- u64 restart_queue2; +-}; +- +-struct igc_rx_queue_stats { +- u64 packets; +- u64 bytes; +- u64 drops; +- u64 csum_err; +- u64 alloc_failed; +-}; +- +-struct igc_rx_packet_stats { +- u64 ipv4_packets; /* IPv4 headers processed */ +- u64 ipv4e_packets; /* IPv4E headers with extensions processed */ +- u64 ipv6_packets; /* IPv6 headers processed */ +- u64 ipv6e_packets; /* IPv6E headers with extensions processed */ +- u64 tcp_packets; /* TCP headers processed */ +- u64 udp_packets; /* UDP headers processed */ +- u64 sctp_packets; /* SCTP headers processed */ +- u64 nfs_packets; /* NFS headers processe */ +- u64 other_packets; +-}; +- +-struct igc_ring_container { +- struct igc_ring *ring; /* pointer to linked list of rings */ +- unsigned int total_bytes; /* total bytes processed this int */ +- unsigned int total_packets; /* total packets processed this int */ +- u16 work_limit; /* total work allowed per interrupt */ +- u8 count; /* total number of rings in vector */ +- u8 itr; /* current ITR setting for ring */ +-}; +- +-struct igc_ring { +- struct igc_q_vector *q_vector; /* backlink to q_vector */ +- struct net_device *netdev; /* back pointer to net_device */ +- struct device *dev; /* device for dma mapping */ +- union { /* array of buffer info structs */ +- struct igc_tx_buffer *tx_buffer_info; +- struct igc_rx_buffer *rx_buffer_info; +- }; +- void *desc; /* descriptor ring memory */ +- unsigned long flags; /* ring specific flags */ +- void __iomem *tail; /* pointer to ring tail register */ +- dma_addr_t dma; /* phys address of the ring */ +- unsigned int size; /* length of desc. ring in bytes */ +- +- u16 count; /* number of desc. in the ring */ +- u8 queue_index; /* logical index of the ring*/ +- u8 reg_idx; /* physical index of the ring */ +- bool launchtime_enable; /* true if LaunchTime is enabled */ +- +- /* everything past this point are written often */ +- u16 next_to_clean; +- u16 next_to_use; +- u16 next_to_alloc; +- +- union { +- /* TX */ +- struct { +- struct igc_tx_queue_stats tx_stats; +- struct u64_stats_sync tx_syncp; +- struct u64_stats_sync tx_syncp2; +- }; +- /* RX */ +- struct { +- struct igc_rx_queue_stats rx_stats; +- struct igc_rx_packet_stats pkt_stats; +- struct u64_stats_sync rx_syncp; +- struct sk_buff *skb; +- }; +- }; +-} ____cacheline_internodealigned_in_smp; +- + struct igc_q_vector { + struct igc_adapter *adapter; /* backlink */ + void __iomem *itr_register; +@@ -298,11 +431,9 @@ + struct net_device poll_dev; + + /* for dynamic allocation of rings associated with this q_vector */ +- struct igc_ring ring[0] ____cacheline_internodealigned_in_smp; ++ struct igc_ring ring[] ____cacheline_internodealigned_in_smp; + }; + +-#define MAX_ETYPE_FILTER (4 - 1) +- + enum igc_filter_match_flags { + IGC_FILTER_FLAG_ETHER_TYPE = 0x1, + IGC_FILTER_FLAG_VLAN_TCI = 0x2, +@@ -310,128 +441,25 @@ + IGC_FILTER_FLAG_DST_MAC_ADDR = 0x8, + }; + +-/* RX network flow classification data structure */ +-struct igc_nfc_input { +- /* Byte layout in order, all values with MSB first: +- * match_flags - 1 byte +- * etype - 2 bytes +- * vlan_tci - 2 bytes +- */ ++struct igc_nfc_filter { + u8 match_flags; +- __be16 etype; +- __be16 vlan_tci; ++ u16 etype; ++ u16 vlan_tci; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; + }; + +-struct igc_nfc_filter { +- struct hlist_node nfc_node; +- struct igc_nfc_input filter; +- unsigned long cookie; +- u16 etype_reg_index; +- u16 sw_idx; ++struct igc_nfc_rule { ++ struct list_head list; ++ struct igc_nfc_filter filter; ++ u32 location; + u16 action; + }; + +-struct igc_mac_addr { +- u8 addr[ETH_ALEN]; +- u8 queue; +- u8 state; /* bitmask */ +-}; +- +-#define IGC_MAC_STATE_DEFAULT 0x1 +-#define IGC_MAC_STATE_IN_USE 0x2 +-#define IGC_MAC_STATE_SRC_ADDR 0x4 +-#define IGC_MAC_STATE_QUEUE_STEERING 0x8 +- +-#define IGC_MAX_RXNFC_FILTERS 16 +- +-/* Board specific private data structure */ +-struct igc_adapter { +- struct net_device *netdev; +- +- unsigned long state; +- unsigned int flags; +- unsigned int num_q_vectors; +- +- struct msix_entry *msix_entries; +- +- /* TX */ +- u16 tx_work_limit; +- u32 tx_timeout_count; +- int num_tx_queues; +- struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES]; +- +- /* RX */ +- int num_rx_queues; +- struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES]; +- +- struct timer_list watchdog_timer; +- struct timer_list dma_err_timer; +- struct timer_list phy_info_timer; +- +- u16 link_speed; +- u16 link_duplex; +- +- u8 port_num; +- +- u8 __iomem *io_addr; +- /* Interrupt Throttle Rate */ +- u32 rx_itr_setting; +- u32 tx_itr_setting; +- +- struct work_struct reset_task; +- struct work_struct watchdog_task; +- struct work_struct dma_err_task; +- bool fc_autoneg; +- +- u8 tx_timeout_factor; +- +- int msg_enable; +- u32 max_frame_size; +- u32 min_frame_size; +- +- /* OS defined structs */ +- struct pci_dev *pdev; +- /* lock for statistics */ +- spinlock_t stats64_lock; +- struct rtnl_link_stats64 stats64; +- +- /* structs defined in igc_hw.h */ +- struct igc_hw hw; +- struct igc_hw_stats stats; +- +- struct igc_q_vector *q_vector[MAX_Q_VECTORS]; +- u32 eims_enable_mask; +- u32 eims_other; +- +- u16 tx_ring_count; +- u16 rx_ring_count; +- +- u32 tx_hwtstamp_timeouts; +- u32 tx_hwtstamp_skipped; +- u32 rx_hwtstamp_cleared; +- u32 *shadow_vfta; +- +- u32 rss_queues; +- u32 rss_indir_tbl_init; +- +- /* RX network flow classification support */ +- struct hlist_head nfc_filter_list; +- struct hlist_head cls_flower_list; +- unsigned int nfc_filter_count; +- +- /* lock for RX network flow classification filter */ +- spinlock_t nfc_lock; +- bool etype_bitmap[MAX_ETYPE_FILTER]; +- +- struct igc_mac_addr *mac_table; +- +- u8 rss_indir_tbl[IGC_RETA_SIZE]; +- +- unsigned long link_check_timeout; +- struct igc_info ei; +-}; ++/* IGC supports a total of 32 NFC rules: 16 MAC address based,, 8 VLAN priority ++ * based, and 8 ethertype based. ++ */ ++#define IGC_MAX_RXNFC_RULES 32 + + /* igc_desc_unused - calculate if we have unused descriptors */ + static inline u16 igc_desc_unused(const struct igc_ring *ring) +@@ -507,12 +535,22 @@ + return -EOPNOTSUPP; + } + +-/* forward declaration */ + void igc_reinit_locked(struct igc_adapter *); +-int igc_add_filter(struct igc_adapter *adapter, +- struct igc_nfc_filter *input); +-int igc_erase_filter(struct igc_adapter *adapter, +- struct igc_nfc_filter *input); ++struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter, ++ u32 location); ++int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule); ++void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule); ++ ++void igc_ptp_init(struct igc_adapter *adapter); ++void igc_ptp_reset(struct igc_adapter *adapter); ++void igc_ptp_suspend(struct igc_adapter *adapter); ++void igc_ptp_stop(struct igc_adapter *adapter); ++void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, __le32 *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); ++void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts); + + #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) + + +--- a/drivers/net/ethernet/intel/igc/igc_hw.h 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_hw.h 2022-03-10 14:51:34.344921696 +0800 +@@ -21,8 +21,17 @@ + #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_K2 0x3101 ++#define IGC_DEV_ID_I226_K 0x3102 ++#define IGC_DEV_ID_I225_LMVP 0x5502 ++#define IGC_DEV_ID_I226_LMVP 0x5503 ++#define IGC_DEV_ID_I225_IT 0x0D9F ++#define IGC_DEV_ID_I226_LM 0x125B ++#define IGC_DEV_ID_I226_V 0x125C ++#define IGC_DEV_ID_I226_IT 0x125D ++#define IGC_DEV_ID_I221_V 0x125E ++#define IGC_DEV_ID_I226_BLANK_NVM 0x125F ++#define IGC_DEV_ID_I225_BLANK_NVM 0x15FD + + /* Function pointers for the MAC. */ + struct igc_mac_operations { +@@ -46,7 +55,6 @@ + + enum igc_phy_type { + igc_phy_unknown = 0, +- igc_phy_none, + igc_phy_i225, + }; + +@@ -59,8 +67,6 @@ + enum igc_nvm_type { + igc_nvm_unknown = 0, + igc_nvm_eeprom_spi, +- igc_nvm_flash_hw, +- igc_nvm_invm, + }; + + struct igc_info { +@@ -80,23 +86,16 @@ + + enum igc_mac_type type; + +- u32 collision_delta; +- u32 ledctl_default; +- u32 ledctl_mode1; +- u32 ledctl_mode2; + u32 mc_filter_type; +- u32 tx_packet_delta; +- u32 txcw; + + u16 mta_reg_count; + u16 uta_reg_count; + ++ u32 mta_shadow[MAX_MTA_REG]; + u16 rar_entry_count; + + u8 forced_speed_duplex; + +- bool adaptive_ifs; +- bool has_fwsm; + bool asf_firmware_present; + bool arc_subsystem_valid; + +@@ -130,9 +129,6 @@ + struct igc_nvm_operations ops; + enum igc_nvm_type type; + +- u32 flash_bank_size; +- u32 flash_base_addr; +- + u16 word_size; + u16 delay_usec; + u16 address_bits; +@@ -158,7 +154,6 @@ + u8 mdix; + + bool is_mdix; +- bool reset_disable; + bool speed_downgraded; + bool autoneg_wait_to_complete; + }; +@@ -188,6 +183,7 @@ + + struct igc_dev_spec_base { + bool clear_semaphore_once; ++ bool eee_enable; + }; + + struct igc_hw { +@@ -243,6 +239,8 @@ + u64 prc511; + u64 prc1023; + u64 prc1522; ++ u64 tlpic; ++ u64 rlpic; + u64 gprc; + u64 bprc; + u64 mprc; +@@ -272,21 +270,9 @@ + u64 tsctc; + u64 tsctfc; + u64 iac; +- u64 icrxptc; +- u64 icrxatc; +- u64 ictxptc; +- u64 ictxatc; +- u64 ictxqec; +- u64 ictxqmtc; +- u64 icrxdmtc; +- u64 icrxoc; +- u64 cbtmpc; + u64 htdpmc; +- u64 cbrdpc; +- u64 cbrmpc; + u64 rpthc; + u64 hgptc; +- u64 htcbdpc; + u64 hgorc; + u64 hgotc; + u64 lenerrs; + +--- a/drivers/net/ethernet/intel/igc/igc_i225.c 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_i225.c 2022-03-10 14:46:02.453700756 +0800 +@@ -473,13 +473,11 @@ + + /* NVM Function Pointers */ + if (igc_get_flash_presence_i225(hw)) { +- hw->nvm.type = igc_nvm_flash_hw; + nvm->ops.read = igc_read_nvm_srrd_i225; + nvm->ops.write = igc_write_nvm_srwr_i225; + nvm->ops.validate = igc_validate_nvm_checksum_i225; + nvm->ops.update = igc_update_nvm_checksum_i225; + } else { +- hw->nvm.type = igc_nvm_invm; + nvm->ops.read = igc_read_nvm_eerd; + nvm->ops.write = NULL; + nvm->ops.validate = NULL; +@@ -487,3 +485,159 @@ + } + return 0; + } ++ ++/** ++ * igc_set_eee_i225 - Enable/disable EEE support ++ * @hw: pointer to the HW structure ++ * @adv2p5G: boolean flag enabling 2.5G EEE advertisement ++ * @adv1G: boolean flag enabling 1G EEE advertisement ++ * @adv100M: boolean flag enabling 100M EEE advertisement ++ * ++ * Enable/disable EEE based on setting in dev_spec structure. ++ **/ ++s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G, ++ bool adv100M) ++{ ++ u32 ipcnfg, eeer; ++ ++ ipcnfg = rd32(IGC_IPCNFG); ++ eeer = rd32(IGC_EEER); ++ ++ /* enable or disable per user setting */ ++ if (hw->dev_spec._base.eee_enable) { ++ u32 eee_su = rd32(IGC_EEE_SU); ++ ++ if (adv100M) ++ ipcnfg |= IGC_IPCNFG_EEE_100M_AN; ++ else ++ ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN; ++ ++ if (adv1G) ++ ipcnfg |= IGC_IPCNFG_EEE_1G_AN; ++ else ++ ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN; ++ ++ if (adv2p5G) ++ ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN; ++ else ++ ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN; ++ ++ eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN | ++ IGC_EEER_LPI_FC); ++ ++ /* This bit should not be set in normal operation. */ ++ if (eee_su & IGC_EEE_SU_LPI_CLK_STP) ++ hw_dbg("LPI Clock Stop Bit should not be set!\n"); ++ } else { ++ ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN | ++ IGC_IPCNFG_EEE_100M_AN); ++ eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN | ++ IGC_EEER_LPI_FC); ++ } ++ wr32(IGC_IPCNFG, ipcnfg); ++ wr32(IGC_EEER, eeer); ++ rd32(IGC_IPCNFG); ++ rd32(IGC_EEER); ++ ++ return IGC_SUCCESS; ++} ++ ++/* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds ++ * @hw: pointer to the HW structure ++ * @link: bool indicating link status ++ * ++ * Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC ++ * settings, otherwise specify that there is no LTR requirement. ++ */ ++s32 igc_set_ltr_i225(struct igc_hw *hw, bool link) ++{ ++ u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max; ++ u16 speed, duplex; ++ s32 size; ++ ++ /* If we do not have link, LTR thresholds are zero. */ ++ if (link) { ++ hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); ++ ++ /* Check if using copper interface with EEE enabled or if the ++ * link speed is 10 Mbps. ++ */ ++ if (hw->dev_spec._base.eee_enable && ++ speed != SPEED_10) { ++ /* EEE enabled, so send LTRMAX threshold. */ ++ ltrc = rd32(IGC_LTRC) | ++ IGC_LTRC_EEEMS_EN; ++ wr32(IGC_LTRC, ltrc); ++ ++ /* Calculate tw_system (nsec). */ ++ if (speed == SPEED_100) { ++ tw_system = ((rd32(IGC_EEE_SU) & ++ IGC_TW_SYSTEM_100_MASK) >> ++ IGC_TW_SYSTEM_100_SHIFT) * 500; ++ } else { ++ tw_system = (rd32(IGC_EEE_SU) & ++ IGC_TW_SYSTEM_1000_MASK) * 500; ++ } ++ } else { ++ tw_system = 0; ++ } ++ ++ /* Get the Rx packet buffer size. */ ++ size = rd32(IGC_RXPBS) & ++ IGC_RXPBS_SIZE_I225_MASK; ++ ++ /* Calculations vary based on DMAC settings. */ ++ if (rd32(IGC_DMACR) & IGC_DMACR_DMAC_EN) { ++ size -= (rd32(IGC_DMACR) & ++ IGC_DMACR_DMACTHR_MASK) >> ++ IGC_DMACR_DMACTHR_SHIFT; ++ /* Convert size to bits. */ ++ size *= 1024 * 8; ++ } else { ++ /* Convert size to bytes, subtract the MTU, and then ++ * convert the size to bits. ++ */ ++ size *= 1024; ++ size *= 8; ++ } ++ ++ if (size < 0) { ++ hw_dbg("Invalid effective Rx buffer size %d\n", ++ size); ++ return -IGC_ERR_CONFIG; ++ } ++ ++ /* Calculate the thresholds. Since speed is in Mbps, simplify ++ * the calculation by multiplying size/speed by 1000 for result ++ * to be in nsec before dividing by the scale in nsec. Set the ++ * scale such that the LTR threshold fits in the register. ++ */ ++ ltr_min = (1000 * size) / speed; ++ ltr_max = ltr_min + tw_system; ++ scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 : ++ IGC_LTRMINV_SCALE_32768; ++ scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 : ++ IGC_LTRMAXV_SCALE_32768; ++ ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768; ++ ltr_min -= 1; ++ ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768; ++ ltr_max -= 1; ++ ++ /* Only write the LTR thresholds if they differ from before. */ ++ ltrv = rd32(IGC_LTRMINV); ++ if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) { ++ ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min | ++ (scale_min << IGC_LTRMINV_SCALE_SHIFT); ++ wr32(IGC_LTRMINV, ltrv); ++ } ++ ++ ltrv = rd32(IGC_LTRMAXV); ++ if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) { ++ ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max | ++ (scale_max << IGC_LTRMAXV_SCALE_SHIFT); ++ wr32(IGC_LTRMAXV, ltrv); ++ } ++ } ++ ++ return IGC_SUCCESS; ++} + +--- a/drivers/net/ethernet/intel/igc/igc_i225.h 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_i225.h 2022-03-10 14:33:17.223213194 +0800 +@@ -9,5 +9,8 @@ + + s32 igc_init_nvm_params_i225(struct igc_hw *hw); + bool igc_get_flash_presence_i225(struct igc_hw *hw); ++s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G, ++ bool adv100M); ++s32 igc_set_ltr_i225(struct igc_hw *hw, bool link); + + #endif + +--- a/drivers/net/ethernet/intel/igc/igc_mac.c 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_mac.c 2022-03-10 14:33:17.227212778 +0800 +@@ -235,15 +235,14 @@ + void igc_clear_hw_cntrs_base(struct igc_hw *hw) + { + rd32(IGC_CRCERRS); +- rd32(IGC_SYMERRS); + rd32(IGC_MPC); + rd32(IGC_SCC); + rd32(IGC_ECOL); + rd32(IGC_MCC); + rd32(IGC_LATECOL); + rd32(IGC_COLC); ++ rd32(IGC_RERC); + rd32(IGC_DC); +- rd32(IGC_SEC); + rd32(IGC_RLEC); + rd32(IGC_XONRXC); + rd32(IGC_XONTXC); +@@ -288,31 +287,20 @@ + rd32(IGC_ALGNERRC); + rd32(IGC_RXERRC); + rd32(IGC_TNCRS); +- rd32(IGC_CEXTERR); ++ rd32(IGC_HTDPMC); + rd32(IGC_TSCTC); +- rd32(IGC_TSCTFC); + + rd32(IGC_MGTPRC); + rd32(IGC_MGTPDC); + rd32(IGC_MGTPTC); + + rd32(IGC_IAC); +- rd32(IGC_ICRXOC); +- +- rd32(IGC_ICRXPTC); +- rd32(IGC_ICRXATC); +- rd32(IGC_ICTXPTC); +- rd32(IGC_ICTXATC); +- rd32(IGC_ICTXQEC); +- rd32(IGC_ICTXQMTC); +- rd32(IGC_ICRXDMTC); + +- rd32(IGC_CBTMPC); +- rd32(IGC_HTDPMC); +- rd32(IGC_CBRMPC); + rd32(IGC_RPTHC); ++ rd32(IGC_TLPIC); ++ rd32(IGC_RLPIC); + rd32(IGC_HGPTC); +- rd32(IGC_HTCBDPC); ++ rd32(IGC_RXDMTC); + rd32(IGC_HGORCL); + rd32(IGC_HGORCH); + rd32(IGC_HGOTCL); +@@ -367,8 +355,8 @@ + s32 igc_check_for_copper_link(struct igc_hw *hw) + { + struct igc_mac_info *mac = &hw->mac; ++ bool link = false; + s32 ret_val; +- bool link; + + /* We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The +@@ -422,6 +410,11 @@ + hw_dbg("Error configuring flow control\n"); + + out: ++ /* Now that we are aware of our link settings, we can set the LTR ++ * thresholds. ++ */ ++ ret_val = igc_set_ltr_i225(hw, link); ++ + return ret_val; + } + +@@ -467,10 +460,8 @@ + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ +- if (mac->autoneg_failed) { +- if (hw->phy.media_type == igc_media_type_copper) +- ret_val = igc_force_mac_fc(hw); +- } ++ if (mac->autoneg_failed) ++ ret_val = igc_force_mac_fc(hw); + + if (ret_val) { + hw_dbg("Error forcing flow control settings\n"); +@@ -482,7 +473,7 @@ + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ +- if (hw->phy.media_type == igc_media_type_copper && mac->autoneg) { ++ if (mac->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. +@@ -784,3 +775,107 @@ + out: + return ret_val; + } ++ ++/** ++ * igc_hash_mc_addr - Generate a multicast hash value ++ * @hw: pointer to the HW structure ++ * @mc_addr: pointer to a multicast address ++ * ++ * Generates a multicast address hash value which is used to determine ++ * the multicast filter table array address and new table value. See ++ * igc_mta_set() ++ **/ ++static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr) ++{ ++ u32 hash_value, hash_mask; ++ u8 bit_shift = 0; ++ ++ /* Register count multiplied by bits per register */ ++ hash_mask = (hw->mac.mta_reg_count * 32) - 1; ++ ++ /* For a mc_filter_type of 0, bit_shift is the number of left-shifts ++ * where 0xFF would still fall within the hash mask. ++ */ ++ while (hash_mask >> bit_shift != 0xFF) ++ bit_shift++; ++ ++ /* The portion of the address that is used for the hash table ++ * is determined by the mc_filter_type setting. ++ * The algorithm is such that there is a total of 8 bits of shifting. ++ * The bit_shift for a mc_filter_type of 0 represents the number of ++ * left-shifts where the MSB of mc_addr[5] would still fall within ++ * the hash_mask. Case 0 does this exactly. Since there are a total ++ * of 8 bits of shifting, then mc_addr[4] will shift right the ++ * remaining number of bits. Thus 8 - bit_shift. The rest of the ++ * cases are a variation of this algorithm...essentially raising the ++ * number of bits to shift mc_addr[5] left, while still keeping the ++ * 8-bit shifting total. ++ * ++ * For example, given the following Destination MAC Address and an ++ * MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask), ++ * we can see that the bit_shift for case 0 is 4. These are the hash ++ * values resulting from each mc_filter_type... ++ * [0] [1] [2] [3] [4] [5] ++ * 01 AA 00 12 34 56 ++ * LSB MSB ++ * ++ * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 ++ * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 ++ * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 ++ * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 ++ */ ++ switch (hw->mac.mc_filter_type) { ++ default: ++ case 0: ++ break; ++ case 1: ++ bit_shift += 1; ++ break; ++ case 2: ++ bit_shift += 2; ++ break; ++ case 3: ++ bit_shift += 4; ++ break; ++ } ++ ++ hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | ++ (((u16)mc_addr[5]) << bit_shift))); ++ ++ return hash_value; ++} ++ ++/** ++ * igc_update_mc_addr_list - Update Multicast addresses ++ * @hw: pointer to the HW structure ++ * @mc_addr_list: array of multicast addresses to program ++ * @mc_addr_count: number of multicast addresses to program ++ * ++ * Updates entire Multicast Table Array. ++ * The caller must have a packed mc_addr_list of multicast addresses. ++ **/ ++void igc_update_mc_addr_list(struct igc_hw *hw, ++ u8 *mc_addr_list, u32 mc_addr_count) ++{ ++ u32 hash_value, hash_bit, hash_reg; ++ int i; ++ ++ /* clear mta_shadow */ ++ memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); ++ ++ /* update mta_shadow from mc_addr_list */ ++ for (i = 0; (u32)i < mc_addr_count; i++) { ++ hash_value = igc_hash_mc_addr(hw, mc_addr_list); ++ ++ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); ++ hash_bit = hash_value & 0x1F; ++ ++ hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit); ++ mc_addr_list += ETH_ALEN; ++ } ++ ++ /* replace the entire MTA table */ ++ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) ++ array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]); ++ wrfl(); ++} + +--- a/drivers/net/ethernet/intel/igc/igc_mac.h 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_mac.h 2022-03-10 14:33:17.227212778 +0800 +@@ -8,10 +8,6 @@ + #include "igc_phy.h" + #include "igc_defines.h" + +-#ifndef IGC_REMOVED +-#define IGC_REMOVED(a) (0) +-#endif /* IGC_REMOVED */ +- + /* forward declaration */ + s32 igc_disable_pcie_master(struct igc_hw *hw); + s32 igc_check_for_copper_link(struct igc_hw *hw); +@@ -29,6 +25,8 @@ + u16 *duplex); + + bool igc_enable_mng_pass_thru(struct igc_hw *hw); ++void igc_update_mc_addr_list(struct igc_hw *hw, ++ u8 *mc_addr_list, u32 mc_addr_count); + + enum igc_mng_mode { + igc_mng_mode_none = 0, + +--- a/drivers/net/ethernet/intel/igc/igc_main.c 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_main.c 2022-03-10 14:56:18.814132021 +0800 +@@ -8,13 +8,15 @@ + #include + #include + #include ++#include ++#include + + #include + + #include "igc.h" + #include "igc_hw.h" ++#include "igc_tsn.h" + +-#define DRV_VERSION "0.0.1-k" + #define DRV_SUMMARY "Intel(R) 2.5G Ethernet Linux Driver" + + #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) +@@ -24,12 +26,10 @@ + MODULE_AUTHOR("Intel Corporation, "); + MODULE_DESCRIPTION(DRV_SUMMARY); + MODULE_LICENSE("GPL v2"); +-MODULE_VERSION(DRV_VERSION); + module_param(debug, int, 0); + MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + + char igc_driver_name[] = "igc"; +-char igc_driver_version[] = DRV_VERSION; + static const char igc_driver_string[] = DRV_SUMMARY; + static const char igc_copyright[] = + "Copyright(c) 2018 Intel Corporation."; +@@ -44,31 +44,23 @@ + { 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_K2), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_K), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LMVP), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_LMVP), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_IT), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_LM), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_V), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_IT), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I221_V), board_base }, ++ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I226_BLANK_NVM), 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, +@@ -78,7 +70,7 @@ + + void igc_reset(struct igc_adapter *adapter) + { +- struct pci_dev *pdev = adapter->pdev; ++ struct net_device *dev = adapter->netdev; + struct igc_hw *hw = &adapter->hw; + struct igc_fc_info *fc = &hw->fc; + u32 pba, hwm; +@@ -105,39 +97,37 @@ + hw->mac.ops.reset_hw(hw); + + if (hw->mac.ops.init_hw(hw)) +- dev_err(&pdev->dev, "Hardware Error\n"); ++ netdev_err(dev, "Error on hardware initialization\n"); ++ ++ /* Re-establish EEE setting */ ++ igc_set_eee_i225(hw, true, true, true); + + if (!netif_running(adapter->netdev)) +- igc_power_down_link(adapter); ++ igc_power_down_phy_copper_base(&adapter->hw); ++ ++ /* Re-enable PTP, where applicable. */ ++ igc_ptp_reset(adapter); ++ ++ /* Re-enable TSN offloading, where applicable. */ ++ igc_tsn_offload_apply(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) + { + igc_reset_phy(&adapter->hw); + +- if (adapter->hw.phy.media_type == igc_media_type_copper) +- igc_power_up_phy_copper(&adapter->hw); ++ igc_power_up_phy_copper(&adapter->hw); + + igc_setup_link(&adapter->hw); + } + + /** +- * 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 + * +@@ -150,6 +140,9 @@ + struct igc_hw *hw = &adapter->hw; + u32 ctrl_ext; + ++ if (!pci_device_is_present(adapter->pdev)) ++ return; ++ + /* Let firmware take over control of h/w */ + ctrl_ext = rd32(IGC_CTRL_EXT); + wr32(IGC_CTRL_EXT, +@@ -176,43 +169,6 @@ + } + + /** +- * 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 + */ +@@ -276,6 +232,43 @@ + } + + /** ++ * 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 + */ +@@ -296,6 +289,7 @@ + */ + int igc_setup_tx_resources(struct igc_ring *tx_ring) + { ++ struct net_device *ndev = tx_ring->netdev; + struct device *dev = tx_ring->dev; + int size = 0; + +@@ -321,8 +315,7 @@ + + err: + vfree(tx_ring->tx_buffer_info); +- dev_err(dev, +- "Unable to allocate memory for the transmit descriptor ring\n"); ++ netdev_err(ndev, "Unable to allocate memory for Tx descriptor ring\n"); + return -ENOMEM; + } + +@@ -334,14 +327,13 @@ + */ + static int igc_setup_all_tx_resources(struct igc_adapter *adapter) + { +- struct pci_dev *pdev = adapter->pdev; ++ struct net_device *dev = adapter->netdev; + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = igc_setup_tx_resources(adapter->tx_ring[i]); + if (err) { +- dev_err(&pdev->dev, +- "Allocation for Tx Queue %u failed\n", i); ++ netdev_err(dev, "Error on Tx queue %u setup\n", i); + for (i--; i >= 0; i--) + igc_free_tx_resources(adapter->tx_ring[i]); + break; +@@ -452,6 +444,7 @@ + */ + int igc_setup_rx_resources(struct igc_ring *rx_ring) + { ++ struct net_device *ndev = rx_ring->netdev; + struct device *dev = rx_ring->dev; + int size, desc_len; + +@@ -481,8 +474,7 @@ + err: + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; +- dev_err(dev, +- "Unable to allocate memory for the receive descriptor ring\n"); ++ netdev_err(ndev, "Unable to allocate memory for Rx descriptor ring\n"); + return -ENOMEM; + } + +@@ -495,14 +487,13 @@ + */ + static int igc_setup_all_rx_resources(struct igc_adapter *adapter) + { +- struct pci_dev *pdev = adapter->pdev; ++ struct net_device *dev = adapter->netdev; + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = igc_setup_rx_resources(adapter->rx_ring[i]); + if (err) { +- dev_err(&pdev->dev, +- "Allocation for Rx Queue %u failed\n", i); ++ netdev_err(dev, "Error on Rx queue %u setup\n", i); + for (i--; i >= 0; i--) + igc_free_rx_resources(adapter->rx_ring[i]); + break; +@@ -773,6 +764,79 @@ + } + + /** ++ * igc_set_mac_filter_hw() - Set MAC address filter in hardware ++ * @adapter: Pointer to adapter where the filter should be set ++ * @index: Filter index ++ * @type: MAC address filter type (source or destination) ++ * @addr: MAC address ++ * @queue: If non-negative, queue assignment feature is enabled and frames ++ * matching the filter are enqueued onto 'queue'. Otherwise, queue ++ * assignment is disabled. ++ */ ++static void igc_set_mac_filter_hw(struct igc_adapter *adapter, int index, ++ enum igc_mac_filter_type type, ++ const u8 *addr, int queue) ++{ ++ struct net_device *dev = adapter->netdev; ++ struct igc_hw *hw = &adapter->hw; ++ u32 ral, rah; ++ ++ if (WARN_ON(index >= hw->mac.rar_entry_count)) ++ return; ++ ++ ral = le32_to_cpup((__le32 *)(addr)); ++ rah = le16_to_cpup((__le16 *)(addr + 4)); ++ ++ if (type == IGC_MAC_FILTER_TYPE_SRC) { ++ rah &= ~IGC_RAH_ASEL_MASK; ++ rah |= IGC_RAH_ASEL_SRC_ADDR; ++ } ++ ++ if (queue >= 0) { ++ rah &= ~IGC_RAH_QSEL_MASK; ++ rah |= (queue << IGC_RAH_QSEL_SHIFT); ++ rah |= IGC_RAH_QSEL_ENABLE; ++ } ++ ++ rah |= IGC_RAH_AV; ++ ++ wr32(IGC_RAL(index), ral); ++ wr32(IGC_RAH(index), rah); ++ ++ netdev_dbg(dev, "MAC address filter set in HW: index %d", index); ++} ++ ++/** ++ * igc_clear_mac_filter_hw() - Clear MAC address filter in hardware ++ * @adapter: Pointer to adapter where the filter should be cleared ++ * @index: Filter index ++ */ ++static void igc_clear_mac_filter_hw(struct igc_adapter *adapter, int index) ++{ ++ struct net_device *dev = adapter->netdev; ++ struct igc_hw *hw = &adapter->hw; ++ ++ if (WARN_ON(index >= hw->mac.rar_entry_count)) ++ return; ++ ++ wr32(IGC_RAL(index), 0); ++ wr32(IGC_RAH(index), 0); ++ ++ netdev_dbg(dev, "MAC address filter cleared in HW: index %d", index); ++} ++ ++/* Set default MAC address for the PF in the first RAR entry */ ++static void igc_set_default_mac_filter(struct igc_adapter *adapter) ++{ ++ struct net_device *dev = adapter->netdev; ++ u8 *addr = adapter->hw.mac.addr; ++ ++ netdev_dbg(dev, "Set default MAC address filter: address %pM", addr); ++ ++ igc_set_mac_filter_hw(adapter, 0, IGC_MAC_FILTER_TYPE_DST, addr, -1); ++} ++ ++/** + * igc_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure +@@ -797,6 +861,61 @@ + return 0; + } + ++/** ++ * igc_write_mc_addr_list - write multicast addresses to MTA ++ * @netdev: network interface device structure ++ * ++ * Writes multicast address list to the MTA hash table. ++ * Returns: -ENOMEM on failure ++ * 0 on no addresses written ++ * X on writing X addresses to MTA ++ **/ ++static int igc_write_mc_addr_list(struct net_device *netdev) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ struct igc_hw *hw = &adapter->hw; ++ struct netdev_hw_addr *ha; ++ u8 *mta_list; ++ int i; ++ ++ if (netdev_mc_empty(netdev)) { ++ /* nothing to program, so clear mc list */ ++ igc_update_mc_addr_list(hw, NULL, 0); ++ return 0; ++ } ++ ++ mta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC); ++ if (!mta_list) ++ return -ENOMEM; ++ ++ /* The shared function expects a packed array of only addresses. */ ++ i = 0; ++ netdev_for_each_mc_addr(ha, netdev) ++ memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN); ++ ++ igc_update_mc_addr_list(hw, mta_list, i); ++ kfree(mta_list); ++ ++ return netdev_mc_count(netdev); ++} ++ ++static __le32 igc_tx_launchtime(struct igc_adapter *adapter, ktime_t txtime) ++{ ++ ktime_t cycle_time = adapter->cycle_time; ++ ktime_t base_time = adapter->base_time; ++ u32 launchtime; ++ ++ /* FIXME: when using ETF together with taprio, we may have a ++ * case where 'delta' is larger than the cycle_time, this may ++ * cause problems if we don't read the current value of ++ * IGC_BASET, as the value writen into the launchtime ++ * descriptor field may be misinterpreted. ++ */ ++ div_s64_rem(ktime_sub_ns(txtime, base_time), cycle_time, &launchtime); ++ ++ return cpu_to_le32(launchtime); ++} ++ + static void igc_tx_ctxtdesc(struct igc_ring *tx_ring, + struct igc_tx_buffer *first, + u32 vlan_macip_lens, u32 type_tucmd, +@@ -804,7 +923,6 @@ + { + struct igc_adv_tx_context_desc *context_desc; + u16 i = tx_ring->next_to_use; +- struct timespec64 ts; + + context_desc = IGC_TX_CTXTDESC(tx_ring, i); + +@@ -814,7 +932,7 @@ + /* 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; + +@@ -826,9 +944,12 @@ + * should have been handled by the upper layers. + */ + if (tx_ring->launchtime_enable) { +- ts = ktime_to_timespec64(first->skb->tstamp); ++ struct igc_adapter *adapter = netdev_priv(tx_ring->netdev); ++ ktime_t txtime = first->skb->tstamp; ++ + first->skb->tstamp = ktime_set(0, 0); +- context_desc->launch_time = cpu_to_le32(ts.tv_nsec / 32); ++ context_desc->launch_time = igc_tx_launchtime(adapter, ++ txtime); + } else { + context_desc->launch_time = 0; + } +@@ -860,7 +981,7 @@ + switch (skb->csum_offset) { + case offsetof(struct tcphdr, check): + type_tucmd = IGC_ADVTXD_TUCMD_L4T_TCP; +- /* fall through */ ++ fallthrough; + case offsetof(struct udphdr, check): + break; + case offsetof(struct sctphdr, checksum): +@@ -872,7 +993,7 @@ + type_tucmd = IGC_ADVTXD_TUCMD_L4T_SCTP; + break; + } +- /* fall through */ ++ fallthrough; + default: + skb_checksum_help(skb); + goto csum_failed; +@@ -921,6 +1042,11 @@ + 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 */ +@@ -928,6 +1054,14 @@ + 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; + } + +@@ -1063,7 +1197,7 @@ + + return 0; + dma_error: +- dev_err(tx_ring->dev, "TX DMA map failed\n"); ++ netdev_err(tx_ring->netdev, "TX DMA map failed\n"); + tx_buffer = &tx_ring->tx_buffer_info[i]; + + /* clear dma mappings for failed tx_buffer_info map */ +@@ -1095,6 +1229,100 @@ + 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) + { +@@ -1104,6 +1332,7 @@ + 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, +@@ -1126,15 +1355,45 @@ + 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, +@@ -1165,6 +1424,46 @@ + return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb)); + } + ++static void igc_rx_checksum(struct igc_ring *ring, ++ union igc_adv_rx_desc *rx_desc, ++ struct sk_buff *skb) ++{ ++ skb_checksum_none_assert(skb); ++ ++ /* Ignore Checksum bit is set */ ++ if (igc_test_staterr(rx_desc, IGC_RXD_STAT_IXSM)) ++ return; ++ ++ /* Rx checksum disabled via ethtool */ ++ if (!(ring->netdev->features & NETIF_F_RXCSUM)) ++ return; ++ ++ /* TCP/UDP checksum error bit is set */ ++ if (igc_test_staterr(rx_desc, ++ IGC_RXDEXT_STATERR_L4E | ++ IGC_RXDEXT_STATERR_IPE)) { ++ /* work around errata with sctp packets where the TCPE aka ++ * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) ++ * packets (aka let the stack check the crc32c) ++ */ ++ if (!(skb->len == 60 && ++ test_bit(IGC_RING_FLAG_RX_SCTP_CSUM, &ring->flags))) { ++ u64_stats_update_begin(&ring->rx_syncp); ++ ring->rx_stats.csum_err++; ++ u64_stats_update_end(&ring->rx_syncp); ++ } ++ /* let the stack verify checksum errors */ ++ return; ++ } ++ /* It must be a TCP or UDP packet with a valid checksum */ ++ if (igc_test_staterr(rx_desc, IGC_RXD_STAT_TCPCS | ++ IGC_RXD_STAT_UDPCS)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ ++ netdev_dbg(ring->netdev, "cksum success: bits %08X\n", ++ le32_to_cpu(rx_desc->wb.upper.status_error)); ++} ++ + static inline void igc_rx_hash(struct igc_ring *ring, + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) +@@ -1181,9 +1480,9 @@ + * @rx_desc: pointer to the EOP Rx descriptor + * @skb: pointer to current skb being populated + * +- * This function checks the ring, descriptor, and packet information in +- * order to populate the hash, checksum, VLAN, timestamp, protocol, and +- * other fields within the skb. ++ * This function checks the ring, descriptor, and packet information in order ++ * to populate the hash, checksum, VLAN, protocol, and other fields within the ++ * skb. + */ + static void igc_process_skb_fields(struct igc_ring *rx_ring, + union igc_adv_rx_desc *rx_desc, +@@ -1191,6 +1490,8 @@ + { + igc_rx_hash(rx_ring, rx_desc, skb); + ++ igc_rx_checksum(rx_ring, rx_desc, skb); ++ + skb_record_rx_queue(skb, rx_ring->queue_index); + + skb->protocol = eth_type_trans(skb, rx_ring->netdev); +@@ -1310,6 +1611,12 @@ + 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) +@@ -1407,7 +1714,6 @@ + * 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 +@@ -1449,8 +1755,7 @@ + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) + { +- if (unlikely((igc_test_staterr(rx_desc, +- IGC_RXDEXT_ERR_FRAME_ERR_MASK)))) { ++ if (unlikely(igc_test_staterr(rx_desc, IGC_RXDEXT_STATERR_RXE))) { + struct net_device *netdev = rx_ring->netdev; + + if (!(netdev->features & NETIF_F_RXALL)) { +@@ -1487,9 +1792,56 @@ + 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) + { +@@ -1619,7 +1971,7 @@ + /* probably a little skewed due to removing CRC */ + total_bytes += skb->len; + +- /* populate checksum, timestamp, VLAN, and protocol */ ++ /* populate checksum, VLAN, and protocol */ + igc_process_skb_fields(rx_ring, rx_desc, skb); + + napi_gro_receive(&q_vector->napi, skb); +@@ -1647,52 +1999,6 @@ + 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 +@@ -1812,27 +2118,27 @@ + (adapter->tx_timeout_factor * HZ)) && + !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF)) { + /* detected Tx unit hang */ +- dev_err(tx_ring->dev, +- "Detected Tx Unit Hang\n" +- " Tx Queue <%d>\n" +- " TDH <%x>\n" +- " TDT <%x>\n" +- " next_to_use <%x>\n" +- " next_to_clean <%x>\n" +- "buffer_info[next_to_clean]\n" +- " time_stamp <%lx>\n" +- " next_to_watch <%p>\n" +- " jiffies <%lx>\n" +- " desc.status <%x>\n", +- tx_ring->queue_index, +- rd32(IGC_TDH(tx_ring->reg_idx)), +- readl(tx_ring->tail), +- tx_ring->next_to_use, +- tx_ring->next_to_clean, +- tx_buffer->time_stamp, +- tx_buffer->next_to_watch, +- jiffies, +- tx_buffer->next_to_watch->wb.status); ++ netdev_err(tx_ring->netdev, ++ "Detected Tx Unit Hang\n" ++ " Tx Queue <%d>\n" ++ " TDH <%x>\n" ++ " TDT <%x>\n" ++ " next_to_use <%x>\n" ++ " next_to_clean <%x>\n" ++ "buffer_info[next_to_clean]\n" ++ " time_stamp <%lx>\n" ++ " next_to_watch <%p>\n" ++ " jiffies <%lx>\n" ++ " desc.status <%x>\n", ++ tx_ring->queue_index, ++ rd32(IGC_TDH(tx_ring->reg_idx)), ++ readl(tx_ring->tail), ++ tx_ring->next_to_use, ++ tx_ring->next_to_clean, ++ tx_buffer->time_stamp, ++ tx_buffer->next_to_watch, ++ jiffies, ++ tx_buffer->next_to_watch->wb.status); + netif_stop_subqueue(tx_ring->netdev, + tx_ring->queue_index); + +@@ -1864,6 +2170,1416 @@ + return !!budget; + } + ++static int igc_find_mac_filter(struct igc_adapter *adapter, ++ enum igc_mac_filter_type type, const u8 *addr) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int max_entries = hw->mac.rar_entry_count; ++ u32 ral, rah; ++ int i; ++ ++ for (i = 0; i < max_entries; i++) { ++ ral = rd32(IGC_RAL(i)); ++ rah = rd32(IGC_RAH(i)); ++ ++ if (!(rah & IGC_RAH_AV)) ++ continue; ++ if (!!(rah & IGC_RAH_ASEL_SRC_ADDR) != type) ++ continue; ++ if ((rah & IGC_RAH_RAH_MASK) != ++ le16_to_cpup((__le16 *)(addr + 4))) ++ continue; ++ if (ral != le32_to_cpup((__le32 *)(addr))) ++ continue; ++ ++ return i; ++ } ++ ++ return -1; ++} ++ ++static int igc_get_avail_mac_filter_slot(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int max_entries = hw->mac.rar_entry_count; ++ u32 rah; ++ int i; ++ ++ for (i = 0; i < max_entries; i++) { ++ rah = rd32(IGC_RAH(i)); ++ ++ if (!(rah & IGC_RAH_AV)) ++ return i; ++ } ++ ++ return -1; ++} ++ ++/** ++ * igc_add_mac_filter() - Add MAC address filter ++ * @adapter: Pointer to adapter where the filter should be added ++ * @type: MAC address filter type (source or destination) ++ * @addr: MAC address ++ * @queue: If non-negative, queue assignment feature is enabled and frames ++ * matching the filter are enqueued onto 'queue'. Otherwise, queue ++ * assignment is disabled. ++ * ++ * Return: 0 in case of success, negative errno code otherwise. ++ */ ++static int igc_add_mac_filter(struct igc_adapter *adapter, ++ enum igc_mac_filter_type type, const u8 *addr, ++ int queue) ++{ ++ struct net_device *dev = adapter->netdev; ++ int index; ++ ++ index = igc_find_mac_filter(adapter, type, addr); ++ if (index >= 0) ++ goto update_filter; ++ ++ index = igc_get_avail_mac_filter_slot(adapter); ++ if (index < 0) ++ return -ENOSPC; ++ ++ netdev_dbg(dev, "Add MAC address filter: index %d type %s address %pM queue %d\n", ++ index, type == IGC_MAC_FILTER_TYPE_DST ? "dst" : "src", ++ addr, queue); ++ ++update_filter: ++ igc_set_mac_filter_hw(adapter, index, type, addr, queue); ++ return 0; ++} ++ ++/** ++ * igc_del_mac_filter() - Delete MAC address filter ++ * @adapter: Pointer to adapter where the filter should be deleted from ++ * @type: MAC address filter type (source or destination) ++ * @addr: MAC address ++ */ ++static void igc_del_mac_filter(struct igc_adapter *adapter, ++ enum igc_mac_filter_type type, const u8 *addr) ++{ ++ struct net_device *dev = adapter->netdev; ++ int index; ++ ++ index = igc_find_mac_filter(adapter, type, addr); ++ if (index < 0) ++ return; ++ ++ if (index == 0) { ++ /* If this is the default filter, we don't actually delete it. ++ * We just reset to its default value i.e. disable queue ++ * assignment. ++ */ ++ netdev_dbg(dev, "Disable default MAC filter queue assignment"); ++ ++ igc_set_mac_filter_hw(adapter, 0, type, addr, -1); ++ } else { ++ netdev_dbg(dev, "Delete MAC address filter: index %d type %s address %pM\n", ++ index, ++ type == IGC_MAC_FILTER_TYPE_DST ? "dst" : "src", ++ addr); ++ ++ igc_clear_mac_filter_hw(adapter, index); ++ } ++} ++ ++/** ++ * igc_add_vlan_prio_filter() - Add VLAN priority filter ++ * @adapter: Pointer to adapter where the filter should be added ++ * @prio: VLAN priority value ++ * @queue: Queue number which matching frames are assigned to ++ * ++ * Return: 0 in case of success, negative errno code otherwise. ++ */ ++static int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, ++ int queue) ++{ ++ struct net_device *dev = adapter->netdev; ++ struct igc_hw *hw = &adapter->hw; ++ u32 vlanpqf; ++ ++ vlanpqf = rd32(IGC_VLANPQF); ++ ++ if (vlanpqf & IGC_VLANPQF_VALID(prio)) { ++ netdev_dbg(dev, "VLAN priority filter already in use\n"); ++ return -EEXIST; ++ } ++ ++ vlanpqf |= IGC_VLANPQF_QSEL(prio, queue); ++ vlanpqf |= IGC_VLANPQF_VALID(prio); ++ ++ wr32(IGC_VLANPQF, vlanpqf); ++ ++ netdev_dbg(dev, "Add VLAN priority filter: prio %d queue %d\n", ++ prio, queue); ++ return 0; ++} ++ ++/** ++ * igc_del_vlan_prio_filter() - Delete VLAN priority filter ++ * @adapter: Pointer to adapter where the filter should be deleted from ++ * @prio: VLAN priority value ++ */ ++static void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 vlanpqf; ++ ++ vlanpqf = rd32(IGC_VLANPQF); ++ ++ vlanpqf &= ~IGC_VLANPQF_VALID(prio); ++ vlanpqf &= ~IGC_VLANPQF_QSEL(prio, IGC_VLANPQF_QUEUE_MASK); ++ ++ wr32(IGC_VLANPQF, vlanpqf); ++ ++ netdev_dbg(adapter->netdev, "Delete VLAN priority filter: prio %d\n", ++ prio); ++} ++ ++static int igc_get_avail_etype_filter_slot(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int i; ++ ++ for (i = 0; i < MAX_ETYPE_FILTER; i++) { ++ u32 etqf = rd32(IGC_ETQF(i)); ++ ++ if (!(etqf & IGC_ETQF_FILTER_ENABLE)) ++ return i; ++ } ++ ++ return -1; ++} ++ ++/** ++ * igc_add_etype_filter() - Add ethertype filter ++ * @adapter: Pointer to adapter where the filter should be added ++ * @etype: Ethertype value ++ * @queue: If non-negative, queue assignment feature is enabled and frames ++ * matching the filter are enqueued onto 'queue'. Otherwise, queue ++ * assignment is disabled. ++ * ++ * Return: 0 in case of success, negative errno code otherwise. ++ */ ++static int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype, ++ int queue) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int index; ++ u32 etqf; ++ ++ index = igc_get_avail_etype_filter_slot(adapter); ++ if (index < 0) ++ return -ENOSPC; ++ ++ etqf = rd32(IGC_ETQF(index)); ++ ++ etqf &= ~IGC_ETQF_ETYPE_MASK; ++ etqf |= etype; ++ ++ if (queue >= 0) { ++ etqf &= ~IGC_ETQF_QUEUE_MASK; ++ etqf |= (queue << IGC_ETQF_QUEUE_SHIFT); ++ etqf |= IGC_ETQF_QUEUE_ENABLE; ++ } ++ ++ etqf |= IGC_ETQF_FILTER_ENABLE; ++ ++ wr32(IGC_ETQF(index), etqf); ++ ++ netdev_dbg(adapter->netdev, "Add ethertype filter: etype %04x queue %d\n", ++ etype, queue); ++ return 0; ++} ++ ++static int igc_find_etype_filter(struct igc_adapter *adapter, u16 etype) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int i; ++ ++ for (i = 0; i < MAX_ETYPE_FILTER; i++) { ++ u32 etqf = rd32(IGC_ETQF(i)); ++ ++ if ((etqf & IGC_ETQF_ETYPE_MASK) == etype) ++ return i; ++ } ++ ++ return -1; ++} ++ ++/** ++ * igc_del_etype_filter() - Delete ethertype filter ++ * @adapter: Pointer to adapter where the filter should be deleted from ++ * @etype: Ethertype value ++ */ ++static void igc_del_etype_filter(struct igc_adapter *adapter, u16 etype) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int index; ++ ++ index = igc_find_etype_filter(adapter, etype); ++ if (index < 0) ++ return; ++ ++ wr32(IGC_ETQF(index), 0); ++ ++ netdev_dbg(adapter->netdev, "Delete ethertype filter: etype %04x\n", ++ etype); ++} ++ ++static int igc_enable_nfc_rule(struct igc_adapter *adapter, ++ const struct igc_nfc_rule *rule) ++{ ++ int err; ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { ++ err = igc_add_etype_filter(adapter, rule->filter.etype, ++ rule->action); ++ if (err) ++ return err; ++ } ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { ++ err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC, ++ rule->filter.src_addr, rule->action); ++ if (err) ++ return err; ++ } ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { ++ err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, ++ rule->filter.dst_addr, rule->action); ++ if (err) ++ return err; ++ } ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { ++ int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >> ++ VLAN_PRIO_SHIFT; ++ ++ err = igc_add_vlan_prio_filter(adapter, prio, rule->action); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void igc_disable_nfc_rule(struct igc_adapter *adapter, ++ const struct igc_nfc_rule *rule) ++{ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) ++ igc_del_etype_filter(adapter, rule->filter.etype); ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { ++ int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >> ++ VLAN_PRIO_SHIFT; ++ ++ igc_del_vlan_prio_filter(adapter, prio); ++ } ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) ++ igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC, ++ rule->filter.src_addr); ++ ++ if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) ++ igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, ++ rule->filter.dst_addr); ++} ++ ++/** ++ * igc_get_nfc_rule() - Get NFC rule ++ * @adapter: Pointer to adapter ++ * @location: Rule location ++ * ++ * Context: Expects adapter->nfc_rule_lock to be held by caller. ++ * ++ * Return: Pointer to NFC rule at @location. If not found, NULL. ++ */ ++struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter, ++ u32 location) ++{ ++ struct igc_nfc_rule *rule; ++ ++ list_for_each_entry(rule, &adapter->nfc_rule_list, list) { ++ if (rule->location == location) ++ return rule; ++ if (rule->location > location) ++ break; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * igc_del_nfc_rule() - Delete NFC rule ++ * @adapter: Pointer to adapter ++ * @rule: Pointer to rule to be deleted ++ * ++ * Disable NFC rule in hardware and delete it from adapter. ++ * ++ * Context: Expects adapter->nfc_rule_lock to be held by caller. ++ */ ++void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule) ++{ ++ igc_disable_nfc_rule(adapter, rule); ++ ++ list_del(&rule->list); ++ adapter->nfc_rule_count--; ++ ++ kfree(rule); ++} ++ ++static void igc_flush_nfc_rules(struct igc_adapter *adapter) ++{ ++ struct igc_nfc_rule *rule, *tmp; ++ ++ mutex_lock(&adapter->nfc_rule_lock); ++ ++ list_for_each_entry_safe(rule, tmp, &adapter->nfc_rule_list, list) ++ igc_del_nfc_rule(adapter, rule); ++ ++ mutex_unlock(&adapter->nfc_rule_lock); ++} ++ ++/** ++ * igc_add_nfc_rule() - Add NFC rule ++ * @adapter: Pointer to adapter ++ * @rule: Pointer to rule to be added ++ * ++ * Enable NFC rule in hardware and add it to adapter. ++ * ++ * Context: Expects adapter->nfc_rule_lock to be held by caller. ++ * ++ * Return: 0 on success, negative errno on failure. ++ */ ++int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule) ++{ ++ struct igc_nfc_rule *pred, *cur; ++ int err; ++ ++ err = igc_enable_nfc_rule(adapter, rule); ++ if (err) ++ return err; ++ ++ pred = NULL; ++ list_for_each_entry(cur, &adapter->nfc_rule_list, list) { ++ if (cur->location >= rule->location) ++ break; ++ pred = cur; ++ } ++ ++ list_add(&rule->list, pred ? &pred->list : &adapter->nfc_rule_list); ++ adapter->nfc_rule_count++; ++ return 0; ++} ++ ++static void igc_restore_nfc_rules(struct igc_adapter *adapter) ++{ ++ struct igc_nfc_rule *rule; ++ ++ mutex_lock(&adapter->nfc_rule_lock); ++ ++ list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list) ++ igc_enable_nfc_rule(adapter, rule); ++ ++ mutex_unlock(&adapter->nfc_rule_lock); ++} ++ ++static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ ++ return igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, addr, -1); ++} ++ ++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, IGC_MAC_FILTER_TYPE_DST, addr); ++ 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_set_default_mac_filter(adapter); ++ igc_restore_nfc_rules(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) ++{ ++ return IGC_MAX_RX_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: ++ 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 net_device *dev = adapter->netdev; ++ int err = 0; ++ ++ igc_set_interrupt_capability(adapter, msix); ++ ++ err = igc_alloc_q_vectors(adapter); ++ if (err) { ++ netdev_err(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; ++ ++ 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; ++ ++ mutex_init(&adapter->nfc_rule_lock); ++ INIT_LIST_HEAD(&adapter->nfc_rule_list); ++ adapter->nfc_rule_count = 0; ++ ++ spin_lock_init(&adapter->stats64_lock); ++ /* Assume MSI-X interrupts, will be checked during IRQ allocation */ ++ adapter->flags |= IGC_FLAG_HAS_MSIX; ++ ++ igc_init_queue_configuration(adapter); ++ ++ /* This call may decrease the number of queues */ ++ if (igc_init_interrupt_scheme(adapter, true)) { ++ netdev_err(netdev, "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 +@@ -1980,8 +3696,8 @@ + adapter->stats.prc511 += rd32(IGC_PRC511); + adapter->stats.prc1023 += rd32(IGC_PRC1023); + adapter->stats.prc1522 += rd32(IGC_PRC1522); +- adapter->stats.symerrs += rd32(IGC_SYMERRS); +- adapter->stats.sec += rd32(IGC_SEC); ++ adapter->stats.tlpic += rd32(IGC_TLPIC); ++ adapter->stats.rlpic += rd32(IGC_RLPIC); + + mpc = rd32(IGC_MPC); + adapter->stats.mpc += mpc; +@@ -2020,21 +3736,13 @@ + + adapter->stats.tpt += rd32(IGC_TPT); + adapter->stats.colc += rd32(IGC_COLC); ++ adapter->stats.colc += rd32(IGC_RERC); + + adapter->stats.algnerrc += rd32(IGC_ALGNERRC); + + adapter->stats.tsctc += rd32(IGC_TSCTC); +- adapter->stats.tsctfc += rd32(IGC_TSCTFC); + + adapter->stats.iac += rd32(IGC_IAC); +- adapter->stats.icrxoc += rd32(IGC_ICRXOC); +- adapter->stats.icrxptc += rd32(IGC_ICRXPTC); +- adapter->stats.icrxatc += rd32(IGC_ICRXATC); +- adapter->stats.ictxptc += rd32(IGC_ICTXPTC); +- adapter->stats.ictxatc += rd32(IGC_ICTXATC); +- adapter->stats.ictxqec += rd32(IGC_ICTXQEC); +- adapter->stats.ictxqmtc += rd32(IGC_ICTXQMTC); +- adapter->stats.icrxdmtc += rd32(IGC_ICRXDMTC); + + /* Fill out the OS statistics structure */ + net_stats->multicast = adapter->stats.mprc; +@@ -2070,33 +3778,6 @@ + adapter->stats.mgpdc += rd32(IGC_MGTPDC); + } + +-static void igc_nfc_filter_exit(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_erase_filter(adapter, rule); +- +- hlist_for_each_entry(rule, &adapter->cls_flower_list, nfc_node) +- igc_erase_filter(adapter, rule); +- +- 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 +@@ -2110,28 +3791,31 @@ + + set_bit(__IGC_DOWN, &adapter->state); + +- /* disable receives in the hardware */ +- rctl = rd32(IGC_RCTL); +- wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); +- /* flush and sleep below */ +- +- igc_nfc_filter_exit(adapter); ++ igc_ptp_suspend(adapter); + ++ if (pci_device_is_present(adapter->pdev)) { ++ /* disable receives in the hardware */ ++ rctl = rd32(IGC_RCTL); ++ wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); ++ /* flush and sleep below */ ++ } + /* set trans_start so we don't get spurious watchdogs during reset */ + netif_trans_update(netdev); + + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); + +- /* disable transmits in the hardware */ +- tctl = rd32(IGC_TCTL); +- tctl &= ~IGC_TCTL_EN; +- wr32(IGC_TCTL, tctl); +- /* flush both disables and wait for them to finish */ +- wrfl(); +- usleep_range(10000, 20000); ++ if (pci_device_is_present(adapter->pdev)) { ++ /* disable transmits in the hardware */ ++ tctl = rd32(IGC_TCTL); ++ tctl &= ~IGC_TCTL_EN; ++ wr32(IGC_TCTL, tctl); ++ /* flush both disables and wait for them to finish */ ++ wrfl(); ++ usleep_range(10000, 20000); + +- igc_irq_disable(adapter); ++ igc_irq_disable(adapter); ++ } + + adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE; + +@@ -2165,7 +3849,6 @@ + + void igc_reinit_locked(struct igc_adapter *adapter) + { +- WARN_ON(in_interrupt()); + while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) + usleep_range(1000, 2000); + igc_down(adapter); +@@ -2179,8 +3862,19 @@ + + adapter = container_of(work, struct igc_adapter, reset_task); + ++ rtnl_lock(); ++ /* If we're already down or resetting, just bail */ ++ if (test_bit(__IGC_DOWN, &adapter->state) || ++ test_bit(__IGC_RESETTING, &adapter->state)) { ++ rtnl_unlock(); ++ return; ++ } ++ ++ igc_rings_dump(adapter); ++ igc_regs_dump(adapter); + netdev_err(adapter->netdev, "Reset adapter\n"); + igc_reinit_locked(adapter); ++ rtnl_unlock(); + } + + /** +@@ -2194,7 +3888,6 @@ + { + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + struct igc_adapter *adapter = netdev_priv(netdev); +- struct pci_dev *pdev = adapter->pdev; + + /* adjust max frame to be at least the size of a standard frame */ + if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN)) +@@ -2209,8 +3902,7 @@ + if (netif_running(netdev)) + igc_down(adapter); + +- dev_info(&pdev->dev, "changing MTU from %d to %d\n", +- netdev->mtu, new_mtu); ++ netdev_dbg(netdev, "changing MTU from %d to %d\n", netdev->mtu, new_mtu); + netdev->mtu = new_mtu; + + if (netif_running(netdev)) +@@ -2267,20 +3959,8 @@ + if (!(changed & (NETIF_F_RXALL | NETIF_F_NTUPLE))) + return 0; + +- if (!(features & NETIF_F_NTUPLE)) { +- struct hlist_node *node2; +- struct igc_nfc_filter *rule; +- +- spin_lock(&adapter->nfc_lock); +- hlist_for_each_entry_safe(rule, node2, +- &adapter->nfc_filter_list, nfc_node) { +- igc_erase_filter(adapter, rule); +- hlist_del(&rule->nfc_node); +- kfree(rule); +- } +- spin_unlock(&adapter->nfc_lock); +- adapter->nfc_filter_count = 0; +- } ++ if (!(features & NETIF_F_NTUPLE)) ++ igc_flush_nfc_rules(adapter); + + netdev->features = features; + +@@ -2323,216 +4003,20 @@ + return features; + } + +-/** +- * igc_configure - configure the hardware for RX and TX +- * @adapter: private board structure +- */ +-static void igc_configure(struct igc_adapter *adapter) ++static void igc_tsync_interrupt(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; ++ u32 tsicr = rd32(IGC_TSICR); ++ u32 ack = 0; + +- /* 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; ++ if (tsicr & IGC_TSICR_TXTS) { ++ /* retrieve hardware timestamp */ ++ schedule_work(&adapter->ptp_tx_work); ++ ack |= IGC_TSICR_TXTS; + } + +- 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 +- * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used. +- */ +-static int igc_add_mac_filter_flags(struct igc_adapter *adapter, +- const u8 *addr, const u8 queue, +- const u8 flags) +-{ +- 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, flags)) +- 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 | flags; +- +- igc_rar_set_index(adapter, i); +- return i; +- } +- +- return -ENOSPC; +-} +- +-int igc_add_mac_steering_filter(struct igc_adapter *adapter, +- const u8 *addr, u8 queue, u8 flags) +-{ +- return igc_add_mac_filter_flags(adapter, addr, queue, +- IGC_MAC_STATE_QUEUE_STEERING | flags); +-} +- +-/* 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_flags(struct igc_adapter *adapter, +- const u8 *addr, const u8 queue, +- const u8 flags) +-{ +- 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 & flags) != flags) +- 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; +- } 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; +-} +- +-int igc_del_mac_steering_filter(struct igc_adapter *adapter, +- const u8 *addr, u8 queue, u8 flags) +-{ +- return igc_del_mac_filter_flags(adapter, addr, queue, +- IGC_MAC_STATE_QUEUE_STEERING | flags); +-} +- +-/** +- * 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) +-{ ++ /* acknowledge the interrupts */ ++ wr32(IGC_TSICR, ack); + } + + /** +@@ -2562,114 +4046,28 @@ + 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) +@@ -2751,49 +4149,6 @@ + } + + /** +- * 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 + * +@@ -2806,48 +4161,6 @@ + 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 + */ +@@ -2872,20 +4185,12 @@ + * false until the igc_check_for_link establishes link + * for copper adapters ONLY + */ +- switch (hw->phy.media_type) { +- case igc_media_type_copper: +- if (!hw->mac.get_link_status) +- return true; +- hw->mac.ops.check_for_link(hw); +- link_active = !hw->mac.get_link_status; +- break; +- default: +- case igc_media_type_unknown: +- break; +- } ++ if (!hw->mac.get_link_status) ++ return true; ++ hw->mac.ops.check_for_link(hw); ++ link_active = !hw->mac.get_link_status; + +- if (hw->mac.type == igc_i225 && +- hw->phy.id == I225_I_PHY_ID) { ++ if (hw->mac.type == igc_i225) { + if (!netif_carrier_ok(adapter->netdev)) { + adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE; + } else if (!(adapter->flags & IGC_FLAG_NEED_LINK_UPDATE)) { +@@ -2899,7 +4204,7 @@ + + /** + * 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) + { +@@ -2917,7 +4222,6 @@ + struct igc_hw *hw = &adapter->hw; + struct igc_phy_info *phy = &hw->phy; + u16 phy_data, retry_count = 20; +- u32 connsw; + u32 link; + int i; + +@@ -2930,15 +4234,10 @@ + link = false; + } + +- /* Force link down if we have fiber to swap to */ +- if (adapter->flags & IGC_FLAG_MAS_ENABLE) { +- if (hw->phy.media_type == igc_media_type_copper) { +- connsw = rd32(IGC_CONNSW); +- if (!(connsw & IGC_CONNSW_AUTOSENSE_EN)) +- link = 0; +- } +- } + if (link) { ++ /* Cancel scheduled suspend requests. */ ++ pm_runtime_resume(netdev->dev.parent); ++ + if (!netif_carrier_ok(netdev)) { + u32 ctrl; + +@@ -2949,8 +4248,7 @@ + ctrl = rd32(IGC_CTRL); + /* Link status message must follow this format */ + netdev_info(netdev, +- "igc: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n", +- netdev->name, ++ "NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n", + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full" : "Half", +@@ -2959,6 +4257,15 @@ + (ctrl & IGC_CTRL_RFCE) ? "RX" : + (ctrl & IGC_CTRL_TFCE) ? "TX" : "None"); + ++ /* disable EEE if enabled */ ++ if ((adapter->flags & IGC_FLAG_EEE) && ++ adapter->link_duplex == HALF_DUPLEX) { ++ netdev_info(netdev, ++ "EEE Disabled: unsupported at half duplex. Re-enable using ethtool when at full duplex\n"); ++ adapter->hw.dev_spec._base.eee_enable = false; ++ adapter->flags &= ~IGC_FLAG_EEE; ++ } ++ + /* check if SmartSpeed worked */ + igc_check_downshift(hw); + if (phy->speed_downgraded) +@@ -2971,7 +4278,9 @@ + adapter->tx_timeout_factor = 14; + break; + case SPEED_100: +- /* maybe add some timeout factor ? */ ++ case SPEED_1000: ++ case SPEED_2500: ++ adapter->tx_timeout_factor = 7; + break; + } + +@@ -2988,10 +4297,10 @@ + retry_count--; + goto retry_read_status; + } else if (!retry_count) { +- dev_err(&adapter->pdev->dev, "exceed max 2 second\n"); ++ netdev_err(netdev, "exceed max 2 second\n"); + } + } else { +- dev_err(&adapter->pdev->dev, "read 1000Base-T Status Reg\n"); ++ netdev_err(netdev, "read 1000Base-T Status Reg\n"); + } + no_wait: + netif_carrier_on(netdev); +@@ -3007,8 +4316,7 @@ + adapter->link_duplex = 0; + + /* Links status message must follow this format */ +- netdev_info(netdev, "igc: %s NIC Link is Down\n", +- netdev->name); ++ netdev_info(netdev, "NIC Link is Down\n"); + netif_carrier_off(netdev); + + /* link state has changed, schedule phy info update */ +@@ -3024,6 +4332,8 @@ + return; + } + } ++ pm_schedule_suspend(netdev->dev.parent, ++ MSEC_PER_SEC * 5); + + /* also check for alternate media here */ + } else if (!netif_carrier_ok(netdev) && +@@ -3072,6 +4382,8 @@ + 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) +@@ -3084,149 +4396,6 @@ + } + + /** +- * 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 +@@ -3255,6 +4424,9 @@ + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + ++ if (icr & IGC_ICR_TS) ++ igc_tsync_interrupt(adapter); ++ + napi_schedule(&q_vector->napi); + + return IRQ_HANDLED; +@@ -3298,429 +4470,14 @@ + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + ++ if (icr & IGC_ICR_TS) ++ igc_tsync_interrupt(adapter); ++ + napi_schedule(&q_vector->napi); + + 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) { +@@ -3737,62 +4494,6 @@ + } + + /** +- * 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 + * +@@ -3839,32 +4540,16 @@ + netdev->name, adapter); + + if (err) +- dev_err(&pdev->dev, "Error %d getting interrupt\n", +- err); ++ netdev_err(netdev, "Error %d getting interrupt\n", err); + + 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 + * +@@ -3877,6 +4562,7 @@ + static int __igc_open(struct net_device *netdev, bool resuming) + { + struct igc_adapter *adapter = netdev_priv(netdev); ++ struct pci_dev *pdev = adapter->pdev; + struct igc_hw *hw = &adapter->hw; + int err = 0; + int i = 0; +@@ -3888,6 +4574,9 @@ + return -EBUSY; + } + ++ if (!resuming) ++ pm_runtime_get_sync(&pdev->dev); ++ + netif_carrier_off(netdev); + + /* allocate transmit descriptors */ +@@ -3926,6 +4615,9 @@ + rd32(IGC_ICR); + igc_irq_enable(adapter); + ++ if (!resuming) ++ pm_runtime_put(&pdev->dev); ++ + netif_tx_start_all_queues(netdev); + + /* start the watchdog. */ +@@ -3938,24 +4630,27 @@ + igc_free_irq(adapter); + err_req_irq: + igc_release_hw_control(adapter); +- igc_power_down_link(adapter); ++ igc_power_down_phy_copper_base(&adapter->hw); + igc_free_all_rx_resources(adapter); + err_setup_rx: + igc_free_all_tx_resources(adapter); + err_setup_tx: + igc_reset(adapter); ++ if (!resuming) ++ pm_runtime_put(&pdev->dev); + + return err; + } + +-static int igc_open(struct net_device *netdev) ++int igc_open(struct net_device *netdev) + { + return __igc_open(netdev, false); + } + + /** +- * 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 + * +@@ -3967,9 +4662,13 @@ + static int __igc_close(struct net_device *netdev, bool suspending) + { + struct igc_adapter *adapter = netdev_priv(netdev); ++ struct pci_dev *pdev = adapter->pdev; + + WARN_ON(test_bit(__IGC_RESETTING, &adapter->state)); + ++ if (!suspending) ++ pm_runtime_get_sync(&pdev->dev); ++ + igc_down(adapter); + + igc_release_hw_control(adapter); +@@ -3979,26 +4678,223 @@ + igc_free_all_tx_resources(adapter); + igc_free_all_rx_resources(adapter); + ++ if (!suspending) ++ pm_runtime_put_sync(&pdev->dev); ++ + return 0; + } + +-static int igc_close(struct net_device *netdev) ++int igc_close(struct net_device *netdev) + { + if (netif_device_present(netdev) || netdev->dismantle) + return __igc_close(netdev, false); + return 0; + } + ++/** ++ * igc_ioctl - Access the hwtstamp interface ++ * @netdev: network interface device structure ++ * @ifr: 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 int igc_save_launchtime_params(struct igc_adapter *adapter, int queue, ++ bool enable) ++{ ++ struct igc_ring *ring; ++ int i; ++ ++ if (queue < 0 || queue >= adapter->num_tx_queues) ++ return -EINVAL; ++ ++ ring = adapter->tx_ring[queue]; ++ ring->launchtime_enable = enable; ++ ++ if (adapter->base_time) ++ return 0; ++ ++ adapter->cycle_time = NSEC_PER_SEC; ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ ring = adapter->tx_ring[i]; ++ ring->start_time = 0; ++ ring->end_time = NSEC_PER_SEC; ++ } ++ ++ return 0; ++} ++ ++static bool is_base_time_past(ktime_t base_time, const struct timespec64 *now) ++{ ++ struct timespec64 b; ++ ++ b = ktime_to_timespec64(base_time); ++ ++ return timespec64_compare(now, &b) > 0; ++} ++ ++static bool validate_schedule(struct igc_adapter *adapter, ++ const struct tc_taprio_qopt_offload *qopt) ++{ ++ int queue_uses[IGC_MAX_TX_QUEUES] = { }; ++ struct timespec64 now; ++ size_t n; ++ ++ if (qopt->cycle_time_extension) ++ return false; ++ ++ igc_ptp_read(adapter, &now); ++ ++ /* If we program the controller's BASET registers with a time ++ * in the future, it will hold all the packets until that ++ * time, causing a lot of TX Hangs, so to avoid that, we ++ * reject schedules that would start in the future. ++ */ ++ if (!is_base_time_past(qopt->base_time, &now)) ++ return false; ++ ++ for (n = 0; n < qopt->num_entries; n++) { ++ const struct tc_taprio_sched_entry *e; ++ int i; ++ ++ e = &qopt->entries[n]; ++ ++ /* i225 only supports "global" frame preemption ++ * settings. ++ */ ++ if (e->command != TC_TAPRIO_CMD_SET_GATES) ++ return false; ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ if (e->gate_mask & BIT(i)) ++ queue_uses[i]++; ++ ++ if (queue_uses[i] > 1) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static int igc_tsn_enable_launchtime(struct igc_adapter *adapter, ++ struct tc_etf_qopt_offload *qopt) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int err; ++ ++ if (hw->mac.type != igc_i225) ++ return -EOPNOTSUPP; ++ ++ err = igc_save_launchtime_params(adapter, qopt->queue, qopt->enable); ++ if (err) ++ return err; ++ ++ return igc_tsn_offload_apply(adapter); ++} ++ ++static int igc_save_qbv_schedule(struct igc_adapter *adapter, ++ struct tc_taprio_qopt_offload *qopt) ++{ ++ u32 start_time = 0, end_time = 0; ++ size_t n; ++ ++ if (!qopt->enable) { ++ adapter->base_time = 0; ++ return 0; ++ } ++ ++ if (adapter->base_time) ++ return -EALREADY; ++ ++ if (!validate_schedule(adapter, qopt)) ++ return -EINVAL; ++ ++ adapter->cycle_time = qopt->cycle_time; ++ adapter->base_time = qopt->base_time; ++ ++ /* FIXME: be a little smarter about cases when the gate for a ++ * queue stays open for more than one entry. ++ */ ++ for (n = 0; n < qopt->num_entries; n++) { ++ struct tc_taprio_sched_entry *e = &qopt->entries[n]; ++ int i; ++ ++ end_time += e->interval; ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ struct igc_ring *ring = adapter->tx_ring[i]; ++ ++ if (!(e->gate_mask & BIT(i))) ++ continue; ++ ++ ring->start_time = start_time; ++ ring->end_time = end_time; ++ } ++ ++ start_time += e->interval; ++ } ++ ++ return 0; ++} ++ ++static int igc_tsn_enable_qbv_scheduling(struct igc_adapter *adapter, ++ struct tc_taprio_qopt_offload *qopt) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ int err; ++ ++ if (hw->mac.type != igc_i225) ++ return -EOPNOTSUPP; ++ ++ err = igc_save_qbv_schedule(adapter, qopt); ++ if (err) ++ return err; ++ ++ return igc_tsn_offload_apply(adapter); ++} ++ ++static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type, ++ void *type_data) ++{ ++ struct igc_adapter *adapter = netdev_priv(dev); ++ ++ switch (type) { ++ case TC_SETUP_QDISC_TAPRIO: ++ return igc_tsn_enable_qbv_scheduling(adapter, type_data); ++ ++ case TC_SETUP_QDISC_ETF: ++ return igc_tsn_enable_launchtime(adapter, type_data); ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ + static const struct net_device_ops igc_netdev_ops = { + .ndo_open = igc_open, + .ndo_stop = igc_close, + .ndo_start_xmit = igc_xmit_frame, ++ .ndo_set_rx_mode = igc_set_rx_mode, + .ndo_set_mac_address = igc_set_mac, + .ndo_change_mtu = igc_change_mtu, + .ndo_get_stats64 = igc_get_stats64, + .ndo_fix_features = igc_fix_features, + .ndo_set_features = igc_set_features, + .ndo_features_check = igc_features_check, ++ .ndo_do_ioctl = igc_ioctl, ++ .ndo_setup_tc = igc_setup_tc, + }; + + /* PCIe configuration access */ +@@ -4046,9 +4942,6 @@ + u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr); + u32 value = 0; + +- if (IGC_REMOVED(hw_addr)) +- return ~value; +- + value = readl(&hw_addr[reg]); + + /* reads should not return all F's */ +@@ -4067,7 +4960,6 @@ + + int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx) + { +- struct pci_dev *pdev = adapter->pdev; + struct igc_mac_info *mac = &adapter->hw.mac; + + mac->autoneg = 0; +@@ -4112,7 +5004,7 @@ + return 0; + + err_inval: +- dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); ++ netdev_err(adapter->netdev, "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; + } + +@@ -4134,32 +5026,26 @@ + 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; + +@@ -4199,7 +5085,7 @@ + hw->hw_addr = adapter->io_addr; + + netdev->netdev_ops = &igc_netdev_ops; +- igc_set_ethtool_ops(netdev); ++ igc_ethtool_set_ops(netdev); + netdev->watchdog_timeo = 5 * HZ; + + netdev->mem_start = pci_resource_start(pdev, 0); +@@ -4222,7 +5108,24 @@ + 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_TSO_ECN; ++ netdev->features |= NETIF_F_RXCSUM; + netdev->features |= NETIF_F_HW_CSUM; ++ netdev->features |= NETIF_F_SCTP_CRC; ++ netdev->features |= NETIF_F_HW_TC; ++ ++#define IGC_GSO_PARTIAL_FEATURES (NETIF_F_GSO_GRE | \ ++ NETIF_F_GSO_GRE_CSUM | \ ++ NETIF_F_GSO_IPXIP4 | \ ++ NETIF_F_GSO_IPXIP6 | \ ++ NETIF_F_GSO_UDP_TUNNEL | \ ++ NETIF_F_GSO_UDP_TUNNEL_CSUM) ++ ++ netdev->gso_partial_features = IGC_GSO_PARTIAL_FEATURES; ++ netdev->features |= NETIF_F_GSO_PARTIAL | IGC_GSO_PARTIAL_FEATURES; + + /* setup the private structure */ + err = igc_sw_init(adapter); +@@ -4233,6 +5136,9 @@ + 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; +@@ -4244,8 +5150,7 @@ + + if (igc_get_flash_presence_i225(hw)) { + if (hw->nvm.ops.validate(hw) < 0) { +- dev_err(&pdev->dev, +- "The NVM Checksum Is Not Valid\n"); ++ dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } +@@ -4283,6 +5188,18 @@ + hw->fc.requested_mode = igc_fc_default; + hw->fc.current_mode = igc_fc_default; + ++ /* By default, support wake on port A */ ++ adapter->flags |= IGC_FLAG_WOL_SUPPORTED; ++ ++ /* initialize the wol settings based on the eeprom settings */ ++ if (adapter->flags & IGC_FLAG_WOL_SUPPORTED) ++ adapter->wol |= IGC_WUFC_MAG; ++ ++ device_set_wakeup_enable(&adapter->pdev->dev, ++ adapter->flags & IGC_FLAG_WOL_SUPPORTED); ++ ++ igc_ptp_init(adapter); ++ + /* reset the hardware with the new settings */ + igc_reset(adapter); + +@@ -4306,6 +5223,14 @@ + pcie_print_link_status(pdev); + netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); + ++ dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP); ++ /* Disable EEE for internal PHY devices */ ++ hw->dev_spec._base.eee_enable = false; ++ adapter->flags &= ~IGC_FLAG_EEE; ++ igc_set_eee_i225(hw, false, false, false); ++ ++ pm_runtime_put_noidle(&pdev->dev); ++ + return 0; + + err_register: +@@ -4341,6 +5266,12 @@ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + ++ pm_runtime_get_noresume(&pdev->dev); ++ ++ igc_flush_nfc_rules(adapter); ++ ++ igc_ptp_stop(adapter); ++ + set_bit(__IGC_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); +@@ -4359,8 +5290,6 @@ + pci_iounmap(pdev, adapter->io_addr); + pci_release_mem_regions(pdev); + +- kfree(adapter->mac_table); +- kfree(adapter->shadow_vfta); + free_netdev(netdev); + + pci_disable_pcie_error_reporting(pdev); +@@ -4368,105 +5297,319 @@ + 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, +-}; ++static int __igc_shutdown(struct pci_dev *pdev, bool *enable_wake, ++ bool runtime) ++{ ++ 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; + +-void igc_set_flag_queue_pairs(struct igc_adapter *adapter, +- const u32 max_rss_queues) ++ rtnl_lock(); ++ netif_device_detach(netdev); ++ ++ if (netif_running(netdev)) ++ __igc_close(netdev, true); ++ ++ igc_ptp_suspend(adapter); ++ ++ 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_phy_copper_base(&adapter->hw); ++ else ++ igc_power_up_link(adapter); ++ ++ if (enable_wake) ++ *enable_wake = wake; ++ ++ /* 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); ++ ++ pci_disable_device(pdev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int __maybe_unused igc_runtime_suspend(struct device *dev) + { +- /* 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. ++ return __igc_shutdown(to_pci_dev(dev), NULL, 1); ++} ++ ++static void igc_deliver_wake_packet(struct net_device *netdev) ++{ ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ struct igc_hw *hw = &adapter->hw; ++ struct sk_buff *skb; ++ u32 wupl; ++ ++ wupl = rd32(IGC_WUPL) & IGC_WUPL_MASK; ++ ++ /* WUPM stores only the first 128 bytes of the wake packet. ++ * Read the packet only if we have the whole thing. + */ +- if (adapter->rss_queues > (max_rss_queues / 2)) +- adapter->flags |= IGC_FLAG_QUEUE_PAIRS; +- else +- adapter->flags &= ~IGC_FLAG_QUEUE_PAIRS; ++ if (wupl == 0 || wupl > IGC_WUPM_BYTES) ++ return; ++ ++ skb = netdev_alloc_skb_ip_align(netdev, IGC_WUPM_BYTES); ++ if (!skb) ++ return; ++ ++ skb_put(skb, wupl); ++ ++ /* Ensure reads are 32-bit aligned */ ++ wupl = roundup(wupl, 4); ++ ++ memcpy_fromio(skb->data, hw->hw_addr + IGC_WUPM_REG(0), wupl); ++ ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_rx(skb); + } + +-unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter) ++static int __maybe_unused igc_resume(struct device *dev) + { +- unsigned int max_rss_queues; ++ 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; ++ ++ 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) { ++ netdev_err(netdev, "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); ++ ++ if (igc_init_interrupt_scheme(adapter, true)) { ++ netdev_err(netdev, "Unable to allocate memory for queues\n"); ++ return -ENOMEM; ++ } ++ ++ igc_reset(adapter); + +- /* Determine the maximum number of RSS queues supported. */ +- max_rss_queues = IGC_MAX_RX_QUEUES; ++ /* let the f/w know that the h/w is now under the control of the ++ * driver. ++ */ ++ igc_get_hw_control(adapter); ++ ++ 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 max_rss_queues; ++ return err; + } + +-static void igc_init_queue_configuration(struct igc_adapter *adapter) ++static int __maybe_unused igc_runtime_resume(struct device *dev) + { +- u32 max_rss_queues; ++ return igc_resume(dev); ++} + +- max_rss_queues = igc_get_max_rss_queues(adapter); +- adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus()); ++static int __maybe_unused igc_suspend(struct device *dev) ++{ ++ return __igc_shutdown(to_pci_dev(dev), NULL, 0); ++} + +- igc_set_flag_queue_pairs(adapter, max_rss_queues); ++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); ++ } + } + + /** +- * igc_sw_init - Initialize general software structures (struct igc_adapter) +- * @adapter: board private structure to initialize ++ * igc_io_error_detected - called when PCI error is detected ++ * @pdev: Pointer to PCI device ++ * @state: The current PCI connection state + * +- * 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) ++ * This function is called after a PCI bus error affecting ++ * this device has been detected. ++ **/ ++static pci_ers_result_t igc_io_error_detected(struct pci_dev *pdev, ++ pci_channel_state_t state) + { +- struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; +- struct igc_hw *hw = &adapter->hw; ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct igc_adapter *adapter = netdev_priv(netdev); + +- int size = sizeof(struct igc_mac_addr) * hw->mac.rar_entry_count; ++ netif_device_detach(netdev); + +- pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); ++ if (state == pci_channel_io_perm_failure) ++ return PCI_ERS_RESULT_DISCONNECT; + +- /* set default ring sizes */ +- adapter->tx_ring_count = IGC_DEFAULT_TXD; +- adapter->rx_ring_count = IGC_DEFAULT_RXD; ++ if (netif_running(netdev)) ++ igc_down(adapter); ++ pci_disable_device(pdev); + +- /* set default ITR values */ +- adapter->rx_itr_setting = IGC_DEFAULT_ITR; +- adapter->tx_itr_setting = IGC_DEFAULT_ITR; ++ /* Request a slot reset. */ ++ return PCI_ERS_RESULT_NEED_RESET; ++} + +- /* set default work limits */ +- adapter->tx_work_limit = IGC_DEFAULT_TX_WORK; ++/** ++ * igc_io_slot_reset - called after the PCI bus has been reset. ++ * @pdev: Pointer to PCI device ++ * ++ * Restart the card from scratch, as if from a cold-boot. Implementation ++ * resembles the first-half of the igc_resume routine. ++ **/ ++static pci_ers_result_t igc_io_slot_reset(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct igc_adapter *adapter = netdev_priv(netdev); ++ struct igc_hw *hw = &adapter->hw; ++ pci_ers_result_t result; + +- /* 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; ++ if (pci_enable_device_mem(pdev)) { ++ netdev_err(netdev, "Could not re-enable PCI device after reset\n"); ++ result = PCI_ERS_RESULT_DISCONNECT; ++ } else { ++ pci_set_master(pdev); ++ pci_restore_state(pdev); ++ pci_save_state(pdev); + +- 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; ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); + +- adapter->mac_table = kzalloc(size, GFP_ATOMIC); +- if (!adapter->mac_table) +- return -ENOMEM; +- +- igc_init_queue_configuration(adapter); ++ /* In case of PCI error, adapter loses its HW address ++ * so we should re-assign it here. ++ */ ++ hw->hw_addr = adapter->io_addr; + +- /* 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; ++ igc_reset(adapter); ++ wr32(IGC_WUS, ~0); ++ result = PCI_ERS_RESULT_RECOVERED; + } + +- /* Explicitly disable IRQ since the NIC can be in any state. */ +- igc_irq_disable(adapter); ++ return result; ++} + +- set_bit(__IGC_DOWN, &adapter->state); ++/** ++ * igc_io_resume - called when traffic can start to flow again. ++ * @pdev: Pointer to PCI device ++ * ++ * This callback is called when the error recovery driver tells us that ++ * its OK to resume normal operation. Implementation resembles the ++ * second-half of the igc_resume routine. ++ */ ++static void igc_io_resume(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct igc_adapter *adapter = netdev_priv(netdev); + +- return 0; ++ rtnl_lock(); ++ if (netif_running(netdev)) { ++ if (igc_open(netdev)) { ++ netdev_err(netdev, "igc_open failed after reset\n"); ++ return; ++ } ++ } ++ ++ netif_device_attach(netdev); ++ ++ /* let the f/w know that the h/w is now under the control of the ++ * driver. ++ */ ++ igc_get_hw_control(adapter); ++ rtnl_unlock(); + } + ++static const struct pci_error_handlers igc_err_handler = { ++ .error_detected = igc_io_error_detected, ++ .slot_reset = igc_io_slot_reset, ++ .resume = igc_io_resume, ++}; ++ ++#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, ++ .err_handler = &igc_err_handler, ++}; ++ + /** + * igc_reinit_queues - return error + * @adapter: pointer to adapter structure +@@ -4474,7 +5617,6 @@ + int igc_reinit_queues(struct igc_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +- struct pci_dev *pdev = adapter->pdev; + int err = 0; + + if (netif_running(netdev)) +@@ -4483,7 +5625,7 @@ + igc_reset_interrupt_capability(adapter); + + if (igc_init_interrupt_scheme(adapter, true)) { +- dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); ++ netdev_err(netdev, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + +@@ -4516,9 +5658,7 @@ + { + int ret; + +- pr_info("%s - version %s\n", +- igc_driver_string, igc_driver_version); +- ++ pr_info("%s\n", igc_driver_string); + pr_info("%s\n", igc_copyright); + + ret = pci_register_driver(&igc_driver); + +--- a/drivers/net/ethernet/intel/igc/igc_phy.c 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_phy.c 2022-03-10 14:39:17.877440146 +0800 +@@ -173,6 +173,7 @@ + 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 @@ + 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 @@ + 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); + +@@ -235,8 +249,7 @@ + return ret_val; + } + +- if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && +- hw->phy.id == I225_I_PHY_ID) { ++ if (phy->autoneg_mask & ADVERTISE_2500_FULL) { + /* Read the MULTI GBT AN Control Register - reg 7.32 */ + ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK << + MMD_DEVADDR_SHIFT) | +@@ -376,8 +389,7 @@ + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, + mii_1000t_ctrl_reg); + +- if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && +- hw->phy.id == I225_I_PHY_ID) ++ if (phy->autoneg_mask & ADVERTISE_2500_FULL) + ret_val = phy->ops.write_reg(hw, + (STANDARD_AN_REG_MASK << + MMD_DEVADDR_SHIFT) | +@@ -734,8 +746,6 @@ + if (ret_val) + return ret_val; + ret_val = igc_write_phy_reg_mdic(hw, offset, data); +- if (ret_val) +- return ret_val; + hw->phy.ops.release(hw); + } else { + ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr, + +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c 2022-03-10 14:33:17.227212778 +0800 +@@ -0,0 +1,620 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (c) 2019 Intel Corporation */ ++ ++#include "igc.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 */ ++void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 sec, nsec; ++ ++ /* The timestamp is latched when SYSTIML is read. */ ++ 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; ++ ++ 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(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); ++ ts->tv_nsec = rd32(IGC_SYSTIML); ++ ts->tv_sec = rd32(IGC_SYSTIMH); ++ ptp_read_system_postts(sts); ++ ++ 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 timestamp from Rx packet buffer ++ * @q_vector: Pointer to interrupt specific structure ++ * @va: Pointer to address containing Rx buffer ++ * @skb: Buffer containing timestamp and packet ++ * ++ * This function retrieves the timestamp saved in the beginning of packet ++ * buffer. While two timestamps are available, one in timer0 reference and the ++ * other in timer1 reference, this function considers only the timestamp in ++ * timer0 reference. ++ */ ++void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, __le32 *va, ++ struct sk_buff *skb) ++{ ++ struct igc_adapter *adapter = q_vector->adapter; ++ u64 regval; ++ int adjust; ++ ++ /* Timestamps are saved in little endian at the beginning of the packet ++ * buffer following the layout: ++ * ++ * DWORD: | 0 | 1 | 2 | 3 | ++ * Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH | ++ * ++ * SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds ++ * part of the timestamp. ++ */ ++ regval = le32_to_cpu(va[2]); ++ regval |= (u64)le32_to_cpu(va[3]) << 32; ++ igc_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); ++ ++ /* Adjust timestamp for the RX latency based on link speed */ ++ 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; ++ default: ++ adjust = 0; ++ netdev_warn_once(adapter->netdev, "Imprecise timestamp\n"); ++ break; ++ } ++ skb_hwtstamps(skb)->hwtstamp = ++ ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); ++} ++ ++static void igc_ptp_disable_rx_timestamp(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 val; ++ int i; ++ ++ wr32(IGC_TSYNCRXCTL, 0); ++ ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ val = rd32(IGC_SRRCTL(i)); ++ val &= ~IGC_SRRCTL_TIMESTAMP; ++ wr32(IGC_SRRCTL(i), val); ++ } ++ ++ val = rd32(IGC_RXPBS); ++ val &= ~IGC_RXPBS_CFG_TS_EN; ++ wr32(IGC_RXPBS, val); ++} ++ ++static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 val; ++ int i; ++ ++ val = rd32(IGC_RXPBS); ++ val |= IGC_RXPBS_CFG_TS_EN; ++ wr32(IGC_RXPBS, val); ++ ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ val = rd32(IGC_SRRCTL(i)); ++ /* FIXME: For now, only support retrieving RX timestamps from ++ * timer 0. ++ */ ++ val |= IGC_SRRCTL_TIMER1SEL(0) | IGC_SRRCTL_TIMER0SEL(0) | ++ IGC_SRRCTL_TIMESTAMP; ++ wr32(IGC_SRRCTL(i), val); ++ } ++ ++ val = IGC_TSYNCRXCTL_ENABLED | IGC_TSYNCRXCTL_TYPE_ALL | ++ IGC_TSYNCRXCTL_RXSYNSIG; ++ wr32(IGC_TSYNCRXCTL, val); ++} ++ ++static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ ++ wr32(IGC_TSYNCTXCTL, 0); ++} ++ ++static void igc_ptp_enable_tx_timestamp(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ ++ wr32(IGC_TSYNCTXCTL, IGC_TSYNCTXCTL_ENABLED | IGC_TSYNCTXCTL_TXSYNSIG); ++ ++ /* Read TXSTMP registers to discard any timestamp previously stored. */ ++ rd32(IGC_TXSTMPL); ++ rd32(IGC_TXSTMPH); ++} ++ ++/** ++ * igc_ptp_set_timestamp_mode - setup hardware for timestamping ++ * @adapter: networking device structure ++ * @config: hwtstamp configuration ++ * ++ * Return: 0 in case of success, negative errno code otherwise. ++ */ ++static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter, ++ struct hwtstamp_config *config) ++{ ++ /* reserved for future extensions */ ++ if (config->flags) ++ return -EINVAL; ++ ++ switch (config->tx_type) { ++ case HWTSTAMP_TX_OFF: ++ igc_ptp_disable_tx_timestamp(adapter); ++ break; ++ case HWTSTAMP_TX_ON: ++ igc_ptp_enable_tx_timestamp(adapter); ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ switch (config->rx_filter) { ++ case HWTSTAMP_FILTER_NONE: ++ igc_ptp_disable_rx_timestamp(adapter); ++ break; ++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: ++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: ++ 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: ++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: ++ case HWTSTAMP_FILTER_NTP_ALL: ++ case HWTSTAMP_FILTER_ALL: ++ igc_ptp_enable_rx_timestamp(adapter); ++ config->rx_filter = HWTSTAMP_FILTER_ALL; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ return 0; ++} ++ ++static void igc_ptp_tx_timeout(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ ++ dev_kfree_skb_any(adapter->ptp_tx_skb); ++ adapter->ptp_tx_skb = NULL; ++ adapter->tx_hwtstamp_timeouts++; ++ clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); ++ /* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */ ++ rd32(IGC_TXSTMPH); ++ netdev_warn(adapter->netdev, "Tx timestamp timeout\n"); ++} ++ ++void igc_ptp_tx_hang(struct igc_adapter *adapter) ++{ ++ bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + ++ IGC_PTP_TX_TIMEOUT); ++ ++ 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); ++ igc_ptp_tx_timeout(adapter); ++ } ++} ++ ++/** ++ * 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; ++ int adjust = 0; ++ u64 regval; ++ ++ if (WARN_ON_ONCE(!skb)) ++ return; ++ ++ regval = rd32(IGC_TXSTMPL); ++ regval |= (u64)rd32(IGC_TXSTMPH) << 32; ++ igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); ++ ++ switch (adapter->link_speed) { ++ case SPEED_10: ++ adjust = IGC_I225_TX_LATENCY_10; ++ break; ++ case SPEED_100: ++ adjust = IGC_I225_TX_LATENCY_100; ++ break; ++ case SPEED_1000: ++ adjust = IGC_I225_TX_LATENCY_1000; ++ break; ++ case SPEED_2500: ++ adjust = IGC_I225_TX_LATENCY_2500; ++ break; ++ } ++ ++ shhwtstamps.hwtstamp = ++ ktime_add_ns(shhwtstamps.hwtstamp, adjust); ++ ++ /* 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. ++ */ ++static 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 (!test_bit(__IGC_PTP_TX_IN_PROGRESS, &adapter->state)) ++ return; ++ ++ tsynctxctl = rd32(IGC_TSYNCTXCTL); ++ if (WARN_ON_ONCE(!(tsynctxctl & IGC_TSYNCTXCTL_TXTT_0))) ++ return; ++ ++ igc_ptp_tx_hwtstamp(adapter); ++} ++ ++/** ++ * igc_ptp_set_ts_config - set hardware time stamping config ++ * @netdev: network interface device structure ++ * @ifr: 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 ++ * @ifr: 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; ++ ++ adapter->prev_ptp_time = ktime_to_timespec64(ktime_get_real()); ++ adapter->ptp_reset_start = ktime_get(); ++ ++ adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, ++ &adapter->pdev->dev); ++ if (IS_ERR(adapter->ptp_clock)) { ++ adapter->ptp_clock = NULL; ++ netdev_err(netdev, "ptp_clock_register failed\n"); ++ } else if (adapter->ptp_clock) { ++ netdev_info(netdev, "PHC added\n"); ++ adapter->ptp_flags |= IGC_PTP_ENABLED; ++ } ++} ++ ++static void igc_ptp_time_save(struct igc_adapter *adapter) ++{ ++ igc_ptp_read(adapter, &adapter->prev_ptp_time); ++ adapter->ptp_reset_start = ktime_get(); ++} ++ ++static void igc_ptp_time_restore(struct igc_adapter *adapter) ++{ ++ struct timespec64 ts = adapter->prev_ptp_time; ++ ktime_t delta; ++ ++ delta = ktime_sub(ktime_get(), adapter->ptp_reset_start); ++ ++ timespec64_add_ns(&ts, ktime_to_ns(delta)); ++ ++ igc_ptp_write_i225(adapter, &ts); ++} ++ ++/** ++ * 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); ++ dev_kfree_skb_any(adapter->ptp_tx_skb); ++ adapter->ptp_tx_skb = NULL; ++ clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); ++ ++ if (pci_device_is_present(adapter->pdev)) ++ igc_ptp_time_save(adapter); ++} ++ ++/** ++ * 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); ++ netdev_info(adapter->netdev, "PHC removed\n"); ++ 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) { ++ igc_ptp_time_restore(adapter); ++ } else { ++ timecounter_init(&adapter->tc, &adapter->cc, ++ ktime_to_ns(ktime_get_real())); ++ } ++out: ++ spin_unlock_irqrestore(&adapter->tmreg_lock, flags); ++ ++ wrfl(); ++} + +--- a/drivers/net/ethernet/intel/igc/igc_regs.h 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_regs.h 2022-03-10 14:33:17.227212778 +0800 +@@ -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 */ +@@ -29,10 +30,6 @@ + #define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */ + #define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */ + #define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */ +-#define IGC_FCSTS 0x02464 /* FC Status - RO */ +- +-/* PCIe Register Description */ +-#define IGC_GCR 0x05B00 /* PCIe control- RW */ + + /* Semaphore registers */ + #define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */ +@@ -43,6 +40,7 @@ + #define IGC_FACTPS 0x05B30 + + /* Interrupt Register Description */ ++#define IGC_EICR 0x01580 /* Ext. Interrupt Cause read - W0 */ + #define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ + #define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ + #define IGC_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ +@@ -60,23 +58,6 @@ + #define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */ + #define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */ + +-/* Interrupt Cause */ +-#define IGC_ICRXPTC 0x04104 /* Rx Packet Timer Expire Count */ +-#define IGC_ICRXATC 0x04108 /* Rx Absolute Timer Expire Count */ +-#define IGC_ICTXPTC 0x0410C /* Tx Packet Timer Expire Count */ +-#define IGC_ICTXATC 0x04110 /* Tx Absolute Timer Expire Count */ +-#define IGC_ICTXQEC 0x04118 /* Tx Queue Empty Count */ +-#define IGC_ICTXQMTC 0x0411C /* Tx Queue Min Threshold Count */ +-#define IGC_ICRXDMTC 0x04120 /* Rx Descriptor Min Threshold Count */ +-#define IGC_ICRXOC 0x04124 /* Receiver Overrun Count */ +- +-#define IGC_CBTMPC 0x0402C /* Circuit Breaker TX Packet Count */ +-#define IGC_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ +-#define IGC_CBRMPC 0x040FC /* Circuit Breaker RX Packet Count */ +-#define IGC_RPTHC 0x04104 /* Rx Packets To Host */ +-#define IGC_HGPTC 0x04118 /* Host Good Packets TX Count */ +-#define IGC_HTCBDPC 0x04124 /* Host TX Circ.Breaker Drop Count */ +- + /* MSI-X Table Register Descriptions */ + #define IGC_PBACL 0x05B68 /* MSIx PBA Clear - R/W 1 to clear */ + +@@ -113,10 +94,11 @@ + #define IGC_RLPML 0x05004 /* Rx Long Packet Max Length */ + #define IGC_RFCTL 0x05008 /* Receive Filter Control*/ + #define IGC_MTA 0x05200 /* Multicast Table Array - RW Array */ ++#define IGC_RA 0x05400 /* Receive Address - RW Array */ + #define IGC_UTA 0x0A000 /* Unicast Table Array - RW */ + #define IGC_RAL(_n) (0x05400 + ((_n) * 0x08)) + #define IGC_RAH(_n) (0x05404 + ((_n) * 0x08)) +-#define IGC_VLAPQF 0x055B0 /* VLAN Priority Queue Filter VLAPQF */ ++#define IGC_VLANPQF 0x055B0 /* VLAN Priority Queue Filter - RW */ + + /* Transmit Register Descriptions */ + #define IGC_TCTL 0x00400 /* Tx Control - RW */ +@@ -132,13 +114,9 @@ + #define IGC_MMDAC 13 /* MMD Access Control */ + #define IGC_MMDAAD 14 /* MMD Access Address/Data */ + +-/* Good transmitted packets counter registers */ +-#define IGC_PQGPTC(_n) (0x010014 + (0x100 * (_n))) +- + /* Statistics Register Descriptions */ + #define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */ + #define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +-#define IGC_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ + #define IGC_RXERRC 0x0400C /* Receive Error Count - R/clr */ + #define IGC_MPC 0x04010 /* Missed Packet Count - R/clr */ + #define IGC_SCC 0x04014 /* Single Collision Count - R/clr */ +@@ -146,10 +124,10 @@ + #define IGC_MCC 0x0401C /* Multiple Collision Count - R/clr */ + #define IGC_LATECOL 0x04020 /* Late Collision Count - R/clr */ + #define IGC_COLC 0x04028 /* Collision Count - R/clr */ ++#define IGC_RERC 0x0402C /* Receive Error Count - R/clr */ + #define IGC_DC 0x04030 /* Defer Count - R/clr */ + #define IGC_TNCRS 0x04034 /* Tx-No CRS - R/clr */ +-#define IGC_SEC 0x04038 /* Sequence Error Count - R/clr */ +-#define IGC_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ ++#define IGC_HTDPMC 0x0403C /* Host Transmit Discarded by MAC - R/clr */ + #define IGC_RLEC 0x04040 /* Receive Length Error Count - R/clr */ + #define IGC_XONRXC 0x04048 /* XON Rx Count - R/clr */ + #define IGC_XONTXC 0x0404C /* XON Tx Count - R/clr */ +@@ -193,13 +171,10 @@ + #define IGC_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ + #define IGC_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ + #define IGC_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ +-#define IGC_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ + #define IGC_IAC 0x04100 /* Interrupt Assertion Count */ +-#define IGC_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */ +-#define IGC_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */ +-#define IGC_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +-#define IGC_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */ + #define IGC_RPTHC 0x04104 /* Rx Packets To Host */ ++#define IGC_TLPIC 0x04148 /* EEE Tx LPI Count */ ++#define IGC_RLPIC 0x0414C /* EEE Rx LPI Count */ + #define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */ + #define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */ + #define IGC_HGORCL 0x04128 /* Host Good Octets Received Count Low */ +@@ -207,7 +182,41 @@ + #define IGC_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ + #define IGC_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ + #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 */ ++ ++/* Transmit Scheduling Registers */ ++#define IGC_TQAVCTRL 0x3570 ++#define IGC_TXQCTL(_n) (0x3344 + 0x4 * (_n)) ++#define IGC_BASET_L 0x3314 ++#define IGC_BASET_H 0x3318 ++#define IGC_QBVCYCLET 0x331C ++#define IGC_QBVCYCLET_S 0x3320 ++ ++#define IGC_STQT(_n) (0x3324 + 0x4 * (_n)) ++#define IGC_ENDQT(_n) (0x3334 + 0x4 * (_n)) ++#define IGC_DTXMXPKTSZ 0x355C ++ ++/* 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_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 */ +@@ -215,6 +224,26 @@ + /* 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)) ++ ++/* Energy Efficient Ethernet "EEE" registers */ ++#define IGC_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/ ++#define IGC_IPCNFG 0x0E38 /* Internal PHY Configuration */ ++#define IGC_EEE_SU 0x0E34 /* EEE Setup */ ++ ++/* LTR registers */ ++#define IGC_LTRC 0x01A0 /* Latency Tolerance Reporting Control */ ++#define IGC_DMACR 0x02508 /* DMA Coalescing Control Register */ ++#define IGC_LTRMINV 0x5BB0 /* LTR Minimum Value */ ++#define IGC_LTRMAXV 0x5BB4 /* LTR Maximum Value */ ++ + /* forward declaration */ + struct igc_hw; + u32 igc_rd32(struct igc_hw *hw, u32 reg); +@@ -223,8 +252,7 @@ + #define wr32(reg, val) \ + do { \ + u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \ +- if (!IGC_REMOVED(hw_addr)) \ +- writel((val), &hw_addr[(reg)]); \ ++ writel((val), &hw_addr[(reg)]); \ + } while (0) + + #define rd32(reg) (igc_rd32(hw, reg)) + +--- a/drivers/net/ethernet/intel/igc/igc_tsn.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_tsn.c 2022-03-10 14:55:29.084835415 +0800 +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (c) 2019 Intel Corporation */ ++ ++#include "igc.h" ++#include "igc_tsn.h" ++ ++static bool is_any_launchtime(struct igc_adapter *adapter) ++{ ++ int i; ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ struct igc_ring *ring = adapter->tx_ring[i]; ++ ++ if (ring->launchtime_enable) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* Returns the TSN specific registers to their default values after ++ * TSN offloading is disabled. ++ */ ++static int igc_tsn_disable_offload(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 tqavctrl; ++ int i; ++ ++ if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED)) ++ return 0; ++ ++ adapter->cycle_time = 0; ++ ++ wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); ++ wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT); ++ ++ tqavctrl = rd32(IGC_TQAVCTRL); ++ tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN | ++ IGC_TQAVCTRL_ENHANCED_QAV); ++ wr32(IGC_TQAVCTRL, tqavctrl); ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ struct igc_ring *ring = adapter->tx_ring[i]; ++ ++ ring->start_time = 0; ++ ring->end_time = 0; ++ ring->launchtime_enable = false; ++ ++ wr32(IGC_TXQCTL(i), 0); ++ wr32(IGC_STQT(i), 0); ++ wr32(IGC_ENDQT(i), NSEC_PER_SEC); ++ } ++ ++ wr32(IGC_QBVCYCLET_S, 0); ++ wr32(IGC_QBVCYCLET, NSEC_PER_SEC); ++ ++ adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED; ++ ++ return 0; ++} ++ ++static int igc_tsn_enable_offload(struct igc_adapter *adapter) ++{ ++ struct igc_hw *hw = &adapter->hw; ++ u32 tqavctrl, baset_l, baset_h; ++ u32 sec, nsec, cycle; ++ ktime_t base_time, systim; ++ int i; ++ ++ if (adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) ++ return 0; ++ ++ cycle = adapter->cycle_time; ++ base_time = adapter->base_time; ++ ++ wr32(IGC_TSAUXC, 0); ++ wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN); ++ wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN); ++ ++ tqavctrl = rd32(IGC_TQAVCTRL); ++ tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV; ++ wr32(IGC_TQAVCTRL, tqavctrl); ++ ++ wr32(IGC_QBVCYCLET_S, cycle); ++ wr32(IGC_QBVCYCLET, cycle); ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ struct igc_ring *ring = adapter->tx_ring[i]; ++ u32 txqctl = 0; ++ ++ wr32(IGC_STQT(i), ring->start_time); ++ wr32(IGC_ENDQT(i), ring->end_time); ++ ++ if (adapter->base_time) { ++ /* If we have a base_time we are in "taprio" ++ * mode and we need to be strict about the ++ * cycles: only transmit a packet if it can be ++ * completed during that cycle. ++ */ ++ txqctl |= IGC_TXQCTL_STRICT_CYCLE | ++ IGC_TXQCTL_STRICT_END; ++ } ++ ++ if (ring->launchtime_enable) ++ txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT; ++ ++ wr32(IGC_TXQCTL(i), txqctl); ++ } ++ ++ nsec = rd32(IGC_SYSTIML); ++ sec = rd32(IGC_SYSTIMH); ++ ++ systim = ktime_set(sec, nsec); ++ ++ if (ktime_compare(systim, base_time) > 0) { ++ s64 n; ++ ++ n = div64_s64(ktime_sub_ns(systim, base_time), cycle); ++ base_time = ktime_add_ns(base_time, (n + 1) * cycle); ++ } ++ ++ baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l); ++ ++ wr32(IGC_BASET_H, baset_h); ++ wr32(IGC_BASET_L, baset_l); ++ ++ adapter->flags |= IGC_FLAG_TSN_QBV_ENABLED; ++ ++ return 0; ++} ++ ++int igc_tsn_offload_apply(struct igc_adapter *adapter) ++{ ++ bool is_any_enabled = adapter->base_time || is_any_launchtime(adapter); ++ ++ if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled) ++ return 0; ++ ++ if (!is_any_enabled) { ++ int err = igc_tsn_disable_offload(adapter); ++ ++ if (err < 0) ++ return err; ++ ++ /* The BASET registers aren't cleared when writing ++ * into them, force a reset if the interface is ++ * running. ++ */ ++ if (netif_running(adapter->netdev)) ++ schedule_work(&adapter->reset_task); ++ ++ return 0; ++ } ++ ++ return igc_tsn_enable_offload(adapter); ++} + +--- a/drivers/net/ethernet/intel/igc/igc_tsn.h 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/igc_tsn.h 2022-03-10 14:33:17.227212778 +0800 +@@ -0,0 +1,9 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2020 Intel Corporation */ ++ ++#ifndef _IGC_TSN_H_ ++#define _IGC_TSN_H_ ++ ++int igc_tsn_offload_apply(struct igc_adapter *adapter); ++ ++#endif /* _IGC_BASE_H */ + +--- a/drivers/net/ethernet/intel/igc/Makefile 2022-03-02 18:41:18.000000000 +0800 ++++ b/drivers/net/ethernet/intel/igc/Makefile 2022-03-10 14:33:17.227212778 +0800 +@@ -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_diag.o igc_ethtool.o igc_ptp.o igc_dump.o igc_tsn.o