diff mbox series

[v3,07/11] igc: Add HW initialization code

Message ID 20180624084515.10242-1-sasha.neftin@intel.com
State RFC
Headers show
Series None | expand

Commit Message

Sasha Neftin June 24, 2018, 8:45 a.m. UTC
Add code for hw initialization and reset.
Add code for semaphore handling.

Sasha Neftin (v2):
fixed code indentation
refactor of igc_desc_unused method

Sasha Neftin (v3):
clean code and remove unused methods

Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
---
 drivers/net/ethernet/intel/igc/Makefile        |   3 +-
 drivers/net/ethernet/intel/igc/e1000_base.c    | 198 +++++++++++++++
 drivers/net/ethernet/intel/igc/e1000_base.h    |   2 +
 drivers/net/ethernet/intel/igc/e1000_defines.h |  39 +++
 drivers/net/ethernet/intel/igc/e1000_hw.h      |  85 +++++++
 drivers/net/ethernet/intel/igc/e1000_i225.c    | 141 +++++++++++
 drivers/net/ethernet/intel/igc/e1000_mac.c     | 320 +++++++++++++++++++++++++
 drivers/net/ethernet/intel/igc/e1000_mac.h     |  13 +-
 drivers/net/ethernet/intel/igc/e1000_regs.h    |  27 +++
 drivers/net/ethernet/intel/igc/igc_main.c      |  21 ++
 10 files changed, 846 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/igc/e1000_i225.c

Comments

kernel test robot June 24, 2018, 3:52 p.m. UTC | #1
Hi Sasha,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on jkirsher-next-queue/dev-queue]
[also build test WARNING on v4.18-rc2 next-20180622]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Sasha-Neftin/igc-Add-skeletal-frame-for-Intel-R-2-5G-Ethernet-Controller-support/20180624-164739
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git dev-queue
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

>> drivers/net/ethernet/intel/igc/e1000_mac.c:228:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:228:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:228:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:229:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:229:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:229:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:82:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:82:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:82:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:173:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:173:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:173:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:174:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:174:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:174:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:175:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:175:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:175:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:177:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:177:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:177:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_mac.c:370:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_mac.c:370:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_mac.c:370:9:    got unsigned char [usertype] *__val
--
>> drivers/net/ethernet/intel/igc/e1000_i225.c:56:17: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_i225.c:56:17:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_i225.c:56:17:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_i225.c:114:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_i225.c:114:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_i225.c:114:9:    got unsigned char [usertype] *__val
   drivers/net/ethernet/intel/igc/e1000_i225.c:138:9: sparse: incorrect type in initializer (different address spaces) @@    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr @@    got deref] [usertype] <asn:2>*hw_addr @@
   drivers/net/ethernet/intel/igc/e1000_i225.c:138:9:    expected unsigned char [noderef] [usertype] <asn:2>*hw_addr
   drivers/net/ethernet/intel/igc/e1000_i225.c:138:9:    got unsigned char [usertype] *__val

vim +228 drivers/net/ethernet/intel/igc/e1000_mac.c

   197	
   198	/**
   199	 *  igc_set_fc_watermarks - Set flow control high/low watermarks
   200	 *  @hw: pointer to the HW structure
   201	 *
   202	 *  Sets the flow control high/low threshold (watermark) registers.  If
   203	 *  flow control XON frame transmission is enabled, then set XON frame
   204	 *  tansmission as well.
   205	 **/
   206	static s32 igc_set_fc_watermarks(struct e1000_hw *hw)
   207	{
   208		s32 ret_val = 0;
   209		u32 fcrtl = 0, fcrth = 0;
   210	
   211		/* Set the flow control receive threshold registers.  Normally,
   212		 * these registers will be set to a default threshold that may be
   213		 * adjusted later by the driver's runtime code.  However, if the
   214		 * ability to transmit pause frames is not enabled, then these
   215		 * registers will be set to 0.
   216		 */
   217		if (hw->fc.current_mode & e1000_fc_tx_pause) {
   218			/* We need to set up the Receive Threshold high and low water
   219			 * marks as well as (optionally) enabling the transmission of
   220			 * XON frames.
   221			 */
   222			fcrtl = hw->fc.low_water;
   223			if (hw->fc.send_xon)
   224				fcrtl |= E1000_FCRTL_XONE;
   225	
   226			fcrth = hw->fc.high_water;
   227		}
 > 228		wr32(E1000_FCRTL, fcrtl);
   229		wr32(E1000_FCRTH, fcrth);
   230	
   231		return ret_val;
   232	}
   233	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Shannon Nelson June 28, 2018, 10:25 p.m. UTC | #2
On 6/24/2018 1:45 AM, Sasha Neftin wrote:
> Add code for hw initialization and reset.
> Add code for semaphore handling.
> 
> Sasha Neftin (v2):
> fixed code indentation
> refactor of igc_desc_unused method
> 
> Sasha Neftin (v3):
> clean code and remove unused methods
> 
> Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
> ---
>   drivers/net/ethernet/intel/igc/Makefile        |   3 +-
>   drivers/net/ethernet/intel/igc/e1000_base.c    | 198 +++++++++++++++
>   drivers/net/ethernet/intel/igc/e1000_base.h    |   2 +
>   drivers/net/ethernet/intel/igc/e1000_defines.h |  39 +++
>   drivers/net/ethernet/intel/igc/e1000_hw.h      |  85 +++++++
>   drivers/net/ethernet/intel/igc/e1000_i225.c    | 141 +++++++++++
>   drivers/net/ethernet/intel/igc/e1000_mac.c     | 320 +++++++++++++++++++++++++
>   drivers/net/ethernet/intel/igc/e1000_mac.h     |  13 +-
>   drivers/net/ethernet/intel/igc/e1000_regs.h    |  27 +++
>   drivers/net/ethernet/intel/igc/igc_main.c      |  21 ++
>   10 files changed, 846 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/net/ethernet/intel/igc/e1000_i225.c
> 
> diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile
> index 6a757ac8492d..cb260bedfa37 100644
> --- a/drivers/net/ethernet/intel/igc/Makefile
> +++ b/drivers/net/ethernet/intel/igc/Makefile
> @@ -7,5 +7,4 @@
>   
>   obj-$(CONFIG_IGC) += igc.o
>   
> -igc-objs := igc_main.o e1000_mac.o \
> -e1000_base.o
> +igc-objs := igc_main.o e1000_mac.o e1000_i225.o e1000_base.o
> diff --git a/drivers/net/ethernet/intel/igc/e1000_base.c b/drivers/net/ethernet/intel/igc/e1000_base.c
> index 265ec98000e7..395d7ce70bb4 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_base.c
> +++ b/drivers/net/ethernet/intel/igc/e1000_base.c
> @@ -5,6 +5,92 @@
>   
>   #include "e1000_hw.h"
>   #include "e1000_i225.h"
> +#include "e1000_mac.h"
> +#include "e1000_base.h"
> +#include "igc.h"
> +
> +/* forward declaration */
> +static s32 igc_get_invariants_base(struct e1000_hw *);
> +static s32 igc_init_hw_base(struct e1000_hw *);
> +static s32 igc_reset_hw_base(struct e1000_hw *);
> +static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw);
> +
> +/**
> + *  igc_init_mac_params_base - Init MAC func ptrs.
> + *  @hw: pointer to the HW structure
> + **/
> +static s32 igc_init_mac_params_base(struct e1000_hw *hw)
> +{
> +	struct e1000_mac_info *mac = &hw->mac;
> +
> +	/* Set mta register count */
> +	mac->mta_reg_count = 128;
> +	mac->rar_entry_count = E1000_RAR_ENTRIES;
> +
> +	/* reset */
> +	mac->ops.reset_hw = igc_reset_hw_base;
> +
> +	mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
> +	mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
> +
> +	return 0;
> +}
> +
> +static s32 igc_get_invariants_base(struct e1000_hw *hw)
> +{
> +	s32 ret_val = 0;
> +	u32 ctrl_ext = 0;
> +	u32 link_mode = 0;
> +
> +	ctrl_ext = rd32(E1000_CTRL_EXT);
> +	link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
> +
> +	/* mac initialization and operations */
> +	ret_val = igc_init_mac_params_base(hw);
> +	if (ret_val)
> +		goto out;
> +
> +out:
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_init_hw_base - Initialize hardware
> + *  @hw: pointer to the HW structure
> + *
> + *  This inits the hardware readying it for operation.
> + **/
> +static s32 igc_init_hw_base(struct e1000_hw *hw)
> +{
> +	struct e1000_mac_info *mac = &hw->mac;
> +	s32 ret_val = 0;
> +	u16 i, rar_count = mac->rar_entry_count;
> +
> +	/* Setup the receive address */
> +	igc_init_rx_addrs(hw, rar_count);
> +
> +	/* Zero out the Multicast HASH table */
> +	hw_dbg("Zeroing the MTA\n");
> +	for (i = 0; i < mac->mta_reg_count; i++)
> +		array_wr32(E1000_MTA, i, 0);
> +
> +	/* Zero out the Unicast HASH table */
> +	hw_dbg("Zeroing the UTA\n");
> +	for (i = 0; i < mac->uta_reg_count; i++)
> +		array_wr32(E1000_UTA, i, 0);
> +
> +	/* Setup link and flow control */
> +	ret_val = igc_setup_link(hw);
> +
> +	/* Clear all of the statistics registers (clear on read).  It is
> +	 * important that we do this after we have tried to establish link
> +	 * because the symbol error count will increment wildly if there
> +	 * is no link.
> +	 */
> +	igc_clear_hw_cntrs_base(hw);
> +
> +	return ret_val;
> +}
>   
>   /**
>    *  igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
> @@ -81,3 +167,115 @@ void igc_rx_fifo_flush_base(struct e1000_hw *hw)
>   	rd32(E1000_RNBC);
>   	rd32(E1000_MPC);
>   }
> +
> +static struct e1000_mac_operations e1000_mac_ops_base = {
> +	.init_hw	= igc_init_hw_base,
> +};
> +
> +const struct e1000_info e1000_base_info = {
> +	.get_invariants = igc_get_invariants_base,
> +	.mac_ops = &e1000_mac_ops_base,
> +};
> +
> +/**
> + *  igc_reset_hw_base - Reset hardware
> + *  @hw: pointer to the HW structure
> + *
> + *  This resets the hardware into a known state.  This is a
> + *  function pointer entry point called by the api module.
> + **/
> +static s32 igc_reset_hw_base(struct e1000_hw *hw)
> +{
> +	u32 ctrl;
> +	s32 ret_val;
> +
> +	/* Prevent the PCI-E bus from sticking if there is no TLP connection
> +	 * on the last TLP read/write transaction when MAC is reset.
> +	 */
> +	ret_val = igc_disable_pcie_master(hw);
> +	if (ret_val)
> +		hw_dbg("PCI-E Master disable polling has failed.\n");
> +
> +	/* set the completion timeout for interface */
> +	ret_val = igc_set_pcie_completion_timeout(hw);
> +	if (ret_val)
> +		hw_dbg("PCI-E Set completion timeout has failed.\n");
> +
> +	hw_dbg("Masking off all interrupts\n");
> +	wr32(E1000_IMC, 0xffffffff);
> +
> +	wr32(E1000_RCTL, 0);
> +	wr32(E1000_TCTL, E1000_TCTL_PSP);
> +	wrfl();
> +
> +	usleep_range(10000, 20000);
> +
> +	ctrl = rd32(E1000_CTRL);
> +
> +	hw_dbg("Issuing a global reset to MAC\n");
> +	wr32(E1000_CTRL, ctrl | E1000_CTRL_RST);
> +
> +	ret_val = igc_get_auto_rd_done(hw);
> +	if (ret_val) {
> +		/* When auto config read does not complete, do not
> +		 * return with an error. This can happen in situations
> +		 * where there is no eeprom and prevents getting link.
> +		 */
> +		hw_dbg("Auto Read Done did not complete\n");
> +	}
> +
> +	/* Clear any pending interrupt events. */
> +	wr32(E1000_IMC, 0xffffffff);
> +	rd32(E1000_ICR);
> +
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_set_pcie_completion_timeout - set pci-e completion timeout
> + *  @hw: pointer to the HW structure
> + *
> + *  The defaults for 82575 and 82576 should be in the range of 50us to 50ms,

Wrong devices

Since this is copy-n-paste from the previous driver, is this even correct?

> + *  however the hardware default for these parts is 500us to 1ms which is less
> + *  than the 10ms recommended by the pci-e spec.  To address this we need to
> + *  increase the value to either 10ms to 200ms for capability version 1 config,
> + *  or 16ms to 55ms for version 2.
> + **/
> +static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw)
> +{
> +	u32 gcr = rd32(E1000_GCR);
> +	s32 ret_val = 0;
> +	u16 pcie_devctl2;
> +
> +	/* only take action if timeout value is defaulted to 0 */
> +	if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
> +		goto out;
> +
> +	/* if capabilities version is type 1 we can write the
> +	 * timeout of 10ms to 200ms through the GCR register
> +	 */
> +	if (!(gcr & E1000_GCR_CAP_VER2)) {
> +		gcr |= E1000_GCR_CMPL_TMOUT_10ms;
> +		goto out;
> +	}
> +
> +	/* for version 2 capabilities we need to write the config space
> +	 * directly in order to set the completion timeout value for
> +	 * 16ms to 55ms
> +	 */
> +	ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
> +					&pcie_devctl2);
> +	if (ret_val)
> +		goto out;
> +
> +	pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
> +
> +	ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
> +					 &pcie_devctl2);
> +out:
> +	/* disable completion timeout resend */
> +	gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
> +
> +	wr32(E1000_GCR, gcr);
> +	return ret_val;
> +}
> diff --git a/drivers/net/ethernet/intel/igc/e1000_base.h b/drivers/net/ethernet/intel/igc/e1000_base.h
> index 5c766fb7514b..210f1b5f6012 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_base.h
> +++ b/drivers/net/ethernet/intel/igc/e1000_base.h
> @@ -33,6 +33,8 @@ union e1000_adv_tx_desc {
>   #define E1000_ADVTXD_DCMD_TSE	0x80000000 /* TCP Seg enable */
>   #define E1000_ADVTXD_PAYLEN_SHIFT	14 /* Adv desc PAYLEN shift */
>   
> +#define E1000_RAR_ENTRIES		16
> +
>   struct e1000_adv_data_desc {
>   	__le64 buffer_addr;    /* Address of the descriptor's data buffer */
>   	union {
> diff --git a/drivers/net/ethernet/intel/igc/e1000_defines.h b/drivers/net/ethernet/intel/igc/e1000_defines.h
> index f39d93d17ba6..5613806742b1 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_defines.h
> +++ b/drivers/net/ethernet/intel/igc/e1000_defines.h
> @@ -30,6 +30,22 @@
>   #define E1000_PCI_PMCSR			0x44
>   #define E1000_PCI_PMCSR_D3		0x03
>   
> +/* Physical Func Reset Done Indication */
> +#define E1000_CTRL_EXT_LINK_MODE_MASK	0x00C00000
> +
> +/* Number of 100 microseconds we wait for PCI Express master disable */
> +#define MASTER_DISABLE_TIMEOUT		800
> +/*Blocks new Master requests */
> +#define E1000_CTRL_GIO_MASTER_DISABLE	0x00000004
> +/* Status of Master requests. */
> +#define E1000_STATUS_GIO_MASTER_ENABLE	0x00080000
> +
> +/* PCI Express Control */
> +#define E1000_GCR_CMPL_TMOUT_MASK	0x0000F000
> +#define E1000_GCR_CMPL_TMOUT_10ms	0x00001000
> +#define E1000_GCR_CMPL_TMOUT_RESEND	0x00010000
> +#define E1000_GCR_CAP_VER2		0x00040000
> +
>   /* Receive Address
>    * Number of high/low register pairs in the RAR. The RAR (Receive Address
>    * Registers) holds the directed and multicast addresses that we monitor.
> @@ -48,10 +64,26 @@
>   #define E1000_ERR_PARAM				4
>   #define E1000_ERR_MAC_INIT			5
>   #define E1000_ERR_RESET				9
> +#define E1000_ERR_MASTER_REQUESTS_PENDING	10
> +#define E1000_ERR_SWFW_SYNC			13
> +
> +/* Device Control */
> +#define E1000_CTRL_RST		0x04000000  /* Global reset */
>   
>   /* PBA constants */
>   #define E1000_PBA_34K			0x0022
>   
> +/* SW Semaphore Register */
> +#define E1000_SWSM_SMBI		0x00000001 /* Driver Semaphore bit */
> +#define E1000_SWSM_SWESMBI	0x00000002 /* FW Semaphore bit */
> +
> +/* NVM Control */
> +#define E1000_EECD_PRES		0x00000100 /* NVM Present */
> +
> +/* Number of milliseconds for NVM auto read done after MAC reset. */
> +#define AUTO_READ_DONE_TIMEOUT		10
> +#define E1000_EECD_AUTO_RD	0x00000200  /* NVM Auto Read done */
> +
>   /* Device Status */
>   #define E1000_STATUS_FD		0x00000001      /* Full duplex.0=half,1=full */
>   #define E1000_STATUS_LU		0x00000002      /* Link up.0=no,1=link */
> @@ -135,6 +167,13 @@
>   #define E1000_CT_SHIFT			4
>   #define E1000_COLLISION_THRESHOLD	15
>   
> +/* Flow Control Constants */
> +#define FLOW_CONTROL_ADDRESS_LOW	0x00C28001
> +#define FLOW_CONTROL_ADDRESS_HIGH	0x00000100
> +#define FLOW_CONTROL_TYPE		0x8808
> +/* Enable XON frame transmission */
> +#define E1000_FCRTL_XONE		0x80000000
> +
>   /* Management Control */
>   #define E1000_MANC_RCV_TCO_EN	0x00020000 /* Receive TCO Packets Enabled */
>   
> diff --git a/drivers/net/ethernet/intel/igc/e1000_hw.h b/drivers/net/ethernet/intel/igc/e1000_hw.h
> index 67fa4f696b98..debeadd61b45 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_hw.h
> +++ b/drivers/net/ethernet/intel/igc/e1000_hw.h
> @@ -6,6 +6,8 @@
>   
>   #include <linux/types.h>
>   #include <linux/if_ether.h>
> +#include <linux/netdevice.h>
> +
>   #include "e1000_regs.h"
>   #include "e1000_defines.h"
>   #include "e1000_mac.h"
> @@ -20,6 +22,16 @@ struct e1000_hw;
>   
>   /* Function pointers for the MAC. */
>   struct e1000_mac_operations {
> +	s32 (*check_for_link)(struct e1000_hw *hw);
> +	s32 (*reset_hw)(struct e1000_hw *hw);
> +	s32 (*init_hw)(struct e1000_hw *hw);
> +	s32 (*setup_physical_interface)(struct e1000_hw *hw);
> +	void (*rar_set)(struct e1000_hw *hw, u8 *address, u32 index);
> +	s32 (*read_mac_addr)(struct e1000_hw *hw);
> +	s32 (*get_speed_and_duplex)(struct e1000_hw *hw, u16 *speed,
> +				    u16 *duplex);
> +	s32 (*acquire_swfw_sync)(struct e1000_hw *hw, u16 mask);
> +	void (*release_swfw_sync)(struct e1000_hw *hw, u16 mask);
>   };
>   
>   enum e1000_mac_type {
> @@ -34,6 +46,12 @@ enum e1000_phy_type {
>   	e1000_phy_i225,
>   };
>   
> +enum e1000_nvm_type {
> +	e1000_nvm_unknown = 0,
> +	e1000_nvm_flash_hw,
> +	e1000_nvm_invm,
> +};
> +
>   enum e1000_bus_type {
>   	e1000_bus_type_unknown = 0,
>   	e1000_bus_type_pci_express,
> @@ -56,6 +74,13 @@ enum e1000_bus_width {
>   	e1000_bus_width_reserved
>   };
>   
> +struct e1000_info {
> +	s32 (*get_invariants)(struct e1000_hw *hw);
> +	struct e1000_mac_operations *mac_ops;
> +	const struct e1000_phy_operations *phy_ops;
> +	struct e1000_nvm_operations *nvm_ops;
> +};
> +
>   struct e1000_mac_info {
>   	struct e1000_mac_operations ops;
>   
> @@ -91,6 +116,30 @@ struct e1000_mac_info {
>   	bool get_link_status;
>   };
>   
> +struct e1000_nvm_operations {
> +	s32 (*acquire)(struct e1000_hw *hw);
> +	s32 (*read)(struct e1000_hw *hw, u16 offset, u16 i, u16 *data);
> +	void (*release)(struct e1000_hw *hw);
> +	s32 (*write)(struct e1000_hw *hw, u16 offset, u16 i, u16 *data);
> +	s32 (*update)(struct e1000_hw *hw);
> +	s32 (*validate)(struct e1000_hw *hw);
> +	s32 (*valid_led_default)(struct e1000_hw *hw, u16 *data);
> +};
> +
> +struct e1000_nvm_info {
> +	struct e1000_nvm_operations ops;
> +	enum e1000_nvm_type type;
> +
> +	u32 flash_bank_size;
> +	u32 flash_base_addr;
> +
> +	u16 word_size;
> +	u16 delay_usec;
> +	u16 address_bits;
> +	u16 opcode_bits;
> +	u16 page_size;
> +};
> +
>   struct e1000_bus_info {
>   	enum e1000_bus_type type;
>   	enum e1000_bus_speed speed;
> @@ -100,6 +149,32 @@ struct e1000_bus_info {
>   	u16 pci_cmd_word;
>   };
>   
> +enum e1000_fc_mode {
> +	e1000_fc_none = 0,
> +	e1000_fc_rx_pause,
> +	e1000_fc_tx_pause,
> +	e1000_fc_full,
> +	e1000_fc_default = 0xFF
> +};
> +
> +struct e1000_fc_info {
> +	u32 high_water;     /* Flow control high-water mark */
> +	u32 low_water;      /* Flow control low-water mark */
> +	u16 pause_time;     /* Flow control pause timer */
> +	bool send_xon;      /* Flow control send XON */
> +	bool strict_ieee;   /* Strict IEEE mode */
> +	enum e1000_fc_mode current_mode; /* Type of flow control */
> +	enum e1000_fc_mode requested_mode;
> +};
> +
> +struct e1000_dev_spec_base {
> +	bool global_device_reset;
> +	bool eee_disable;
> +	bool clear_semaphore_once;
> +	bool module_plugged;
> +	u8 media_port;
> +};
> +
>   struct e1000_hw {
>   	void *back;
>   
> @@ -108,9 +183,15 @@ struct e1000_hw {
>   	unsigned long io_base;
>   
>   	struct e1000_mac_info  mac;
> +	struct e1000_fc_info   fc;
> +	struct e1000_nvm_info  nvm;
>   
>   	struct e1000_bus_info bus;
>   
> +	union {
> +		struct e1000_dev_spec_base	_base;
> +	} dev_spec;
> +
>   	u16 device_id;
>   	u16 subsystem_vendor_id;
>   	u16 subsystem_device_id;
> @@ -203,6 +284,10 @@ struct e1000_hw_stats {
>   	u64 b2ogprc;
>   };
>   
> +struct net_device *igc_get_hw_dev(struct e1000_hw *hw);
> +#define hw_dbg(format, arg...) \
> +	netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
> +
>   /* These functions must be implemented by drivers */
>   s32  igc_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
>   s32  igc_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
> diff --git a/drivers/net/ethernet/intel/igc/e1000_i225.c b/drivers/net/ethernet/intel/igc/e1000_i225.c
> new file mode 100644
> index 000000000000..11d797c77619
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/igc/e1000_i225.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c)  2018 Intel Corporation */
> +
> +#include <linux/delay.h>
> +
> +#include "e1000_hw.h"
> +
> +/**
> + *  igc_get_hw_semaphore_i225 - Acquire hardware semaphore
> + *  @hw: pointer to the HW structure
> + *
> + *  Acquire the HW semaphore to access the PHY or NVM
> + */
> +static s32 igc_get_hw_semaphore_i225(struct e1000_hw *hw)
> +{
> +	u32 swsm;
> +	s32 timeout = hw->nvm.word_size + 1;
> +	s32 i = 0;

reverse xmas tree

> +
> +	/* Get the SW semaphore */
> +	while (i < timeout) {
> +		swsm = rd32(E1000_SWSM);
> +		if (!(swsm & E1000_SWSM_SMBI))
> +			break;
> +
> +		usleep_range(500, 600);
> +		i++;
> +	}
> +
> +	if (i == timeout) {
> +		/* In rare circumstances, the SW semaphore may already be held
> +		 * unintentionally. Clear the semaphore once before giving up.
> +		 */
> +		if (hw->dev_spec._base.clear_semaphore_once) {
> +			hw->dev_spec._base.clear_semaphore_once = false;
> +			igc_put_hw_semaphore(hw);
> +			for (i = 0; i < timeout; i++) {
> +				swsm = rd32(E1000_SWSM);
> +				if (!(swsm & E1000_SWSM_SMBI))
> +					break;
> +
> +				usleep_range(500, 600);
> +			}
> +		}
> +
> +		/* If we do not have the semaphore here, we have to give up. */
> +		if (i == timeout) {
> +			hw_dbg("Driver can't access device - SMBI bit is set.\n");
> +			return -E1000_ERR_NVM;
> +		}
> +	}
> +
> +	/* Get the FW semaphore. */
> +	for (i = 0; i < timeout; i++) {
> +		swsm = rd32(E1000_SWSM);
> +		wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
> +
> +		/* Semaphore acquired if bit latched */
> +		if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
> +			break;
> +
> +		usleep_range(500, 600);
> +	}
> +
> +	if (i == timeout) {
> +		/* Release semaphores */
> +		igc_put_hw_semaphore(hw);
> +		hw_dbg("Driver can't access the NVM\n");
> +		return -E1000_ERR_NVM;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + *  igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
> + *  @hw: pointer to the HW structure
> + *  @mask: specifies which semaphore to acquire
> + *
> + *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
> + *  will also specify which port we're acquiring the lock for.
> + **/
> +s32 igc_acquire_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
> +{
> +	u32 swfw_sync;
> +	u32 swmask = mask;
> +	u32 fwmask = mask << 16;
> +	s32 ret_val = 0;
> +	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
> +
> +	while (i < timeout) {
> +		if (igc_get_hw_semaphore_i225(hw)) {
> +			ret_val = -E1000_ERR_SWFW_SYNC;
> +			goto out;
> +		}
> +
> +		swfw_sync = rd32(E1000_SW_FW_SYNC);
> +		if (!(swfw_sync & (fwmask | swmask)))
> +			break;
> +
> +		/* Firmware currently using resource (fwmask) */
> +		igc_put_hw_semaphore(hw);
> +		mdelay(5);
> +		i++;
> +	}
> +
> +	if (i == timeout) {
> +		hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
> +		ret_val = -E1000_ERR_SWFW_SYNC;
> +		goto out;
> +	}
> +
> +	swfw_sync |= swmask;
> +	wr32(E1000_SW_FW_SYNC, swfw_sync);
> +
> +	igc_put_hw_semaphore(hw);
> +out:
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_release_swfw_sync_i225 - Release SW/FW semaphore
> + *  @hw: pointer to the HW structure
> + *  @mask: specifies which semaphore to acquire
> + *
> + *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
> + *  will also specify which port we're releasing the lock for.
> + **/
> +void igc_release_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
> +{
> +	u32 swfw_sync;
> +
> +	while (igc_get_hw_semaphore_i225(hw))
> +		; /* Empty */

This loop needs a bounding condition

> +
> +	swfw_sync = rd32(E1000_SW_FW_SYNC);
> +	swfw_sync &= ~mask;
> +	wr32(E1000_SW_FW_SYNC, swfw_sync);
> +
> +	igc_put_hw_semaphore(hw);
> +}
> diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.c b/drivers/net/ethernet/intel/igc/e1000_mac.c
> index c38435bb8a8c..27e478a9854c 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_mac.c
> +++ b/drivers/net/ethernet/intel/igc/e1000_mac.c
> @@ -2,8 +2,15 @@
>   /* Copyright (c)  2018 Intel Corporation */
>   
>   #include <linux/pci.h>
> +#include <linux/delay.h>
> +
> +#include "e1000_mac.h"
>   #include "e1000_hw.h"
>   
> +/* forward declaration */
> +static s32 igc_set_default_fc(struct e1000_hw *hw);
> +static s32 igc_set_fc_watermarks(struct e1000_hw *hw);
> +
>   /**
>    *  igc_get_bus_info_pcie - Get PCIe bus information
>    *  @hw: pointer to the HW structure
> @@ -49,3 +56,316 @@ s32 igc_get_bus_info_pcie(struct e1000_hw *hw)
>   
>   	return 0;
>   }
> +
> +/**
> + *  igc_disable_pcie_master - Disables PCI-express master access
> + *  @hw: pointer to the HW structure
> + *
> + *  Returns 0 (0) if successful, else returns -10
> + *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
> + *  the master requests to be disabled.
> + *
> + *  Disables PCI-Express master access and verifies there are no pending
> + *  requests.
> + **/
> +s32 igc_disable_pcie_master(struct e1000_hw *hw)
> +{
> +	u32 ctrl;
> +	s32 timeout = MASTER_DISABLE_TIMEOUT;
> +	s32 ret_val = 0;
> +
> +	if (hw->bus.type != e1000_bus_type_pci_express)
> +		goto out;
> +
> +	ctrl = rd32(E1000_CTRL);
> +	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
> +	wr32(E1000_CTRL, ctrl);
> +
> +	while (timeout) {
> +		if (!(rd32(E1000_STATUS) &
> +		    E1000_STATUS_GIO_MASTER_ENABLE))
> +			break;
> +		usleep_range(2000, 3000);
> +		timeout--;
> +	}
> +
> +	if (!timeout) {
> +		hw_dbg("Master requests are pending.\n");
> +		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
> +		goto out;
> +	}
> +
> +out:
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_init_rx_addrs - Initialize receive address's

s/address's/addresses/

> + *  @hw: pointer to the HW structure
> + *  @rar_count: receive address registers
> + *
> + *  Setups the receive address registers by setting the base receive address

s/Setups/Setup/

> + *  register to the devices MAC address and clearing all the other receive
> + *  address registers to 0.
> + **/
> +void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
> +{
> +	u32 i;
> +	u8 mac_addr[ETH_ALEN] = {0};
> +
> +	/* Setup the receive address */
> +	hw_dbg("Programming MAC Address into RAR[0]\n");
> +
> +	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
> +
> +	/* Zero out the other (rar_entry_count - 1) receive addresses */
> +	hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
> +	for (i = 1; i < rar_count; i++)
> +		hw->mac.ops.rar_set(hw, mac_addr, i);
> +}
> +
> +/**
> + *  igc_setup_link - Setup flow control and link settings
> + *  @hw: pointer to the HW structure
> + *
> + *  Determines which flow control settings to use, then configures flow
> + *  control.  Calls the appropriate media-specific link configuration
> + *  function.  Assuming the adapter has a valid link partner, a valid link
> + *  should be established.  Assumes the hardware has previously been reset
> + *  and the transmitter and receiver are not enabled.
> + **/
> +s32 igc_setup_link(struct e1000_hw *hw)
> +{
> +	s32 ret_val = 0;
> +
> +	/* In the case of the phy reset being blocked, we already have a link.
> +	 * We do not need to set it up again.
> +	 */
> +
> +	/* If requested flow control is set to default, set flow control
> +	 * based on the EEPROM flow control settings.
> +	 */
> +	if (hw->fc.requested_mode == e1000_fc_default) {
> +		ret_val = igc_set_default_fc(hw);
> +		if (ret_val)
> +			goto out;
> +	}
> +
> +	/* We want to save off the original Flow Control configuration just
> +	 * in case we get disconnected and then reconnected into a different
> +	 * hub or switch with different Flow Control capabilities.
> +	 */
> +	hw->fc.current_mode = hw->fc.requested_mode;
> +
> +	hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
> +
> +	/* Call the necessary media_type subroutine to configure the link. */
> +	ret_val = hw->mac.ops.setup_physical_interface(hw);
> +	if (ret_val)
> +		goto out;
> +
> +	/* Initialize the flow control address, type, and PAUSE timer
> +	 * registers to their default values.  This is done even if flow
> +	 * control is disabled, because it does not hurt anything to
> +	 * initialize these registers.
> +	 */
> +	hw_dbg("Initializing the Flow Control address, type and timer regs\n");
> +	wr32(E1000_FCT, FLOW_CONTROL_TYPE);
> +	wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
> +	wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
> +
> +	wr32(E1000_FCTTV, hw->fc.pause_time);
> +
> +	ret_val = igc_set_fc_watermarks(hw);
> +
> +out:
> +
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_set_default_fc - Set flow control default values
> + *  @hw: pointer to the HW structure
> + *
> + *  Read the EEPROM for the default values for flow control and store the
> + *  values.
> + **/
> +static s32 igc_set_default_fc(struct e1000_hw *hw)
> +{
> +	return 0;
> +}
> +
> +/**
> + *  igc_set_fc_watermarks - Set flow control high/low watermarks
> + *  @hw: pointer to the HW structure
> + *
> + *  Sets the flow control high/low threshold (watermark) registers.  If
> + *  flow control XON frame transmission is enabled, then set XON frame
> + *  tansmission as well.

s/tansmission/transmission/

> + **/
> +static s32 igc_set_fc_watermarks(struct e1000_hw *hw)
> +{
> +	s32 ret_val = 0;
> +	u32 fcrtl = 0, fcrth = 0;
> +
> +	/* Set the flow control receive threshold registers.  Normally,
> +	 * these registers will be set to a default threshold that may be
> +	 * adjusted later by the driver's runtime code.  However, if the
> +	 * ability to transmit pause frames is not enabled, then these
> +	 * registers will be set to 0.
> +	 */
> +	if (hw->fc.current_mode & e1000_fc_tx_pause) {
> +		/* We need to set up the Receive Threshold high and low water
> +		 * marks as well as (optionally) enabling the transmission of
> +		 * XON frames.
> +		 */
> +		fcrtl = hw->fc.low_water;
> +		if (hw->fc.send_xon)
> +			fcrtl |= E1000_FCRTL_XONE;
> +
> +		fcrth = hw->fc.high_water;
> +	}
> +	wr32(E1000_FCRTL, fcrtl);
> +	wr32(E1000_FCRTH, fcrth);
> +
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_clear_hw_cntrs_base - Clear base hardware counters
> + *  @hw: pointer to the HW structure
> + *
> + *  Clears the base hardware counters by reading the counter registers.
> + **/
> +void igc_clear_hw_cntrs_base(struct e1000_hw *hw)
> +{
> +	rd32(E1000_CRCERRS);
> +	rd32(E1000_SYMERRS);
> +	rd32(E1000_MPC);
> +	rd32(E1000_SCC);
> +	rd32(E1000_ECOL);
> +	rd32(E1000_MCC);
> +	rd32(E1000_LATECOL);
> +	rd32(E1000_COLC);
> +	rd32(E1000_DC);
> +	rd32(E1000_SEC);
> +	rd32(E1000_RLEC);
> +	rd32(E1000_XONRXC);
> +	rd32(E1000_XONTXC);
> +	rd32(E1000_XOFFRXC);
> +	rd32(E1000_XOFFTXC);
> +	rd32(E1000_FCRUC);
> +	rd32(E1000_GPRC);
> +	rd32(E1000_BPRC);
> +	rd32(E1000_MPRC);
> +	rd32(E1000_GPTC);
> +	rd32(E1000_GORCL);
> +	rd32(E1000_GORCH);
> +	rd32(E1000_GOTCL);
> +	rd32(E1000_GOTCH);
> +	rd32(E1000_RNBC);
> +	rd32(E1000_RUC);
> +	rd32(E1000_RFC);
> +	rd32(E1000_ROC);
> +	rd32(E1000_RJC);
> +	rd32(E1000_TORL);
> +	rd32(E1000_TORH);
> +	rd32(E1000_TOTL);
> +	rd32(E1000_TOTH);
> +	rd32(E1000_TPR);
> +	rd32(E1000_TPT);
> +	rd32(E1000_MPTC);
> +	rd32(E1000_BPTC);
> +
> +	rd32(E1000_PRC64);
> +	rd32(E1000_PRC127);
> +	rd32(E1000_PRC255);
> +	rd32(E1000_PRC511);
> +	rd32(E1000_PRC1023);
> +	rd32(E1000_PRC1522);
> +	rd32(E1000_PTC64);
> +	rd32(E1000_PTC127);
> +	rd32(E1000_PTC255);
> +	rd32(E1000_PTC511);
> +	rd32(E1000_PTC1023);
> +	rd32(E1000_PTC1522);
> +
> +	rd32(E1000_ALGNERRC);
> +	rd32(E1000_RXERRC);
> +	rd32(E1000_TNCRS);
> +	rd32(E1000_CEXTERR);
> +	rd32(E1000_TSCTC);
> +	rd32(E1000_TSCTFC);
> +
> +	rd32(E1000_MGTPRC);
> +	rd32(E1000_MGTPDC);
> +	rd32(E1000_MGTPTC);
> +
> +	rd32(E1000_IAC);
> +	rd32(E1000_ICRXOC);
> +
> +	rd32(E1000_ICRXPTC);
> +	rd32(E1000_ICRXATC);
> +	rd32(E1000_ICTXPTC);
> +	rd32(E1000_ICTXATC);
> +	rd32(E1000_ICTXQEC);
> +	rd32(E1000_ICTXQMTC);
> +	rd32(E1000_ICRXDMTC);
> +
> +	rd32(E1000_CBTMPC);
> +	rd32(E1000_HTDPMC);
> +	rd32(E1000_CBRMPC);
> +	rd32(E1000_RPTHC);
> +	rd32(E1000_HGPTC);
> +	rd32(E1000_HTCBDPC);
> +	rd32(E1000_HGORCL);
> +	rd32(E1000_HGORCH);
> +	rd32(E1000_HGOTCL);
> +	rd32(E1000_HGOTCH);
> +	rd32(E1000_LENERRS);
> +}
> +
> +/**
> + *  igc_get_auto_rd_done - Check for auto read completion
> + *  @hw: pointer to the HW structure
> + *
> + *  Check EEPROM for Auto Read done bit.
> + **/
> +s32 igc_get_auto_rd_done(struct e1000_hw *hw)
> +{
> +	s32 i = 0;
> +	s32 ret_val = 0;
> +
> +	while (i < AUTO_READ_DONE_TIMEOUT) {
> +		if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD)
> +			break;
> +		usleep_range(1000, 2000);
> +		i++;
> +	}
> +
> +	if (i == AUTO_READ_DONE_TIMEOUT) {
> +		hw_dbg("Auto read by HW from NVM has not completed.\n");
> +		ret_val = -E1000_ERR_RESET;
> +		goto out;
> +	}
> +
> +out:
> +	return ret_val;
> +}
> +
> +/**
> + *  igc_put_hw_semaphore - Release hardware semaphore
> + *  @hw: pointer to the HW structure
> + *
> + *  Release hardware semaphore used to access the PHY or NVM
> + **/
> +void igc_put_hw_semaphore(struct e1000_hw *hw)
> +{
> +	u32 swsm;
> +
> +	swsm = rd32(E1000_SWSM);
> +
> +	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
> +
> +	wr32(E1000_SWSM, swsm);
> +}
> diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.h b/drivers/net/ethernet/intel/igc/e1000_mac.h
> index afb0f7b28222..2f8dbf17800a 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_mac.h
> +++ b/drivers/net/ethernet/intel/igc/e1000_mac.h
> @@ -4,10 +4,21 @@
>   #ifndef _E1000_MAC_H_
>   #define _E1000_MAC_H_
>   
> +#include "e1000_hw.h"
> +#include "e1000_defines.h"
> +
>   #ifndef E1000_REMOVED
>   #define E1000_REMOVED(a) (0)
>   #endif /* E1000_REMOVED */
>   
> -s32 igc_get_bus_info_pcie(struct e1000_hw *hw);
> +/* forward declaration */
> +s32  igc_disable_pcie_master(struct e1000_hw *hw);
> +void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
> +s32  igc_setup_link(struct e1000_hw *hw);
> +void igc_clear_hw_cntrs_base(struct e1000_hw *hw);
> +s32 igc_get_auto_rd_done(struct e1000_hw *hw);
> +void igc_put_hw_semaphore(struct e1000_hw *hw);
> +
> +s32  igc_get_bus_info_pcie(struct e1000_hw *hw);
>   
>   #endif
> diff --git a/drivers/net/ethernet/intel/igc/e1000_regs.h b/drivers/net/ethernet/intel/igc/e1000_regs.h
> index dcc4d89c9933..66d5c757dae8 100644
> --- a/drivers/net/ethernet/intel/igc/e1000_regs.h
> +++ b/drivers/net/ethernet/intel/igc/e1000_regs.h
> @@ -7,6 +7,7 @@
>   /* General Register Descriptions */
>   #define E1000_CTRL		0x00000  /* Device Control - RW */
>   #define E1000_STATUS		0x00008  /* Device Status - RO */
> +#define E1000_EECD		0x00010  /* EEPROM/Flash Control - RW */
>   #define E1000_CTRL_EXT		0x00018  /* Extended Device Control - RW */
>   #define E1000_MDIC		0x00020  /* MDI Control - RW */
>   #define E1000_MDICNFG		0x00E04  /* MDC/MDIO Configuration - RW */
> @@ -75,6 +76,30 @@
>   #define E1000_IVAR_MISC		0x01740   /* IVAR for "other" causes - RW */
>   #define E1000_GPIE		0x01514  /* General Purpose Intr Enable - RW */
>   
> +/* Interrupt Cause Rx Packet Timer Expire Count */
> +#define E1000_ICRXPTC		0x04104
> +/* Interrupt Cause Rx Absolute Timer Expire Count */
> +#define E1000_ICRXATC		0x04108
> +/* Interrupt Cause Tx Packet Timer Expire Count */
> +#define E1000_ICTXPTC		0x0410C
> +/* Interrupt Cause Tx Absolute Timer Expire Count */
> +#define E1000_ICTXATC		0x04110
> +/* Interrupt Cause Tx Queue Empty Count */
> +#define E1000_ICTXQEC		0x04118
> +/* Interrupt Cause Tx Queue Minimum Threshold Count */
> +#define E1000_ICTXQMTC		0x0411C
> +/* Interrupt Cause Rx Descriptor Minimum Threshold Count */
> +#define E1000_ICRXDMTC		0x04120
> +/* Interrupt Cause Receiver Overrun Count */
> +#define E1000_ICRXOC		0x04124

These comments intersperced make the #defines hard to read - putting 
them off to the side would help a lot.

> +
> +#define E1000_CBTMPC		0x0402C  /* Circuit Breaker TX Packet Count */
> +#define E1000_HTDPMC		0x0403C  /* Host Transmit Discarded Packets */
> +#define E1000_CBRMPC		0x040FC  /* Circuit Breaker RX Packet Count */
> +#define E1000_RPTHC		0x04104  /* Rx Packets To Host */
> +#define E1000_HGPTC		0x04118  /* Host Good Packets TX Count */
> +#define E1000_HTCBDPC		0x04124  /* Host TX Circ.Breaker Drop Count */
> +
>   /* MSI-X Table Register Descriptions */
>   #define E1000_PBACL		0x05B68  /* MSIx PBA Clear - R/W 1 to clear */
>   
> @@ -92,6 +117,8 @@
>   #define E1000_RXCSUM		0x05000  /* Rx Checksum Control - RW */
>   #define E1000_RLPML		0x05004  /* Rx Long Packet Max Length */
>   #define E1000_RFCTL		0x05008  /* Receive Filter Control*/
> +#define E1000_MTA		0x05200  /* Multicast Table Array - RW Array */
> +#define E1000_UTA		0x0A000 /* Unicast Table Array - RW */
>   #define E1000_RAL(_n)		(0x05400 + ((_n) * 0x08))
>   #define E1000_RAH(_n)		(0x05404 + ((_n) * 0x08))
>   #define E1000_VLAPQF		0x055B0  /* VLAN Priority Queuue - RW */
> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
> index 67826041eb3c..9a99c7d68796 100644
> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> @@ -86,6 +86,14 @@ enum latency_range {
>   
>   void igc_reset(struct igc_adapter *adapter)
>   {
> +	struct pci_dev *pdev = adapter->pdev;
> +	struct e1000_hw *hw = &adapter->hw;
> +
> +	hw->mac.ops.reset_hw(hw);
> +
> +	if (hw->mac.ops.init_hw(hw))
> +		dev_err(&pdev->dev, "Hardware Error\n");

Is there something more specific that can be said here, including 
something about it being the init that failed?

> +
>   	if (!netif_running(adapter->netdev))
>   		igc_power_down_link(adapter);
>   }
> @@ -3621,6 +3629,19 @@ static void igc_nfc_filter_exit(struct igc_adapter *adapter)
>   }
>   
>   /**
> + *  igc_get_hw_dev - return device
> + *  @hw: pointer to hardware structure
> + *
> + *  used by hardware layer to print debugging information
> + **/
> +struct net_device *igc_get_hw_dev(struct e1000_hw *hw)
> +{
> +	struct igc_adapter *adapter = hw->back;
> +
> +	return adapter->netdev;

I think this can either become a #define or an inline in a .h file

> +}
> +
> +/**
>    *  igc_init_module - Driver Registration Routine
>    *
>    *  igc_init_module is the first routine called when the driver is
>
Sasha Neftin July 4, 2018, 1:39 p.m. UTC | #3
On 6/29/2018 01:25, Shannon Nelson wrote:
> On 6/24/2018 1:45 AM, Sasha Neftin wrote:
>> Add code for hw initialization and reset.
>> Add code for semaphore handling.
>>
>> Sasha Neftin (v2):
>> fixed code indentation
>> refactor of igc_desc_unused method
>>
>> Sasha Neftin (v3):
>> clean code and remove unused methods
>>
>> Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
>> ---
>>   drivers/net/ethernet/intel/igc/Makefile        |   3 +-
>>   drivers/net/ethernet/intel/igc/e1000_base.c    | 198 +++++++++++++++
>>   drivers/net/ethernet/intel/igc/e1000_base.h    |   2 +
>>   drivers/net/ethernet/intel/igc/e1000_defines.h |  39 +++
>>   drivers/net/ethernet/intel/igc/e1000_hw.h      |  85 +++++++
>>   drivers/net/ethernet/intel/igc/e1000_i225.c    | 141 +++++++++++
>>   drivers/net/ethernet/intel/igc/e1000_mac.c     | 320 
>> +++++++++++++++++++++++++
>>   drivers/net/ethernet/intel/igc/e1000_mac.h     |  13 +-
>>   drivers/net/ethernet/intel/igc/e1000_regs.h    |  27 +++
>>   drivers/net/ethernet/intel/igc/igc_main.c      |  21 ++
>>   10 files changed, 846 insertions(+), 3 deletions(-)
>>   create mode 100644 drivers/net/ethernet/intel/igc/e1000_i225.c
>>
>> diff --git a/drivers/net/ethernet/intel/igc/Makefile 
>> b/drivers/net/ethernet/intel/igc/Makefile
>> index 6a757ac8492d..cb260bedfa37 100644
>> --- a/drivers/net/ethernet/intel/igc/Makefile
>> +++ b/drivers/net/ethernet/intel/igc/Makefile
>> @@ -7,5 +7,4 @@
>>   obj-$(CONFIG_IGC) += igc.o
>> -igc-objs := igc_main.o e1000_mac.o \
>> -e1000_base.o
>> +igc-objs := igc_main.o e1000_mac.o e1000_i225.o e1000_base.o
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_base.c 
>> b/drivers/net/ethernet/intel/igc/e1000_base.c
>> index 265ec98000e7..395d7ce70bb4 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_base.c
>> +++ b/drivers/net/ethernet/intel/igc/e1000_base.c
>> @@ -5,6 +5,92 @@
>>   #include "e1000_hw.h"
>>   #include "e1000_i225.h"
>> +#include "e1000_mac.h"
>> +#include "e1000_base.h"
>> +#include "igc.h"
>> +
>> +/* forward declaration */
>> +static s32 igc_get_invariants_base(struct e1000_hw *);
>> +static s32 igc_init_hw_base(struct e1000_hw *);
>> +static s32 igc_reset_hw_base(struct e1000_hw *);
>> +static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw);
>> +
>> +/**
>> + *  igc_init_mac_params_base - Init MAC func ptrs.
>> + *  @hw: pointer to the HW structure
>> + **/
>> +static s32 igc_init_mac_params_base(struct e1000_hw *hw)
>> +{
>> +    struct e1000_mac_info *mac = &hw->mac;
>> +
>> +    /* Set mta register count */
>> +    mac->mta_reg_count = 128;
>> +    mac->rar_entry_count = E1000_RAR_ENTRIES;
>> +
>> +    /* reset */
>> +    mac->ops.reset_hw = igc_reset_hw_base;
>> +
>> +    mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
>> +    mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
>> +
>> +    return 0;
>> +}
>> +
>> +static s32 igc_get_invariants_base(struct e1000_hw *hw)
>> +{
>> +    s32 ret_val = 0;
>> +    u32 ctrl_ext = 0;
>> +    u32 link_mode = 0;
>> +
>> +    ctrl_ext = rd32(E1000_CTRL_EXT);
>> +    link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
>> +
>> +    /* mac initialization and operations */
>> +    ret_val = igc_init_mac_params_base(hw);
>> +    if (ret_val)
>> +        goto out;
>> +
>> +out:
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_init_hw_base - Initialize hardware
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  This inits the hardware readying it for operation.
>> + **/
>> +static s32 igc_init_hw_base(struct e1000_hw *hw)
>> +{
>> +    struct e1000_mac_info *mac = &hw->mac;
>> +    s32 ret_val = 0;
>> +    u16 i, rar_count = mac->rar_entry_count;
>> +
>> +    /* Setup the receive address */
>> +    igc_init_rx_addrs(hw, rar_count);
>> +
>> +    /* Zero out the Multicast HASH table */
>> +    hw_dbg("Zeroing the MTA\n");
>> +    for (i = 0; i < mac->mta_reg_count; i++)
>> +        array_wr32(E1000_MTA, i, 0);
>> +
>> +    /* Zero out the Unicast HASH table */
>> +    hw_dbg("Zeroing the UTA\n");
>> +    for (i = 0; i < mac->uta_reg_count; i++)
>> +        array_wr32(E1000_UTA, i, 0);
>> +
>> +    /* Setup link and flow control */
>> +    ret_val = igc_setup_link(hw);
>> +
>> +    /* Clear all of the statistics registers (clear on read).  It is
>> +     * important that we do this after we have tried to establish link
>> +     * because the symbol error count will increment wildly if there
>> +     * is no link.
>> +     */
>> +    igc_clear_hw_cntrs_base(hw);
>> +
>> +    return ret_val;
>> +}
>>   /**
>>    *  igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
>> @@ -81,3 +167,115 @@ void igc_rx_fifo_flush_base(struct e1000_hw *hw)
>>       rd32(E1000_RNBC);
>>       rd32(E1000_MPC);
>>   }
>> +
>> +static struct e1000_mac_operations e1000_mac_ops_base = {
>> +    .init_hw    = igc_init_hw_base,
>> +};
>> +
>> +const struct e1000_info e1000_base_info = {
>> +    .get_invariants = igc_get_invariants_base,
>> +    .mac_ops = &e1000_mac_ops_base,
>> +};
>> +
>> +/**
>> + *  igc_reset_hw_base - Reset hardware
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  This resets the hardware into a known state.  This is a
>> + *  function pointer entry point called by the api module.
>> + **/
>> +static s32 igc_reset_hw_base(struct e1000_hw *hw)
>> +{
>> +    u32 ctrl;
>> +    s32 ret_val;
>> +
>> +    /* Prevent the PCI-E bus from sticking if there is no TLP connection
>> +     * on the last TLP read/write transaction when MAC is reset.
>> +     */
>> +    ret_val = igc_disable_pcie_master(hw);
>> +    if (ret_val)
>> +        hw_dbg("PCI-E Master disable polling has failed.\n");
>> +
>> +    /* set the completion timeout for interface */
>> +    ret_val = igc_set_pcie_completion_timeout(hw);
>> +    if (ret_val)
>> +        hw_dbg("PCI-E Set completion timeout has failed.\n");
>> +
>> +    hw_dbg("Masking off all interrupts\n");
>> +    wr32(E1000_IMC, 0xffffffff);
>> +
>> +    wr32(E1000_RCTL, 0);
>> +    wr32(E1000_TCTL, E1000_TCTL_PSP);
>> +    wrfl();
>> +
>> +    usleep_range(10000, 20000);
>> +
>> +    ctrl = rd32(E1000_CTRL);
>> +
>> +    hw_dbg("Issuing a global reset to MAC\n");
>> +    wr32(E1000_CTRL, ctrl | E1000_CTRL_RST);
>> +
>> +    ret_val = igc_get_auto_rd_done(hw);
>> +    if (ret_val) {
>> +        /* When auto config read does not complete, do not
>> +         * return with an error. This can happen in situations
>> +         * where there is no eeprom and prevents getting link.
>> +         */
>> +        hw_dbg("Auto Read Done did not complete\n");
>> +    }
>> +
>> +    /* Clear any pending interrupt events. */
>> +    wr32(E1000_IMC, 0xffffffff);
>> +    rd32(E1000_ICR);
>> +
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_set_pcie_completion_timeout - set pci-e completion timeout
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  The defaults for 82575 and 82576 should be in the range of 50us 
>> to 50ms,
> 
> Wrong devices
> 
> Since this is copy-n-paste from the previous driver, is this even correct?
> 
Right. Should be gone. fix will be applied in v4.
>> + *  however the hardware default for these parts is 500us to 1ms 
>> which is less
>> + *  than the 10ms recommended by the pci-e spec.  To address this we 
>> need to
>> + *  increase the value to either 10ms to 200ms for capability version 
>> 1 config,
>> + *  or 16ms to 55ms for version 2.
>> + **/
>> +static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw)
>> +{
>> +    u32 gcr = rd32(E1000_GCR);
>> +    s32 ret_val = 0;
>> +    u16 pcie_devctl2;
>> +
>> +    /* only take action if timeout value is defaulted to 0 */
>> +    if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
>> +        goto out;
>> +
>> +    /* if capabilities version is type 1 we can write the
>> +     * timeout of 10ms to 200ms through the GCR register
>> +     */
>> +    if (!(gcr & E1000_GCR_CAP_VER2)) {
>> +        gcr |= E1000_GCR_CMPL_TMOUT_10ms;
>> +        goto out;
>> +    }
>> +
>> +    /* for version 2 capabilities we need to write the config space
>> +     * directly in order to set the completion timeout value for
>> +     * 16ms to 55ms
>> +     */
>> +    ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
>> +                    &pcie_devctl2);
>> +    if (ret_val)
>> +        goto out;
>> +
>> +    pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
>> +
>> +    ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
>> +                     &pcie_devctl2);
>> +out:
>> +    /* disable completion timeout resend */
>> +    gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
>> +
>> +    wr32(E1000_GCR, gcr);
>> +    return ret_val;
>> +}
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_base.h 
>> b/drivers/net/ethernet/intel/igc/e1000_base.h
>> index 5c766fb7514b..210f1b5f6012 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_base.h
>> +++ b/drivers/net/ethernet/intel/igc/e1000_base.h
>> @@ -33,6 +33,8 @@ union e1000_adv_tx_desc {
>>   #define E1000_ADVTXD_DCMD_TSE    0x80000000 /* TCP Seg enable */
>>   #define E1000_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
>> +#define E1000_RAR_ENTRIES        16
>> +
>>   struct e1000_adv_data_desc {
>>       __le64 buffer_addr;    /* Address of the descriptor's data 
>> buffer */
>>       union {
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_defines.h 
>> b/drivers/net/ethernet/intel/igc/e1000_defines.h
>> index f39d93d17ba6..5613806742b1 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_defines.h
>> +++ b/drivers/net/ethernet/intel/igc/e1000_defines.h
>> @@ -30,6 +30,22 @@
>>   #define E1000_PCI_PMCSR            0x44
>>   #define E1000_PCI_PMCSR_D3        0x03
>> +/* Physical Func Reset Done Indication */
>> +#define E1000_CTRL_EXT_LINK_MODE_MASK    0x00C00000
>> +
>> +/* Number of 100 microseconds we wait for PCI Express master disable */
>> +#define MASTER_DISABLE_TIMEOUT        800
>> +/*Blocks new Master requests */
>> +#define E1000_CTRL_GIO_MASTER_DISABLE    0x00000004
>> +/* Status of Master requests. */
>> +#define E1000_STATUS_GIO_MASTER_ENABLE    0x00080000
>> +
>> +/* PCI Express Control */
>> +#define E1000_GCR_CMPL_TMOUT_MASK    0x0000F000
>> +#define E1000_GCR_CMPL_TMOUT_10ms    0x00001000
>> +#define E1000_GCR_CMPL_TMOUT_RESEND    0x00010000
>> +#define E1000_GCR_CAP_VER2        0x00040000
>> +
>>   /* Receive Address
>>    * Number of high/low register pairs in the RAR. The RAR (Receive 
>> Address
>>    * Registers) holds the directed and multicast addresses that we 
>> monitor.
>> @@ -48,10 +64,26 @@
>>   #define E1000_ERR_PARAM                4
>>   #define E1000_ERR_MAC_INIT            5
>>   #define E1000_ERR_RESET                9
>> +#define E1000_ERR_MASTER_REQUESTS_PENDING    10
>> +#define E1000_ERR_SWFW_SYNC            13
>> +
>> +/* Device Control */
>> +#define E1000_CTRL_RST        0x04000000  /* Global reset */
>>   /* PBA constants */
>>   #define E1000_PBA_34K            0x0022
>> +/* SW Semaphore Register */
>> +#define E1000_SWSM_SMBI        0x00000001 /* Driver Semaphore bit */
>> +#define E1000_SWSM_SWESMBI    0x00000002 /* FW Semaphore bit */
>> +
>> +/* NVM Control */
>> +#define E1000_EECD_PRES        0x00000100 /* NVM Present */
>> +
>> +/* Number of milliseconds for NVM auto read done after MAC reset. */
>> +#define AUTO_READ_DONE_TIMEOUT        10
>> +#define E1000_EECD_AUTO_RD    0x00000200  /* NVM Auto Read done */
>> +
>>   /* Device Status */
>>   #define E1000_STATUS_FD        0x00000001      /* Full 
>> duplex.0=half,1=full */
>>   #define E1000_STATUS_LU        0x00000002      /* Link 
>> up.0=no,1=link */
>> @@ -135,6 +167,13 @@
>>   #define E1000_CT_SHIFT            4
>>   #define E1000_COLLISION_THRESHOLD    15
>> +/* Flow Control Constants */
>> +#define FLOW_CONTROL_ADDRESS_LOW    0x00C28001
>> +#define FLOW_CONTROL_ADDRESS_HIGH    0x00000100
>> +#define FLOW_CONTROL_TYPE        0x8808
>> +/* Enable XON frame transmission */
>> +#define E1000_FCRTL_XONE        0x80000000
>> +
>>   /* Management Control */
>>   #define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets 
>> Enabled */
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_hw.h 
>> b/drivers/net/ethernet/intel/igc/e1000_hw.h
>> index 67fa4f696b98..debeadd61b45 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_hw.h
>> +++ b/drivers/net/ethernet/intel/igc/e1000_hw.h
>> @@ -6,6 +6,8 @@
>>   #include <linux/types.h>
>>   #include <linux/if_ether.h>
>> +#include <linux/netdevice.h>
>> +
>>   #include "e1000_regs.h"
>>   #include "e1000_defines.h"
>>   #include "e1000_mac.h"
>> @@ -20,6 +22,16 @@ struct e1000_hw;
>>   /* Function pointers for the MAC. */
>>   struct e1000_mac_operations {
>> +    s32 (*check_for_link)(struct e1000_hw *hw);
>> +    s32 (*reset_hw)(struct e1000_hw *hw);
>> +    s32 (*init_hw)(struct e1000_hw *hw);
>> +    s32 (*setup_physical_interface)(struct e1000_hw *hw);
>> +    void (*rar_set)(struct e1000_hw *hw, u8 *address, u32 index);
>> +    s32 (*read_mac_addr)(struct e1000_hw *hw);
>> +    s32 (*get_speed_and_duplex)(struct e1000_hw *hw, u16 *speed,
>> +                    u16 *duplex);
>> +    s32 (*acquire_swfw_sync)(struct e1000_hw *hw, u16 mask);
>> +    void (*release_swfw_sync)(struct e1000_hw *hw, u16 mask);
>>   };
>>   enum e1000_mac_type {
>> @@ -34,6 +46,12 @@ enum e1000_phy_type {
>>       e1000_phy_i225,
>>   };
>> +enum e1000_nvm_type {
>> +    e1000_nvm_unknown = 0,
>> +    e1000_nvm_flash_hw,
>> +    e1000_nvm_invm,
>> +};
>> +
>>   enum e1000_bus_type {
>>       e1000_bus_type_unknown = 0,
>>       e1000_bus_type_pci_express,
>> @@ -56,6 +74,13 @@ enum e1000_bus_width {
>>       e1000_bus_width_reserved
>>   };
>> +struct e1000_info {
>> +    s32 (*get_invariants)(struct e1000_hw *hw);
>> +    struct e1000_mac_operations *mac_ops;
>> +    const struct e1000_phy_operations *phy_ops;
>> +    struct e1000_nvm_operations *nvm_ops;
>> +};
>> +
>>   struct e1000_mac_info {
>>       struct e1000_mac_operations ops;
>> @@ -91,6 +116,30 @@ struct e1000_mac_info {
>>       bool get_link_status;
>>   };
>> +struct e1000_nvm_operations {
>> +    s32 (*acquire)(struct e1000_hw *hw);
>> +    s32 (*read)(struct e1000_hw *hw, u16 offset, u16 i, u16 *data);
>> +    void (*release)(struct e1000_hw *hw);
>> +    s32 (*write)(struct e1000_hw *hw, u16 offset, u16 i, u16 *data);
>> +    s32 (*update)(struct e1000_hw *hw);
>> +    s32 (*validate)(struct e1000_hw *hw);
>> +    s32 (*valid_led_default)(struct e1000_hw *hw, u16 *data);
>> +};
>> +
>> +struct e1000_nvm_info {
>> +    struct e1000_nvm_operations ops;
>> +    enum e1000_nvm_type type;
>> +
>> +    u32 flash_bank_size;
>> +    u32 flash_base_addr;
>> +
>> +    u16 word_size;
>> +    u16 delay_usec;
>> +    u16 address_bits;
>> +    u16 opcode_bits;
>> +    u16 page_size;
>> +};
>> +
>>   struct e1000_bus_info {
>>       enum e1000_bus_type type;
>>       enum e1000_bus_speed speed;
>> @@ -100,6 +149,32 @@ struct e1000_bus_info {
>>       u16 pci_cmd_word;
>>   };
>> +enum e1000_fc_mode {
>> +    e1000_fc_none = 0,
>> +    e1000_fc_rx_pause,
>> +    e1000_fc_tx_pause,
>> +    e1000_fc_full,
>> +    e1000_fc_default = 0xFF
>> +};
>> +
>> +struct e1000_fc_info {
>> +    u32 high_water;     /* Flow control high-water mark */
>> +    u32 low_water;      /* Flow control low-water mark */
>> +    u16 pause_time;     /* Flow control pause timer */
>> +    bool send_xon;      /* Flow control send XON */
>> +    bool strict_ieee;   /* Strict IEEE mode */
>> +    enum e1000_fc_mode current_mode; /* Type of flow control */
>> +    enum e1000_fc_mode requested_mode;
>> +};
>> +
>> +struct e1000_dev_spec_base {
>> +    bool global_device_reset;
>> +    bool eee_disable;
>> +    bool clear_semaphore_once;
>> +    bool module_plugged;
>> +    u8 media_port;
>> +};
>> +
>>   struct e1000_hw {
>>       void *back;
>> @@ -108,9 +183,15 @@ struct e1000_hw {
>>       unsigned long io_base;
>>       struct e1000_mac_info  mac;
>> +    struct e1000_fc_info   fc;
>> +    struct e1000_nvm_info  nvm;
>>       struct e1000_bus_info bus;
>> +    union {
>> +        struct e1000_dev_spec_base    _base;
>> +    } dev_spec;
>> +
>>       u16 device_id;
>>       u16 subsystem_vendor_id;
>>       u16 subsystem_device_id;
>> @@ -203,6 +284,10 @@ struct e1000_hw_stats {
>>       u64 b2ogprc;
>>   };
>> +struct net_device *igc_get_hw_dev(struct e1000_hw *hw);
>> +#define hw_dbg(format, arg...) \
>> +    netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
>> +
>>   /* These functions must be implemented by drivers */
>>   s32  igc_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
>>   s32  igc_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_i225.c 
>> b/drivers/net/ethernet/intel/igc/e1000_i225.c
>> new file mode 100644
>> index 000000000000..11d797c77619
>> --- /dev/null
>> +++ b/drivers/net/ethernet/intel/igc/e1000_i225.c
>> @@ -0,0 +1,141 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c)  2018 Intel Corporation */
>> +
>> +#include <linux/delay.h>
>> +
>> +#include "e1000_hw.h"
>> +
>> +/**
>> + *  igc_get_hw_semaphore_i225 - Acquire hardware semaphore
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Acquire the HW semaphore to access the PHY or NVM
>> + */
>> +static s32 igc_get_hw_semaphore_i225(struct e1000_hw *hw)
>> +{
>> +    u32 swsm;
>> +    s32 timeout = hw->nvm.word_size + 1;
>> +    s32 i = 0;
> 
> reverse xmas tree
> 
fix will be applied in v4.
>> +
>> +    /* Get the SW semaphore */
>> +    while (i < timeout) {
>> +        swsm = rd32(E1000_SWSM);
>> +        if (!(swsm & E1000_SWSM_SMBI))
>> +            break;
>> +
>> +        usleep_range(500, 600);
>> +        i++;
>> +    }
>> +
>> +    if (i == timeout) {
>> +        /* In rare circumstances, the SW semaphore may already be held
>> +         * unintentionally. Clear the semaphore once before giving up.
>> +         */
>> +        if (hw->dev_spec._base.clear_semaphore_once) {
>> +            hw->dev_spec._base.clear_semaphore_once = false;
>> +            igc_put_hw_semaphore(hw);
>> +            for (i = 0; i < timeout; i++) {
>> +                swsm = rd32(E1000_SWSM);
>> +                if (!(swsm & E1000_SWSM_SMBI))
>> +                    break;
>> +
>> +                usleep_range(500, 600);
>> +            }
>> +        }
>> +
>> +        /* If we do not have the semaphore here, we have to give up. */
>> +        if (i == timeout) {
>> +            hw_dbg("Driver can't access device - SMBI bit is set.\n");
>> +            return -E1000_ERR_NVM;
>> +        }
>> +    }
>> +
>> +    /* Get the FW semaphore. */
>> +    for (i = 0; i < timeout; i++) {
>> +        swsm = rd32(E1000_SWSM);
>> +        wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
>> +
>> +        /* Semaphore acquired if bit latched */
>> +        if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
>> +            break;
>> +
>> +        usleep_range(500, 600);
>> +    }
>> +
>> +    if (i == timeout) {
>> +        /* Release semaphores */
>> +        igc_put_hw_semaphore(hw);
>> +        hw_dbg("Driver can't access the NVM\n");
>> +        return -E1000_ERR_NVM;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + *  igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
>> + *  @hw: pointer to the HW structure
>> + *  @mask: specifies which semaphore to acquire
>> + *
>> + *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
>> + *  will also specify which port we're acquiring the lock for.
>> + **/
>> +s32 igc_acquire_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
>> +{
>> +    u32 swfw_sync;
>> +    u32 swmask = mask;
>> +    u32 fwmask = mask << 16;
>> +    s32 ret_val = 0;
>> +    s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
>> +
>> +    while (i < timeout) {
>> +        if (igc_get_hw_semaphore_i225(hw)) {
>> +            ret_val = -E1000_ERR_SWFW_SYNC;
>> +            goto out;
>> +        }
>> +
>> +        swfw_sync = rd32(E1000_SW_FW_SYNC);
>> +        if (!(swfw_sync & (fwmask | swmask)))
>> +            break;
>> +
>> +        /* Firmware currently using resource (fwmask) */
>> +        igc_put_hw_semaphore(hw);
>> +        mdelay(5);
>> +        i++;
>> +    }
>> +
>> +    if (i == timeout) {
>> +        hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
>> +        ret_val = -E1000_ERR_SWFW_SYNC;
>> +        goto out;
>> +    }
>> +
>> +    swfw_sync |= swmask;
>> +    wr32(E1000_SW_FW_SYNC, swfw_sync);
>> +
>> +    igc_put_hw_semaphore(hw);
>> +out:
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_release_swfw_sync_i225 - Release SW/FW semaphore
>> + *  @hw: pointer to the HW structure
>> + *  @mask: specifies which semaphore to acquire
>> + *
>> + *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
>> + *  will also specify which port we're releasing the lock for.
>> + **/
>> +void igc_release_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
>> +{
>> +    u32 swfw_sync;
>> +
>> +    while (igc_get_hw_semaphore_i225(hw))
>> +        ; /* Empty */
> 
> This loop needs a bounding condition
> 
I prefer keep and be alight with another drivers. Any benefit if we will 
change?
>> +
>> +    swfw_sync = rd32(E1000_SW_FW_SYNC);
>> +    swfw_sync &= ~mask;
>> +    wr32(E1000_SW_FW_SYNC, swfw_sync);
>> +
>> +    igc_put_hw_semaphore(hw);
>> +}
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.c 
>> b/drivers/net/ethernet/intel/igc/e1000_mac.c
>> index c38435bb8a8c..27e478a9854c 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_mac.c
>> +++ b/drivers/net/ethernet/intel/igc/e1000_mac.c
>> @@ -2,8 +2,15 @@
>>   /* Copyright (c)  2018 Intel Corporation */
>>   #include <linux/pci.h>
>> +#include <linux/delay.h>
>> +
>> +#include "e1000_mac.h"
>>   #include "e1000_hw.h"
>> +/* forward declaration */
>> +static s32 igc_set_default_fc(struct e1000_hw *hw);
>> +static s32 igc_set_fc_watermarks(struct e1000_hw *hw);
>> +
>>   /**
>>    *  igc_get_bus_info_pcie - Get PCIe bus information
>>    *  @hw: pointer to the HW structure
>> @@ -49,3 +56,316 @@ s32 igc_get_bus_info_pcie(struct e1000_hw *hw)
>>       return 0;
>>   }
>> +
>> +/**
>> + *  igc_disable_pcie_master - Disables PCI-express master access
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Returns 0 (0) if successful, else returns -10
>> + *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has 
>> not caused
>> + *  the master requests to be disabled.
>> + *
>> + *  Disables PCI-Express master access and verifies there are no pending
>> + *  requests.
>> + **/
>> +s32 igc_disable_pcie_master(struct e1000_hw *hw)
>> +{
>> +    u32 ctrl;
>> +    s32 timeout = MASTER_DISABLE_TIMEOUT;
>> +    s32 ret_val = 0;
>> +
>> +    if (hw->bus.type != e1000_bus_type_pci_express)
>> +        goto out;
>> +
>> +    ctrl = rd32(E1000_CTRL);
>> +    ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
>> +    wr32(E1000_CTRL, ctrl);
>> +
>> +    while (timeout) {
>> +        if (!(rd32(E1000_STATUS) &
>> +            E1000_STATUS_GIO_MASTER_ENABLE))
>> +            break;
>> +        usleep_range(2000, 3000);
>> +        timeout--;
>> +    }
>> +
>> +    if (!timeout) {
>> +        hw_dbg("Master requests are pending.\n");
>> +        ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
>> +        goto out;
>> +    }
>> +
>> +out:
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_init_rx_addrs - Initialize receive address's
> 
> s/address's/addresses/
> 
fix will be applied in v4.
>> + *  @hw: pointer to the HW structure
>> + *  @rar_count: receive address registers
>> + *
>> + *  Setups the receive address registers by setting the base receive 
>> address
> 
> s/Setups/Setup/
> 
fix will be applied in v4.
>> + *  register to the devices MAC address and clearing all the other 
>> receive
>> + *  address registers to 0.
>> + **/
>> +void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
>> +{
>> +    u32 i;
>> +    u8 mac_addr[ETH_ALEN] = {0};
>> +
>> +    /* Setup the receive address */
>> +    hw_dbg("Programming MAC Address into RAR[0]\n");
>> +
>> +    hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
>> +
>> +    /* Zero out the other (rar_entry_count - 1) receive addresses */
>> +    hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
>> +    for (i = 1; i < rar_count; i++)
>> +        hw->mac.ops.rar_set(hw, mac_addr, i);
>> +}
>> +
>> +/**
>> + *  igc_setup_link - Setup flow control and link settings
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Determines which flow control settings to use, then configures flow
>> + *  control.  Calls the appropriate media-specific link configuration
>> + *  function.  Assuming the adapter has a valid link partner, a valid 
>> link
>> + *  should be established.  Assumes the hardware has previously been 
>> reset
>> + *  and the transmitter and receiver are not enabled.
>> + **/
>> +s32 igc_setup_link(struct e1000_hw *hw)
>> +{
>> +    s32 ret_val = 0;
>> +
>> +    /* In the case of the phy reset being blocked, we already have a 
>> link.
>> +     * We do not need to set it up again.
>> +     */
>> +
>> +    /* If requested flow control is set to default, set flow control
>> +     * based on the EEPROM flow control settings.
>> +     */
>> +    if (hw->fc.requested_mode == e1000_fc_default) {
>> +        ret_val = igc_set_default_fc(hw);
>> +        if (ret_val)
>> +            goto out;
>> +    }
>> +
>> +    /* We want to save off the original Flow Control configuration just
>> +     * in case we get disconnected and then reconnected into a different
>> +     * hub or switch with different Flow Control capabilities.
>> +     */
>> +    hw->fc.current_mode = hw->fc.requested_mode;
>> +
>> +    hw_dbg("After fix-ups FlowControl is now = %x\n", 
>> hw->fc.current_mode);
>> +
>> +    /* Call the necessary media_type subroutine to configure the 
>> link. */
>> +    ret_val = hw->mac.ops.setup_physical_interface(hw);
>> +    if (ret_val)
>> +        goto out;
>> +
>> +    /* Initialize the flow control address, type, and PAUSE timer
>> +     * registers to their default values.  This is done even if flow
>> +     * control is disabled, because it does not hurt anything to
>> +     * initialize these registers.
>> +     */
>> +    hw_dbg("Initializing the Flow Control address, type and timer 
>> regs\n");
>> +    wr32(E1000_FCT, FLOW_CONTROL_TYPE);
>> +    wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
>> +    wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
>> +
>> +    wr32(E1000_FCTTV, hw->fc.pause_time);
>> +
>> +    ret_val = igc_set_fc_watermarks(hw);
>> +
>> +out:
>> +
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_set_default_fc - Set flow control default values
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Read the EEPROM for the default values for flow control and store 
>> the
>> + *  values.
>> + **/
>> +static s32 igc_set_default_fc(struct e1000_hw *hw)
>> +{
>> +    return 0;
>> +}
>> +
>> +/**
>> + *  igc_set_fc_watermarks - Set flow control high/low watermarks
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Sets the flow control high/low threshold (watermark) registers.  If
>> + *  flow control XON frame transmission is enabled, then set XON frame
>> + *  tansmission as well.
> 
> s/tansmission/transmission/
> 
fix will be applied in v4.
>> + **/
>> +static s32 igc_set_fc_watermarks(struct e1000_hw *hw)
>> +{
>> +    s32 ret_val = 0;
>> +    u32 fcrtl = 0, fcrth = 0;
>> +
>> +    /* Set the flow control receive threshold registers.  Normally,
>> +     * these registers will be set to a default threshold that may be
>> +     * adjusted later by the driver's runtime code.  However, if the
>> +     * ability to transmit pause frames is not enabled, then these
>> +     * registers will be set to 0.
>> +     */
>> +    if (hw->fc.current_mode & e1000_fc_tx_pause) {
>> +        /* We need to set up the Receive Threshold high and low water
>> +         * marks as well as (optionally) enabling the transmission of
>> +         * XON frames.
>> +         */
>> +        fcrtl = hw->fc.low_water;
>> +        if (hw->fc.send_xon)
>> +            fcrtl |= E1000_FCRTL_XONE;
>> +
>> +        fcrth = hw->fc.high_water;
>> +    }
>> +    wr32(E1000_FCRTL, fcrtl);
>> +    wr32(E1000_FCRTH, fcrth);
>> +
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_clear_hw_cntrs_base - Clear base hardware counters
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Clears the base hardware counters by reading the counter registers.
>> + **/
>> +void igc_clear_hw_cntrs_base(struct e1000_hw *hw)
>> +{
>> +    rd32(E1000_CRCERRS);
>> +    rd32(E1000_SYMERRS);
>> +    rd32(E1000_MPC);
>> +    rd32(E1000_SCC);
>> +    rd32(E1000_ECOL);
>> +    rd32(E1000_MCC);
>> +    rd32(E1000_LATECOL);
>> +    rd32(E1000_COLC);
>> +    rd32(E1000_DC);
>> +    rd32(E1000_SEC);
>> +    rd32(E1000_RLEC);
>> +    rd32(E1000_XONRXC);
>> +    rd32(E1000_XONTXC);
>> +    rd32(E1000_XOFFRXC);
>> +    rd32(E1000_XOFFTXC);
>> +    rd32(E1000_FCRUC);
>> +    rd32(E1000_GPRC);
>> +    rd32(E1000_BPRC);
>> +    rd32(E1000_MPRC);
>> +    rd32(E1000_GPTC);
>> +    rd32(E1000_GORCL);
>> +    rd32(E1000_GORCH);
>> +    rd32(E1000_GOTCL);
>> +    rd32(E1000_GOTCH);
>> +    rd32(E1000_RNBC);
>> +    rd32(E1000_RUC);
>> +    rd32(E1000_RFC);
>> +    rd32(E1000_ROC);
>> +    rd32(E1000_RJC);
>> +    rd32(E1000_TORL);
>> +    rd32(E1000_TORH);
>> +    rd32(E1000_TOTL);
>> +    rd32(E1000_TOTH);
>> +    rd32(E1000_TPR);
>> +    rd32(E1000_TPT);
>> +    rd32(E1000_MPTC);
>> +    rd32(E1000_BPTC);
>> +
>> +    rd32(E1000_PRC64);
>> +    rd32(E1000_PRC127);
>> +    rd32(E1000_PRC255);
>> +    rd32(E1000_PRC511);
>> +    rd32(E1000_PRC1023);
>> +    rd32(E1000_PRC1522);
>> +    rd32(E1000_PTC64);
>> +    rd32(E1000_PTC127);
>> +    rd32(E1000_PTC255);
>> +    rd32(E1000_PTC511);
>> +    rd32(E1000_PTC1023);
>> +    rd32(E1000_PTC1522);
>> +
>> +    rd32(E1000_ALGNERRC);
>> +    rd32(E1000_RXERRC);
>> +    rd32(E1000_TNCRS);
>> +    rd32(E1000_CEXTERR);
>> +    rd32(E1000_TSCTC);
>> +    rd32(E1000_TSCTFC);
>> +
>> +    rd32(E1000_MGTPRC);
>> +    rd32(E1000_MGTPDC);
>> +    rd32(E1000_MGTPTC);
>> +
>> +    rd32(E1000_IAC);
>> +    rd32(E1000_ICRXOC);
>> +
>> +    rd32(E1000_ICRXPTC);
>> +    rd32(E1000_ICRXATC);
>> +    rd32(E1000_ICTXPTC);
>> +    rd32(E1000_ICTXATC);
>> +    rd32(E1000_ICTXQEC);
>> +    rd32(E1000_ICTXQMTC);
>> +    rd32(E1000_ICRXDMTC);
>> +
>> +    rd32(E1000_CBTMPC);
>> +    rd32(E1000_HTDPMC);
>> +    rd32(E1000_CBRMPC);
>> +    rd32(E1000_RPTHC);
>> +    rd32(E1000_HGPTC);
>> +    rd32(E1000_HTCBDPC);
>> +    rd32(E1000_HGORCL);
>> +    rd32(E1000_HGORCH);
>> +    rd32(E1000_HGOTCL);
>> +    rd32(E1000_HGOTCH);
>> +    rd32(E1000_LENERRS);
>> +}
>> +
>> +/**
>> + *  igc_get_auto_rd_done - Check for auto read completion
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Check EEPROM for Auto Read done bit.
>> + **/
>> +s32 igc_get_auto_rd_done(struct e1000_hw *hw)
>> +{
>> +    s32 i = 0;
>> +    s32 ret_val = 0;
>> +
>> +    while (i < AUTO_READ_DONE_TIMEOUT) {
>> +        if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD)
>> +            break;
>> +        usleep_range(1000, 2000);
>> +        i++;
>> +    }
>> +
>> +    if (i == AUTO_READ_DONE_TIMEOUT) {
>> +        hw_dbg("Auto read by HW from NVM has not completed.\n");
>> +        ret_val = -E1000_ERR_RESET;
>> +        goto out;
>> +    }
>> +
>> +out:
>> +    return ret_val;
>> +}
>> +
>> +/**
>> + *  igc_put_hw_semaphore - Release hardware semaphore
>> + *  @hw: pointer to the HW structure
>> + *
>> + *  Release hardware semaphore used to access the PHY or NVM
>> + **/
>> +void igc_put_hw_semaphore(struct e1000_hw *hw)
>> +{
>> +    u32 swsm;
>> +
>> +    swsm = rd32(E1000_SWSM);
>> +
>> +    swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
>> +
>> +    wr32(E1000_SWSM, swsm);
>> +}
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.h 
>> b/drivers/net/ethernet/intel/igc/e1000_mac.h
>> index afb0f7b28222..2f8dbf17800a 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_mac.h
>> +++ b/drivers/net/ethernet/intel/igc/e1000_mac.h
>> @@ -4,10 +4,21 @@
>>   #ifndef _E1000_MAC_H_
>>   #define _E1000_MAC_H_
>> +#include "e1000_hw.h"
>> +#include "e1000_defines.h"
>> +
>>   #ifndef E1000_REMOVED
>>   #define E1000_REMOVED(a) (0)
>>   #endif /* E1000_REMOVED */
>> -s32 igc_get_bus_info_pcie(struct e1000_hw *hw);
>> +/* forward declaration */
>> +s32  igc_disable_pcie_master(struct e1000_hw *hw);
>> +void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
>> +s32  igc_setup_link(struct e1000_hw *hw);
>> +void igc_clear_hw_cntrs_base(struct e1000_hw *hw);
>> +s32 igc_get_auto_rd_done(struct e1000_hw *hw);
>> +void igc_put_hw_semaphore(struct e1000_hw *hw);
>> +
>> +s32  igc_get_bus_info_pcie(struct e1000_hw *hw);
>>   #endif
>> diff --git a/drivers/net/ethernet/intel/igc/e1000_regs.h 
>> b/drivers/net/ethernet/intel/igc/e1000_regs.h
>> index dcc4d89c9933..66d5c757dae8 100644
>> --- a/drivers/net/ethernet/intel/igc/e1000_regs.h
>> +++ b/drivers/net/ethernet/intel/igc/e1000_regs.h
>> @@ -7,6 +7,7 @@
>>   /* General Register Descriptions */
>>   #define E1000_CTRL        0x00000  /* Device Control - RW */
>>   #define E1000_STATUS        0x00008  /* Device Status - RO */
>> +#define E1000_EECD        0x00010  /* EEPROM/Flash Control - RW */
>>   #define E1000_CTRL_EXT        0x00018  /* Extended Device Control - 
>> RW */
>>   #define E1000_MDIC        0x00020  /* MDI Control - RW */
>>   #define E1000_MDICNFG        0x00E04  /* MDC/MDIO Configuration - RW */
>> @@ -75,6 +76,30 @@
>>   #define E1000_IVAR_MISC        0x01740   /* IVAR for "other" causes 
>> - RW */
>>   #define E1000_GPIE        0x01514  /* General Purpose Intr Enable - 
>> RW */
>> +/* Interrupt Cause Rx Packet Timer Expire Count */
>> +#define E1000_ICRXPTC        0x04104
>> +/* Interrupt Cause Rx Absolute Timer Expire Count */
>> +#define E1000_ICRXATC        0x04108
>> +/* Interrupt Cause Tx Packet Timer Expire Count */
>> +#define E1000_ICTXPTC        0x0410C
>> +/* Interrupt Cause Tx Absolute Timer Expire Count */
>> +#define E1000_ICTXATC        0x04110
>> +/* Interrupt Cause Tx Queue Empty Count */
>> +#define E1000_ICTXQEC        0x04118
>> +/* Interrupt Cause Tx Queue Minimum Threshold Count */
>> +#define E1000_ICTXQMTC        0x0411C
>> +/* Interrupt Cause Rx Descriptor Minimum Threshold Count */
>> +#define E1000_ICRXDMTC        0x04120
>> +/* Interrupt Cause Receiver Overrun Count */
>> +#define E1000_ICRXOC        0x04124
> 
> These comments intersperced make the #defines hard to read - putting 
> them off to the side would help a lot.
> 
Good. fix will be applied in v4.
>> +
>> +#define E1000_CBTMPC        0x0402C  /* Circuit Breaker TX Packet 
>> Count */
>> +#define E1000_HTDPMC        0x0403C  /* Host Transmit Discarded 
>> Packets */
>> +#define E1000_CBRMPC        0x040FC  /* Circuit Breaker RX Packet 
>> Count */
>> +#define E1000_RPTHC        0x04104  /* Rx Packets To Host */
>> +#define E1000_HGPTC        0x04118  /* Host Good Packets TX Count */
>> +#define E1000_HTCBDPC        0x04124  /* Host TX Circ.Breaker Drop 
>> Count */
>> +
>>   /* MSI-X Table Register Descriptions */
>>   #define E1000_PBACL        0x05B68  /* MSIx PBA Clear - R/W 1 to 
>> clear */
>> @@ -92,6 +117,8 @@
>>   #define E1000_RXCSUM        0x05000  /* Rx Checksum Control - RW */
>>   #define E1000_RLPML        0x05004  /* Rx Long Packet Max Length */
>>   #define E1000_RFCTL        0x05008  /* Receive Filter Control*/
>> +#define E1000_MTA        0x05200  /* Multicast Table Array - RW Array */
>> +#define E1000_UTA        0x0A000 /* Unicast Table Array - RW */
>>   #define E1000_RAL(_n)        (0x05400 + ((_n) * 0x08))
>>   #define E1000_RAH(_n)        (0x05404 + ((_n) * 0x08))
>>   #define E1000_VLAPQF        0x055B0  /* VLAN Priority Queuue - RW */
>> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c 
>> b/drivers/net/ethernet/intel/igc/igc_main.c
>> index 67826041eb3c..9a99c7d68796 100644
>> --- a/drivers/net/ethernet/intel/igc/igc_main.c
>> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
>> @@ -86,6 +86,14 @@ enum latency_range {
>>   void igc_reset(struct igc_adapter *adapter)
>>   {
>> +    struct pci_dev *pdev = adapter->pdev;
>> +    struct e1000_hw *hw = &adapter->hw;
>> +
>> +    hw->mac.ops.reset_hw(hw);
>> +
>> +    if (hw->mac.ops.init_hw(hw))
>> +        dev_err(&pdev->dev, "Hardware Error\n");
> 
> Is there something more specific that can be said here, including 
> something about it being the init that failed?
> 
No. Let's keep it as default. I consider extend this message when I will 
more logic to the driver.
>> +
>>       if (!netif_running(adapter->netdev))
>>           igc_power_down_link(adapter);
>>   }
>> @@ -3621,6 +3629,19 @@ static void igc_nfc_filter_exit(struct 
>> igc_adapter *adapter)
>>   }
>>   /**
>> + *  igc_get_hw_dev - return device
>> + *  @hw: pointer to hardware structure
>> + *
>> + *  used by hardware layer to print debugging information
>> + **/
>> +struct net_device *igc_get_hw_dev(struct e1000_hw *hw)
>> +{
>> +    struct igc_adapter *adapter = hw->back;
>> +
>> +    return adapter->netdev;
> 
> I think this can either become a #define or an inline in a .h file
> 
Declared in .h Move it will cause to mess. What is benefit move it?
>> +}
>> +
>> +/**
>>    *  igc_init_module - Driver Registration Routine
>>    *
>>    *  igc_init_module is the first routine called when the driver is
>>
Thanks for your comments.
Shannon Nelson July 9, 2018, 4:07 p.m. UTC | #4
On 7/4/2018 6:39 AM, Neftin, Sasha wrote:
> On 6/29/2018 01:25, Shannon Nelson wrote:
>> On 6/24/2018 1:45 AM, Sasha Neftin wrote:

[...]

>>> +
>>> +/**
>>> + *  igc_release_swfw_sync_i225 - Release SW/FW semaphore
>>> + *  @hw: pointer to the HW structure
>>> + *  @mask: specifies which semaphore to acquire
>>> + *
>>> + *  Release the SW/FW semaphore used to access the PHY or NVM.  The 
>>> mask
>>> + *  will also specify which port we're releasing the lock for.
>>> + **/
>>> +void igc_release_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
>>> +{
>>> +    u32 swfw_sync;
>>> +
>>> +    while (igc_get_hw_semaphore_i225(hw))
>>> +        ; /* Empty */
>>
>> This loop needs a bounding condition
>>
> I prefer keep and be alight with another drivers. Any benefit if we will 
> change?

When the firmware is "broken" the semaphore get will never succeed and 
the thread will hang.  We shouldn't be creating opportunities for a 
driver to hang a kernel thread.


[...]

>>>   /**
>>> + *  igc_get_hw_dev - return device
>>> + *  @hw: pointer to hardware structure
>>> + *
>>> + *  used by hardware layer to print debugging information
>>> + **/
>>> +struct net_device *igc_get_hw_dev(struct e1000_hw *hw)
>>> +{
>>> +    struct igc_adapter *adapter = hw->back;
>>> +
>>> +    return adapter->netdev;
>>
>> I think this can either become a #define or an inline in a .h file
>>
> Declared in .h Move it will cause to mess. What is benefit move it?

This is a very simple accessor function to get at the netdev, but 
because it is in a separate code file from those that use it, the 
compiler can't optimize it well - there will likely be an expensive 
function call each time it is used.  If it was set up as a "static 
inline" function in a .h file, the compiler can optimize out the 
function call and save a lot of cycles.

sln
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile
index 6a757ac8492d..cb260bedfa37 100644
--- a/drivers/net/ethernet/intel/igc/Makefile
+++ b/drivers/net/ethernet/intel/igc/Makefile
@@ -7,5 +7,4 @@ 
 
 obj-$(CONFIG_IGC) += igc.o
 
-igc-objs := igc_main.o e1000_mac.o \
-e1000_base.o
+igc-objs := igc_main.o e1000_mac.o e1000_i225.o e1000_base.o
diff --git a/drivers/net/ethernet/intel/igc/e1000_base.c b/drivers/net/ethernet/intel/igc/e1000_base.c
index 265ec98000e7..395d7ce70bb4 100644
--- a/drivers/net/ethernet/intel/igc/e1000_base.c
+++ b/drivers/net/ethernet/intel/igc/e1000_base.c
@@ -5,6 +5,92 @@ 
 
 #include "e1000_hw.h"
 #include "e1000_i225.h"
+#include "e1000_mac.h"
+#include "e1000_base.h"
+#include "igc.h"
+
+/* forward declaration */
+static s32 igc_get_invariants_base(struct e1000_hw *);
+static s32 igc_init_hw_base(struct e1000_hw *);
+static s32 igc_reset_hw_base(struct e1000_hw *);
+static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw);
+
+/**
+ *  igc_init_mac_params_base - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igc_init_mac_params_base(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+
+	/* reset */
+	mac->ops.reset_hw = igc_reset_hw_base;
+
+	mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
+	mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
+
+	return 0;
+}
+
+static s32 igc_get_invariants_base(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u32 ctrl_ext = 0;
+	u32 link_mode = 0;
+
+	ctrl_ext = rd32(E1000_CTRL_EXT);
+	link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
+
+	/* mac initialization and operations */
+	ret_val = igc_init_mac_params_base(hw);
+	if (ret_val)
+		goto out;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igc_init_hw_base - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 igc_init_hw_base(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = 0;
+	u16 i, rar_count = mac->rar_entry_count;
+
+	/* Setup the receive address */
+	igc_init_rx_addrs(hw, rar_count);
+
+	/* Zero out the Multicast HASH table */
+	hw_dbg("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		array_wr32(E1000_MTA, i, 0);
+
+	/* Zero out the Unicast HASH table */
+	hw_dbg("Zeroing the UTA\n");
+	for (i = 0; i < mac->uta_reg_count; i++)
+		array_wr32(E1000_UTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = igc_setup_link(hw);
+
+	/* Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	igc_clear_hw_cntrs_base(hw);
+
+	return ret_val;
+}
 
 /**
  *  igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
@@ -81,3 +167,115 @@  void igc_rx_fifo_flush_base(struct e1000_hw *hw)
 	rd32(E1000_RNBC);
 	rd32(E1000_MPC);
 }
+
+static struct e1000_mac_operations e1000_mac_ops_base = {
+	.init_hw	= igc_init_hw_base,
+};
+
+const struct e1000_info e1000_base_info = {
+	.get_invariants = igc_get_invariants_base,
+	.mac_ops = &e1000_mac_ops_base,
+};
+
+/**
+ *  igc_reset_hw_base - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 igc_reset_hw_base(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+
+	/* Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = igc_disable_pcie_master(hw);
+	if (ret_val)
+		hw_dbg("PCI-E Master disable polling has failed.\n");
+
+	/* set the completion timeout for interface */
+	ret_val = igc_set_pcie_completion_timeout(hw);
+	if (ret_val)
+		hw_dbg("PCI-E Set completion timeout has failed.\n");
+
+	hw_dbg("Masking off all interrupts\n");
+	wr32(E1000_IMC, 0xffffffff);
+
+	wr32(E1000_RCTL, 0);
+	wr32(E1000_TCTL, E1000_TCTL_PSP);
+	wrfl();
+
+	usleep_range(10000, 20000);
+
+	ctrl = rd32(E1000_CTRL);
+
+	hw_dbg("Issuing a global reset to MAC\n");
+	wr32(E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	ret_val = igc_get_auto_rd_done(hw);
+	if (ret_val) {
+		/* When auto config read does not complete, do not
+		 * return with an error. This can happen in situations
+		 * where there is no eeprom and prevents getting link.
+		 */
+		hw_dbg("Auto Read Done did not complete\n");
+	}
+
+	/* Clear any pending interrupt events. */
+	wr32(E1000_IMC, 0xffffffff);
+	rd32(E1000_ICR);
+
+	return ret_val;
+}
+
+/**
+ *  igc_set_pcie_completion_timeout - set pci-e completion timeout
+ *  @hw: pointer to the HW structure
+ *
+ *  The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ *  however the hardware default for these parts is 500us to 1ms which is less
+ *  than the 10ms recommended by the pci-e spec.  To address this we need to
+ *  increase the value to either 10ms to 200ms for capability version 1 config,
+ *  or 16ms to 55ms for version 2.
+ **/
+static s32 igc_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+	u32 gcr = rd32(E1000_GCR);
+	s32 ret_val = 0;
+	u16 pcie_devctl2;
+
+	/* only take action if timeout value is defaulted to 0 */
+	if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+		goto out;
+
+	/* if capabilities version is type 1 we can write the
+	 * timeout of 10ms to 200ms through the GCR register
+	 */
+	if (!(gcr & E1000_GCR_CAP_VER2)) {
+		gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+		goto out;
+	}
+
+	/* for version 2 capabilities we need to write the config space
+	 * directly in order to set the completion timeout value for
+	 * 16ms to 55ms
+	 */
+	ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+					&pcie_devctl2);
+	if (ret_val)
+		goto out;
+
+	pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+	ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+					 &pcie_devctl2);
+out:
+	/* disable completion timeout resend */
+	gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+	wr32(E1000_GCR, gcr);
+	return ret_val;
+}
diff --git a/drivers/net/ethernet/intel/igc/e1000_base.h b/drivers/net/ethernet/intel/igc/e1000_base.h
index 5c766fb7514b..210f1b5f6012 100644
--- a/drivers/net/ethernet/intel/igc/e1000_base.h
+++ b/drivers/net/ethernet/intel/igc/e1000_base.h
@@ -33,6 +33,8 @@  union e1000_adv_tx_desc {
 #define E1000_ADVTXD_DCMD_TSE	0x80000000 /* TCP Seg enable */
 #define E1000_ADVTXD_PAYLEN_SHIFT	14 /* Adv desc PAYLEN shift */
 
+#define E1000_RAR_ENTRIES		16
+
 struct e1000_adv_data_desc {
 	__le64 buffer_addr;    /* Address of the descriptor's data buffer */
 	union {
diff --git a/drivers/net/ethernet/intel/igc/e1000_defines.h b/drivers/net/ethernet/intel/igc/e1000_defines.h
index f39d93d17ba6..5613806742b1 100644
--- a/drivers/net/ethernet/intel/igc/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igc/e1000_defines.h
@@ -30,6 +30,22 @@ 
 #define E1000_PCI_PMCSR			0x44
 #define E1000_PCI_PMCSR_D3		0x03
 
+/* Physical Func Reset Done Indication */
+#define E1000_CTRL_EXT_LINK_MODE_MASK	0x00C00000
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT		800
+/*Blocks new Master requests */
+#define E1000_CTRL_GIO_MASTER_DISABLE	0x00000004
+/* Status of Master requests. */
+#define E1000_STATUS_GIO_MASTER_ENABLE	0x00080000
+
+/* PCI Express Control */
+#define E1000_GCR_CMPL_TMOUT_MASK	0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms	0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND	0x00010000
+#define E1000_GCR_CAP_VER2		0x00040000
+
 /* Receive Address
  * Number of high/low register pairs in the RAR. The RAR (Receive Address
  * Registers) holds the directed and multicast addresses that we monitor.
@@ -48,10 +64,26 @@ 
 #define E1000_ERR_PARAM				4
 #define E1000_ERR_MAC_INIT			5
 #define E1000_ERR_RESET				9
+#define E1000_ERR_MASTER_REQUESTS_PENDING	10
+#define E1000_ERR_SWFW_SYNC			13
+
+/* Device Control */
+#define E1000_CTRL_RST		0x04000000  /* Global reset */
 
 /* PBA constants */
 #define E1000_PBA_34K			0x0022
 
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI		0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI	0x00000002 /* FW Semaphore bit */
+
+/* NVM Control */
+#define E1000_EECD_PRES		0x00000100 /* NVM Present */
+
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT		10
+#define E1000_EECD_AUTO_RD	0x00000200  /* NVM Auto Read done */
+
 /* Device Status */
 #define E1000_STATUS_FD		0x00000001      /* Full duplex.0=half,1=full */
 #define E1000_STATUS_LU		0x00000002      /* Link up.0=no,1=link */
@@ -135,6 +167,13 @@ 
 #define E1000_CT_SHIFT			4
 #define E1000_COLLISION_THRESHOLD	15
 
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW	0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH	0x00000100
+#define FLOW_CONTROL_TYPE		0x8808
+/* Enable XON frame transmission */
+#define E1000_FCRTL_XONE		0x80000000
+
 /* Management Control */
 #define E1000_MANC_RCV_TCO_EN	0x00020000 /* Receive TCO Packets Enabled */
 
diff --git a/drivers/net/ethernet/intel/igc/e1000_hw.h b/drivers/net/ethernet/intel/igc/e1000_hw.h
index 67fa4f696b98..debeadd61b45 100644
--- a/drivers/net/ethernet/intel/igc/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igc/e1000_hw.h
@@ -6,6 +6,8 @@ 
 
 #include <linux/types.h>
 #include <linux/if_ether.h>
+#include <linux/netdevice.h>
+
 #include "e1000_regs.h"
 #include "e1000_defines.h"
 #include "e1000_mac.h"
@@ -20,6 +22,16 @@  struct e1000_hw;
 
 /* Function pointers for the MAC. */
 struct e1000_mac_operations {
+	s32 (*check_for_link)(struct e1000_hw *hw);
+	s32 (*reset_hw)(struct e1000_hw *hw);
+	s32 (*init_hw)(struct e1000_hw *hw);
+	s32 (*setup_physical_interface)(struct e1000_hw *hw);
+	void (*rar_set)(struct e1000_hw *hw, u8 *address, u32 index);
+	s32 (*read_mac_addr)(struct e1000_hw *hw);
+	s32 (*get_speed_and_duplex)(struct e1000_hw *hw, u16 *speed,
+				    u16 *duplex);
+	s32 (*acquire_swfw_sync)(struct e1000_hw *hw, u16 mask);
+	void (*release_swfw_sync)(struct e1000_hw *hw, u16 mask);
 };
 
 enum e1000_mac_type {
@@ -34,6 +46,12 @@  enum e1000_phy_type {
 	e1000_phy_i225,
 };
 
+enum e1000_nvm_type {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_flash_hw,
+	e1000_nvm_invm,
+};
+
 enum e1000_bus_type {
 	e1000_bus_type_unknown = 0,
 	e1000_bus_type_pci_express,
@@ -56,6 +74,13 @@  enum e1000_bus_width {
 	e1000_bus_width_reserved
 };
 
+struct e1000_info {
+	s32 (*get_invariants)(struct e1000_hw *hw);
+	struct e1000_mac_operations *mac_ops;
+	const struct e1000_phy_operations *phy_ops;
+	struct e1000_nvm_operations *nvm_ops;
+};
+
 struct e1000_mac_info {
 	struct e1000_mac_operations ops;
 
@@ -91,6 +116,30 @@  struct e1000_mac_info {
 	bool get_link_status;
 };
 
+struct e1000_nvm_operations {
+	s32 (*acquire)(struct e1000_hw *hw);
+	s32 (*read)(struct e1000_hw *hw, u16 offset, u16 i, u16 *data);
+	void (*release)(struct e1000_hw *hw);
+	s32 (*write)(struct e1000_hw *hw, u16 offset, u16 i, u16 *data);
+	s32 (*update)(struct e1000_hw *hw);
+	s32 (*validate)(struct e1000_hw *hw);
+	s32 (*valid_led_default)(struct e1000_hw *hw, u16 *data);
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+	enum e1000_nvm_type type;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
 struct e1000_bus_info {
 	enum e1000_bus_type type;
 	enum e1000_bus_speed speed;
@@ -100,6 +149,32 @@  struct e1000_bus_info {
 	u16 pci_cmd_word;
 };
 
+enum e1000_fc_mode {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+};
+
+struct e1000_fc_info {
+	u32 high_water;     /* Flow control high-water mark */
+	u32 low_water;      /* Flow control low-water mark */
+	u16 pause_time;     /* Flow control pause timer */
+	bool send_xon;      /* Flow control send XON */
+	bool strict_ieee;   /* Strict IEEE mode */
+	enum e1000_fc_mode current_mode; /* Type of flow control */
+	enum e1000_fc_mode requested_mode;
+};
+
+struct e1000_dev_spec_base {
+	bool global_device_reset;
+	bool eee_disable;
+	bool clear_semaphore_once;
+	bool module_plugged;
+	u8 media_port;
+};
+
 struct e1000_hw {
 	void *back;
 
@@ -108,9 +183,15 @@  struct e1000_hw {
 	unsigned long io_base;
 
 	struct e1000_mac_info  mac;
+	struct e1000_fc_info   fc;
+	struct e1000_nvm_info  nvm;
 
 	struct e1000_bus_info bus;
 
+	union {
+		struct e1000_dev_spec_base	_base;
+	} dev_spec;
+
 	u16 device_id;
 	u16 subsystem_vendor_id;
 	u16 subsystem_device_id;
@@ -203,6 +284,10 @@  struct e1000_hw_stats {
 	u64 b2ogprc;
 };
 
+struct net_device *igc_get_hw_dev(struct e1000_hw *hw);
+#define hw_dbg(format, arg...) \
+	netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
+
 /* These functions must be implemented by drivers */
 s32  igc_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
 s32  igc_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
diff --git a/drivers/net/ethernet/intel/igc/e1000_i225.c b/drivers/net/ethernet/intel/igc/e1000_i225.c
new file mode 100644
index 000000000000..11d797c77619
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/e1000_i225.c
@@ -0,0 +1,141 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c)  2018 Intel Corporation */
+
+#include <linux/delay.h>
+
+#include "e1000_hw.h"
+
+/**
+ *  igc_get_hw_semaphore_i225 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ */
+static s32 igc_get_hw_semaphore_i225(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = rd32(E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		usleep_range(500, 600);
+		i++;
+	}
+
+	if (i == timeout) {
+		/* In rare circumstances, the SW semaphore may already be held
+		 * unintentionally. Clear the semaphore once before giving up.
+		 */
+		if (hw->dev_spec._base.clear_semaphore_once) {
+			hw->dev_spec._base.clear_semaphore_once = false;
+			igc_put_hw_semaphore(hw);
+			for (i = 0; i < timeout; i++) {
+				swsm = rd32(E1000_SWSM);
+				if (!(swsm & E1000_SWSM_SMBI))
+					break;
+
+				usleep_range(500, 600);
+			}
+		}
+
+		/* If we do not have the semaphore here, we have to give up. */
+		if (i == timeout) {
+			hw_dbg("Driver can't access device - SMBI bit is set.\n");
+			return -E1000_ERR_NVM;
+		}
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = rd32(E1000_SWSM);
+		wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		usleep_range(500, 600);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		igc_put_hw_semaphore(hw);
+		hw_dbg("Driver can't access the NVM\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return 0;
+}
+
+/**
+ *  igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+s32 igc_acquire_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 ret_val = 0;
+	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+	while (i < timeout) {
+		if (igc_get_hw_semaphore_i225(hw)) {
+			ret_val = -E1000_ERR_SWFW_SYNC;
+			goto out;
+		}
+
+		swfw_sync = rd32(E1000_SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		/* Firmware currently using resource (fwmask) */
+		igc_put_hw_semaphore(hw);
+		mdelay(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -E1000_ERR_SWFW_SYNC;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+	igc_put_hw_semaphore(hw);
+out:
+	return ret_val;
+}
+
+/**
+ *  igc_release_swfw_sync_i225 - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+void igc_release_swfw_sync_i225(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	while (igc_get_hw_semaphore_i225(hw))
+		; /* Empty */
+
+	swfw_sync = rd32(E1000_SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+	igc_put_hw_semaphore(hw);
+}
diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.c b/drivers/net/ethernet/intel/igc/e1000_mac.c
index c38435bb8a8c..27e478a9854c 100644
--- a/drivers/net/ethernet/intel/igc/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igc/e1000_mac.c
@@ -2,8 +2,15 @@ 
 /* Copyright (c)  2018 Intel Corporation */
 
 #include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "e1000_mac.h"
 #include "e1000_hw.h"
 
+/* forward declaration */
+static s32 igc_set_default_fc(struct e1000_hw *hw);
+static s32 igc_set_fc_watermarks(struct e1000_hw *hw);
+
 /**
  *  igc_get_bus_info_pcie - Get PCIe bus information
  *  @hw: pointer to the HW structure
@@ -49,3 +56,316 @@  s32 igc_get_bus_info_pcie(struct e1000_hw *hw)
 
 	return 0;
 }
+
+/**
+ *  igc_disable_pcie_master - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (0) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 igc_disable_pcie_master(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+	s32 ret_val = 0;
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	ctrl = rd32(E1000_CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	wr32(E1000_CTRL, ctrl);
+
+	while (timeout) {
+		if (!(rd32(E1000_STATUS) &
+		    E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		usleep_range(2000, 3000);
+		timeout--;
+	}
+
+	if (!timeout) {
+		hw_dbg("Master requests are pending.\n");
+		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igc_init_rx_addrs - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+	u8 mac_addr[ETH_ALEN] = {0};
+
+	/* Setup the receive address */
+	hw_dbg("Programming MAC Address into RAR[0]\n");
+
+	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
+	for (i = 1; i < rar_count; i++)
+		hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ *  igc_setup_link - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 igc_setup_link(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+
+	/* In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+
+	/* If requested flow control is set to default, set flow control
+	 * based on the EEPROM flow control settings.
+	 */
+	if (hw->fc.requested_mode == e1000_fc_default) {
+		ret_val = igc_set_default_fc(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/* We want to save off the original Flow Control configuration just
+	 * in case we get disconnected and then reconnected into a different
+	 * hub or switch with different Flow Control capabilities.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
+
+	hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/* Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	hw_dbg("Initializing the Flow Control address, type and timer regs\n");
+	wr32(E1000_FCT, FLOW_CONTROL_TYPE);
+	wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	wr32(E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = igc_set_fc_watermarks(hw);
+
+out:
+
+	return ret_val;
+}
+
+/**
+ *  igc_set_default_fc - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+static s32 igc_set_default_fc(struct e1000_hw *hw)
+{
+	return 0;
+}
+
+/**
+ *  igc_set_fc_watermarks - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  tansmission as well.
+ **/
+static s32 igc_set_fc_watermarks(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u32 fcrtl = 0, fcrth = 0;
+
+	/* Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (hw->fc.current_mode & e1000_fc_tx_pause) {
+		/* We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = hw->fc.low_water;
+		if (hw->fc.send_xon)
+			fcrtl |= E1000_FCRTL_XONE;
+
+		fcrth = hw->fc.high_water;
+	}
+	wr32(E1000_FCRTL, fcrtl);
+	wr32(E1000_FCRTH, fcrth);
+
+	return ret_val;
+}
+
+/**
+ *  igc_clear_hw_cntrs_base - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void igc_clear_hw_cntrs_base(struct e1000_hw *hw)
+{
+	rd32(E1000_CRCERRS);
+	rd32(E1000_SYMERRS);
+	rd32(E1000_MPC);
+	rd32(E1000_SCC);
+	rd32(E1000_ECOL);
+	rd32(E1000_MCC);
+	rd32(E1000_LATECOL);
+	rd32(E1000_COLC);
+	rd32(E1000_DC);
+	rd32(E1000_SEC);
+	rd32(E1000_RLEC);
+	rd32(E1000_XONRXC);
+	rd32(E1000_XONTXC);
+	rd32(E1000_XOFFRXC);
+	rd32(E1000_XOFFTXC);
+	rd32(E1000_FCRUC);
+	rd32(E1000_GPRC);
+	rd32(E1000_BPRC);
+	rd32(E1000_MPRC);
+	rd32(E1000_GPTC);
+	rd32(E1000_GORCL);
+	rd32(E1000_GORCH);
+	rd32(E1000_GOTCL);
+	rd32(E1000_GOTCH);
+	rd32(E1000_RNBC);
+	rd32(E1000_RUC);
+	rd32(E1000_RFC);
+	rd32(E1000_ROC);
+	rd32(E1000_RJC);
+	rd32(E1000_TORL);
+	rd32(E1000_TORH);
+	rd32(E1000_TOTL);
+	rd32(E1000_TOTH);
+	rd32(E1000_TPR);
+	rd32(E1000_TPT);
+	rd32(E1000_MPTC);
+	rd32(E1000_BPTC);
+
+	rd32(E1000_PRC64);
+	rd32(E1000_PRC127);
+	rd32(E1000_PRC255);
+	rd32(E1000_PRC511);
+	rd32(E1000_PRC1023);
+	rd32(E1000_PRC1522);
+	rd32(E1000_PTC64);
+	rd32(E1000_PTC127);
+	rd32(E1000_PTC255);
+	rd32(E1000_PTC511);
+	rd32(E1000_PTC1023);
+	rd32(E1000_PTC1522);
+
+	rd32(E1000_ALGNERRC);
+	rd32(E1000_RXERRC);
+	rd32(E1000_TNCRS);
+	rd32(E1000_CEXTERR);
+	rd32(E1000_TSCTC);
+	rd32(E1000_TSCTFC);
+
+	rd32(E1000_MGTPRC);
+	rd32(E1000_MGTPDC);
+	rd32(E1000_MGTPTC);
+
+	rd32(E1000_IAC);
+	rd32(E1000_ICRXOC);
+
+	rd32(E1000_ICRXPTC);
+	rd32(E1000_ICRXATC);
+	rd32(E1000_ICTXPTC);
+	rd32(E1000_ICTXATC);
+	rd32(E1000_ICTXQEC);
+	rd32(E1000_ICTXQMTC);
+	rd32(E1000_ICRXDMTC);
+
+	rd32(E1000_CBTMPC);
+	rd32(E1000_HTDPMC);
+	rd32(E1000_CBRMPC);
+	rd32(E1000_RPTHC);
+	rd32(E1000_HGPTC);
+	rd32(E1000_HTCBDPC);
+	rd32(E1000_HGORCL);
+	rd32(E1000_HGORCH);
+	rd32(E1000_HGOTCL);
+	rd32(E1000_HGOTCH);
+	rd32(E1000_LENERRS);
+}
+
+/**
+ *  igc_get_auto_rd_done - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 igc_get_auto_rd_done(struct e1000_hw *hw)
+{
+	s32 i = 0;
+	s32 ret_val = 0;
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD)
+			break;
+		usleep_range(1000, 2000);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		hw_dbg("Auto read by HW from NVM has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igc_put_hw_semaphore - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void igc_put_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	swsm = rd32(E1000_SWSM);
+
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+	wr32(E1000_SWSM, swsm);
+}
diff --git a/drivers/net/ethernet/intel/igc/e1000_mac.h b/drivers/net/ethernet/intel/igc/e1000_mac.h
index afb0f7b28222..2f8dbf17800a 100644
--- a/drivers/net/ethernet/intel/igc/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igc/e1000_mac.h
@@ -4,10 +4,21 @@ 
 #ifndef _E1000_MAC_H_
 #define _E1000_MAC_H_
 
+#include "e1000_hw.h"
+#include "e1000_defines.h"
+
 #ifndef E1000_REMOVED
 #define E1000_REMOVED(a) (0)
 #endif /* E1000_REMOVED */
 
-s32 igc_get_bus_info_pcie(struct e1000_hw *hw);
+/* forward declaration */
+s32  igc_disable_pcie_master(struct e1000_hw *hw);
+void igc_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+s32  igc_setup_link(struct e1000_hw *hw);
+void igc_clear_hw_cntrs_base(struct e1000_hw *hw);
+s32 igc_get_auto_rd_done(struct e1000_hw *hw);
+void igc_put_hw_semaphore(struct e1000_hw *hw);
+
+s32  igc_get_bus_info_pcie(struct e1000_hw *hw);
 
 #endif
diff --git a/drivers/net/ethernet/intel/igc/e1000_regs.h b/drivers/net/ethernet/intel/igc/e1000_regs.h
index dcc4d89c9933..66d5c757dae8 100644
--- a/drivers/net/ethernet/intel/igc/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igc/e1000_regs.h
@@ -7,6 +7,7 @@ 
 /* General Register Descriptions */
 #define E1000_CTRL		0x00000  /* Device Control - RW */
 #define E1000_STATUS		0x00008  /* Device Status - RO */
+#define E1000_EECD		0x00010  /* EEPROM/Flash Control - RW */
 #define E1000_CTRL_EXT		0x00018  /* Extended Device Control - RW */
 #define E1000_MDIC		0x00020  /* MDI Control - RW */
 #define E1000_MDICNFG		0x00E04  /* MDC/MDIO Configuration - RW */
@@ -75,6 +76,30 @@ 
 #define E1000_IVAR_MISC		0x01740   /* IVAR for "other" causes - RW */
 #define E1000_GPIE		0x01514  /* General Purpose Intr Enable - RW */
 
+/* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXPTC		0x04104
+/* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICRXATC		0x04108
+/* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXPTC		0x0410C
+/* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXATC		0x04110
+/* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQEC		0x04118
+/* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICTXQMTC		0x0411C
+/* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXDMTC		0x04120
+/* Interrupt Cause Receiver Overrun Count */
+#define E1000_ICRXOC		0x04124
+
+#define E1000_CBTMPC		0x0402C  /* Circuit Breaker TX Packet Count */
+#define E1000_HTDPMC		0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRMPC		0x040FC  /* Circuit Breaker RX Packet Count */
+#define E1000_RPTHC		0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC		0x04118  /* Host Good Packets TX Count */
+#define E1000_HTCBDPC		0x04124  /* Host TX Circ.Breaker Drop Count */
+
 /* MSI-X Table Register Descriptions */
 #define E1000_PBACL		0x05B68  /* MSIx PBA Clear - R/W 1 to clear */
 
@@ -92,6 +117,8 @@ 
 #define E1000_RXCSUM		0x05000  /* Rx Checksum Control - RW */
 #define E1000_RLPML		0x05004  /* Rx Long Packet Max Length */
 #define E1000_RFCTL		0x05008  /* Receive Filter Control*/
+#define E1000_MTA		0x05200  /* Multicast Table Array - RW Array */
+#define E1000_UTA		0x0A000 /* Unicast Table Array - RW */
 #define E1000_RAL(_n)		(0x05400 + ((_n) * 0x08))
 #define E1000_RAH(_n)		(0x05404 + ((_n) * 0x08))
 #define E1000_VLAPQF		0x055B0  /* VLAN Priority Queuue - RW */
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 67826041eb3c..9a99c7d68796 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -86,6 +86,14 @@  enum latency_range {
 
 void igc_reset(struct igc_adapter *adapter)
 {
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_hw *hw = &adapter->hw;
+
+	hw->mac.ops.reset_hw(hw);
+
+	if (hw->mac.ops.init_hw(hw))
+		dev_err(&pdev->dev, "Hardware Error\n");
+
 	if (!netif_running(adapter->netdev))
 		igc_power_down_link(adapter);
 }
@@ -3621,6 +3629,19 @@  static void igc_nfc_filter_exit(struct igc_adapter *adapter)
 }
 
 /**
+ *  igc_get_hw_dev - return device
+ *  @hw: pointer to hardware structure
+ *
+ *  used by hardware layer to print debugging information
+ **/
+struct net_device *igc_get_hw_dev(struct e1000_hw *hw)
+{
+	struct igc_adapter *adapter = hw->back;
+
+	return adapter->netdev;
+}
+
+/**
  *  igc_init_module - Driver Registration Routine
  *
  *  igc_init_module is the first routine called when the driver is