diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igb')
| -rw-r--r-- | drivers/net/ethernet/intel/igb/Makefile | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.c | 276 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_defines.h | 35 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_hw.h | 14 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_i210.c | 603 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_i210.h | 76 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_mac.c | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_nvm.c | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_phy.c | 147 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_phy.h | 22 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_regs.h | 14 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb.h | 30 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 141 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 323 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ptp.c | 385 | 
16 files changed, 1777 insertions, 298 deletions
diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile index 6565c463185..97c197fd4a8 100644 --- a/drivers/net/ethernet/intel/igb/Makefile +++ b/drivers/net/ethernet/intel/igb/Makefile @@ -33,5 +33,7 @@  obj-$(CONFIG_IGB) += igb.o  igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ -	    e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o +	    e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \ +	    e1000_i210.o +igb-$(CONFIG_IGB_PTP) += igb_ptp.o diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 08bdc33715e..e6508395842 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -36,6 +36,7 @@  #include "e1000_mac.h"  #include "e1000_82575.h" +#include "e1000_i210.h"  static s32  igb_get_invariants_82575(struct e1000_hw *);  static s32  igb_acquire_phy_82575(struct e1000_hw *); @@ -52,6 +53,8 @@ static s32  igb_write_phy_reg_82580(struct e1000_hw *, u32, u16);  static s32  igb_reset_hw_82575(struct e1000_hw *);  static s32  igb_reset_hw_82580(struct e1000_hw *);  static s32  igb_set_d0_lplu_state_82575(struct e1000_hw *, bool); +static s32  igb_set_d0_lplu_state_82580(struct e1000_hw *, bool); +static s32  igb_set_d3_lplu_state_82580(struct e1000_hw *, bool);  static s32  igb_setup_copper_link_82575(struct e1000_hw *);  static s32  igb_setup_serdes_link_82575(struct e1000_hw *);  static s32  igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16); @@ -96,6 +99,8 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw)  		break;  	case e1000_82580:  	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  		reg = rd32(E1000_MDICNFG);  		ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);  		break; @@ -150,6 +155,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  	case E1000_DEV_ID_I350_SGMII:  		mac->type = e1000_i350;  		break; +	case E1000_DEV_ID_I210_COPPER: +	case E1000_DEV_ID_I210_COPPER_OEM1: +	case E1000_DEV_ID_I210_COPPER_IT: +	case E1000_DEV_ID_I210_FIBER: +	case E1000_DEV_ID_I210_SERDES: +	case E1000_DEV_ID_I210_SGMII: +		mac->type = e1000_i210; +		break; +	case E1000_DEV_ID_I211_COPPER: +		mac->type = e1000_i211; +		break;  	default:  		return -E1000_ERR_MAC_INIT;  		break; @@ -182,26 +198,44 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  	/* Set mta register count */  	mac->mta_reg_count = 128;  	/* Set rar entry count */ -	mac->rar_entry_count = E1000_RAR_ENTRIES_82575; -	if (mac->type == e1000_82576) +	switch (mac->type) { +	case e1000_82576:  		mac->rar_entry_count = E1000_RAR_ENTRIES_82576; -	if (mac->type == e1000_82580) +		break; +	case e1000_82580:  		mac->rar_entry_count = E1000_RAR_ENTRIES_82580; -	if (mac->type == e1000_i350) +		break; +	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  		mac->rar_entry_count = E1000_RAR_ENTRIES_I350; +		break; +	default: +		mac->rar_entry_count = E1000_RAR_ENTRIES_82575; +		break; +	}  	/* reset */  	if (mac->type >= e1000_82580)  		mac->ops.reset_hw = igb_reset_hw_82580;  	else  		mac->ops.reset_hw = igb_reset_hw_82575; + +	if (mac->type >= e1000_i210) { +		mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210; +		mac->ops.release_swfw_sync = igb_release_swfw_sync_i210; +	} else { +		mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575; +		mac->ops.release_swfw_sync = igb_release_swfw_sync_82575; +	} +  	/* Set if part includes ASF firmware */  	mac->asf_firmware_present = true;  	/* Set if manageability features are enabled. */  	mac->arc_subsystem_valid =  		(rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)  			? true : false; -	/* enable EEE on i350 parts */ -	if (mac->type == e1000_i350) +	/* enable EEE on i350 parts and later parts */ +	if (mac->type >= e1000_i350)  		dev_spec->eee_disable = false;  	else  		dev_spec->eee_disable = true; @@ -213,26 +247,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  	/* NVM initialization */  	eecd = rd32(E1000_EECD); - -	nvm->opcode_bits        = 8; -	nvm->delay_usec         = 1; -	switch (nvm->override) { -	case e1000_nvm_override_spi_large: -		nvm->page_size    = 32; -		nvm->address_bits = 16; -		break; -	case e1000_nvm_override_spi_small: -		nvm->page_size    = 8; -		nvm->address_bits = 8; -		break; -	default: -		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; -		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; -		break; -	} - -	nvm->type = e1000_nvm_eeprom_spi; -  	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>  		     E1000_EECD_SIZE_EX_SHIFT); @@ -242,6 +256,33 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  	 */  	size += NVM_WORD_SIZE_BASE_SHIFT; +	nvm->word_size = 1 << size; +	if (hw->mac.type < e1000_i210) { +		nvm->opcode_bits        = 8; +		nvm->delay_usec         = 1; +		switch (nvm->override) { +		case e1000_nvm_override_spi_large: +			nvm->page_size    = 32; +			nvm->address_bits = 16; +			break; +		case e1000_nvm_override_spi_small: +			nvm->page_size    = 8; +			nvm->address_bits = 8; +			break; +		default: +			nvm->page_size    = eecd +				& E1000_EECD_ADDR_BITS ? 32 : 8; +			nvm->address_bits = eecd +				& E1000_EECD_ADDR_BITS ? 16 : 8; +			break; +		} +		if (nvm->word_size == (1 << 15)) +			nvm->page_size = 128; + +		nvm->type = e1000_nvm_eeprom_spi; +	} else +		nvm->type = e1000_nvm_flash_hw; +  	/*  	 * Check for invalid size  	 */ @@ -249,32 +290,60 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  		pr_notice("The NVM size is not valid, defaulting to 32K\n");  		size = 15;  	} -	nvm->word_size = 1 << size; -	if (nvm->word_size == (1 << 15)) -		nvm->page_size = 128;  	/* NVM Function Pointers */ -	nvm->ops.acquire = igb_acquire_nvm_82575; -	if (nvm->word_size < (1 << 15)) -		nvm->ops.read = igb_read_nvm_eerd; -	else -		nvm->ops.read = igb_read_nvm_spi; - -	nvm->ops.release = igb_release_nvm_82575;  	switch (hw->mac.type) {  	case e1000_82580:  		nvm->ops.validate = igb_validate_nvm_checksum_82580;  		nvm->ops.update = igb_update_nvm_checksum_82580; +		nvm->ops.acquire = igb_acquire_nvm_82575; +		nvm->ops.release = igb_release_nvm_82575; +		if (nvm->word_size < (1 << 15)) +			nvm->ops.read = igb_read_nvm_eerd; +		else +			nvm->ops.read = igb_read_nvm_spi; +		nvm->ops.write = igb_write_nvm_spi;  		break;  	case e1000_i350:  		nvm->ops.validate = igb_validate_nvm_checksum_i350;  		nvm->ops.update = igb_update_nvm_checksum_i350; +		nvm->ops.acquire = igb_acquire_nvm_82575; +		nvm->ops.release = igb_release_nvm_82575; +		if (nvm->word_size < (1 << 15)) +			nvm->ops.read = igb_read_nvm_eerd; +		else +			nvm->ops.read = igb_read_nvm_spi; +		nvm->ops.write = igb_write_nvm_spi; +		break; +	case e1000_i210: +		nvm->ops.validate = igb_validate_nvm_checksum_i210; +		nvm->ops.update   = igb_update_nvm_checksum_i210; +		nvm->ops.acquire = igb_acquire_nvm_i210; +		nvm->ops.release = igb_release_nvm_i210; +		nvm->ops.read    = igb_read_nvm_srrd_i210; +		nvm->ops.valid_led_default = igb_valid_led_default_i210; +		break; +	case e1000_i211: +		nvm->ops.acquire  = igb_acquire_nvm_i210; +		nvm->ops.release  = igb_release_nvm_i210; +		nvm->ops.read     = igb_read_nvm_i211; +		nvm->ops.valid_led_default = igb_valid_led_default_i210; +		nvm->ops.validate = NULL; +		nvm->ops.update   = NULL; +		nvm->ops.write    = NULL;  		break;  	default:  		nvm->ops.validate = igb_validate_nvm_checksum;  		nvm->ops.update = igb_update_nvm_checksum; +		nvm->ops.acquire = igb_acquire_nvm_82575; +		nvm->ops.release = igb_release_nvm_82575; +		if (nvm->word_size < (1 << 15)) +			nvm->ops.read = igb_read_nvm_eerd; +		else +			nvm->ops.read = igb_read_nvm_spi; +		nvm->ops.write = igb_write_nvm_spi; +		break;  	} -	nvm->ops.write = igb_write_nvm_spi;  	/* if part supports SR-IOV then initialize mailbox parameters */  	switch (mac->type) { @@ -312,9 +381,13 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  	if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {  		phy->ops.read_reg   = igb_read_phy_reg_sgmii_82575;  		phy->ops.write_reg  = igb_write_phy_reg_sgmii_82575; -	} else if (hw->mac.type >= e1000_82580) { +	} else if ((hw->mac.type == e1000_82580) +		|| (hw->mac.type == e1000_i350)) {  		phy->ops.read_reg   = igb_read_phy_reg_82580;  		phy->ops.write_reg  = igb_write_phy_reg_82580; +	} else if (hw->phy.type >= e1000_phy_i210) { +		phy->ops.read_reg   = igb_read_phy_reg_gs40g; +		phy->ops.write_reg  = igb_write_phy_reg_gs40g;  	} else {  		phy->ops.read_reg   = igb_read_phy_reg_igp;  		phy->ops.write_reg  = igb_write_phy_reg_igp; @@ -343,6 +416,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  		else  			phy->ops.get_cable_length = igb_get_cable_length_m88; +		if (phy->id == I210_I_PHY_ID) { +			phy->ops.get_cable_length = +					 igb_get_cable_length_m88_gen2; +			phy->ops.set_d0_lplu_state = +					igb_set_d0_lplu_state_82580; +			phy->ops.set_d3_lplu_state = +					igb_set_d3_lplu_state_82580; +		}  		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;  		break;  	case IGP03E1000_E_PHY_ID: @@ -359,6 +440,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)  		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;  		phy->ops.get_cable_length   = igb_get_cable_length_82580;  		phy->ops.get_phy_info       = igb_get_phy_info_82580; +		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82580; +		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state_82580; +		break; +	case I210_I_PHY_ID: +		phy->type                   = e1000_phy_i210; +		phy->ops.get_phy_info       = igb_get_phy_info_m88; +		phy->ops.check_polarity     = igb_check_polarity_m88; +		phy->ops.get_cable_length   = igb_get_cable_length_m88_gen2; +		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82580; +		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state_82580; +		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;  		break;  	default:  		return -E1000_ERR_PHY; @@ -385,7 +477,7 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw)  	else if (hw->bus.func == E1000_FUNC_3)  		mask = E1000_SWFW_PHY3_SM; -	return igb_acquire_swfw_sync_82575(hw, mask); +	return hw->mac.ops.acquire_swfw_sync(hw, mask);  }  /** @@ -406,7 +498,7 @@ static void igb_release_phy_82575(struct e1000_hw *hw)  	else if (hw->bus.func == E1000_FUNC_3)  		mask = E1000_SWFW_PHY3_SM; -	igb_release_swfw_sync_82575(hw, mask); +	hw->mac.ops.release_swfw_sync(hw, mask);  }  /** @@ -510,6 +602,8 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)  			break;  		case e1000_82580:  		case e1000_i350: +		case e1000_i210: +		case e1000_i211:  			mdic = rd32(E1000_MDICNFG);  			mdic &= E1000_MDICNFG_PHY_MASK;  			phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT; @@ -674,6 +768,96 @@ out:  }  /** + *  igb_set_d0_lplu_state_82580 - Set Low Power Linkup D0 state + *  @hw: pointer to the HW structure + *  @active: true to enable LPLU, false to disable + * + *  Sets the LPLU D0 state according to the active flag.  When + *  activating LPLU this function also disables smart speed + *  and vice versa.  LPLU will not be activated unless the + *  device autonegotiation advertisement meets standards of + *  either 10 or 10/100 or 10/100/1000 at all duplexes. + *  This is a function pointer entry point only called by + *  PHY setup routines. + **/ +static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active) +{ +	struct e1000_phy_info *phy = &hw->phy; +	s32 ret_val = 0; +	u16 data; + +	data = rd32(E1000_82580_PHY_POWER_MGMT); + +	if (active) { +		data |= E1000_82580_PM_D0_LPLU; + +		/* When LPLU is enabled, we should disable SmartSpeed */ +		data &= ~E1000_82580_PM_SPD; +	} else { +		data &= ~E1000_82580_PM_D0_LPLU; + +		/* +		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used +		 * during Dx states where the power conservation is most +		 * important.  During driver activity we should enable +		 * SmartSpeed, so performance is maintained. +		 */ +		if (phy->smart_speed == e1000_smart_speed_on) +			data |= E1000_82580_PM_SPD; +		else if (phy->smart_speed == e1000_smart_speed_off) +			data &= ~E1000_82580_PM_SPD; } + +	wr32(E1000_82580_PHY_POWER_MGMT, data); +	return ret_val; +} + +/** + *  igb_set_d3_lplu_state_82580 - Sets low power link up state for D3 + *  @hw: pointer to the HW structure + *  @active: boolean used to enable/disable lplu + * + *  Success returns 0, Failure returns 1 + * + *  The low power link up (lplu) state is set to the power management level D3 + *  and SmartSpeed is disabled when active is true, else clear lplu for D3 + *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU + *  is used during Dx states where the power conservation is most important. + *  During driver activity, SmartSpeed should be enabled so performance is + *  maintained. + **/ +s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active) +{ +	struct e1000_phy_info *phy = &hw->phy; +	s32 ret_val = 0; +	u16 data; + +	data = rd32(E1000_82580_PHY_POWER_MGMT); + +	if (!active) { +		data &= ~E1000_82580_PM_D3_LPLU; +		/* +		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used +		 * during Dx states where the power conservation is most +		 * important.  During driver activity we should enable +		 * SmartSpeed, so performance is maintained. +		 */ +		if (phy->smart_speed == e1000_smart_speed_on) +			data |= E1000_82580_PM_SPD; +		else if (phy->smart_speed == e1000_smart_speed_off) +			data &= ~E1000_82580_PM_SPD; +	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || +		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || +		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { +		data |= E1000_82580_PM_D3_LPLU; +		/* When LPLU is enabled, we should disable SmartSpeed */ +		data &= ~E1000_82580_PM_SPD; +	} + +	wr32(E1000_82580_PHY_POWER_MGMT, data); +	return ret_val; +} + +/**   *  igb_acquire_nvm_82575 - Request for access to EEPROM   *  @hw: pointer to the HW structure   * @@ -686,14 +870,14 @@ static s32 igb_acquire_nvm_82575(struct e1000_hw *hw)  {  	s32 ret_val; -	ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); +	ret_val = hw->mac.ops.acquire_swfw_sync(hw, E1000_SWFW_EEP_SM);  	if (ret_val)  		goto out;  	ret_val = igb_acquire_nvm(hw);  	if (ret_val) -		igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); +		hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM);  out:  	return ret_val; @@ -709,7 +893,7 @@ out:  static void igb_release_nvm_82575(struct e1000_hw *hw)  {  	igb_release_nvm(hw); -	igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); +	hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM);  }  /** @@ -1080,7 +1264,6 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)  	 * is no link.  	 */  	igb_clear_hw_cntrs_82575(hw); -  	return ret_val;  } @@ -1117,6 +1300,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)  		}  	}  	switch (hw->phy.type) { +	case e1000_phy_i210:  	case e1000_phy_m88:  		if (hw->phy.id == I347AT4_E_PHY_ID ||  		    hw->phy.id == M88E1112_E_PHY_ID) @@ -1757,7 +1941,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)  	/* Determine whether or not a global dev reset is requested */  	if (global_device_reset && -		igb_acquire_swfw_sync_82575(hw, swmbsw_mask)) +		hw->mac.ops.acquire_swfw_sync(hw, swmbsw_mask))  			global_device_reset = false;  	if (global_device_reset && @@ -1803,7 +1987,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)  	/* Release semaphore */  	if (global_device_reset) -		igb_release_swfw_sync_82575(hw, swmbsw_mask); +		hw->mac.ops.release_swfw_sync(hw, swmbsw_mask);  	return ret_val;  } diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index b927d79ab53..e85c453f542 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -55,10 +55,11 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);  #define E1000_SRRCTL_DROP_EN                            0x80000000  #define E1000_SRRCTL_TIMESTAMP                          0x40000000 +  #define E1000_MRQC_ENABLE_RSS_4Q            0x00000002  #define E1000_MRQC_ENABLE_VMDQ              0x00000003 -#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005  #define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000 +#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005  #define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000  #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000 diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 89eb1f85b9f..ec7e4fe3e3e 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -301,6 +301,8 @@  							* transactions */  #define E1000_DMACR_DMAC_LX_SHIFT       28  #define E1000_DMACR_DMAC_EN             0x80000000 /* Enable DMA Coalescing */ +/* DMA Coalescing BMC-to-OS Watchdog Enable */ +#define E1000_DMACR_DC_BMC2OSW_EN	0x00008000  #define E1000_DMCTXTH_DMCTTHR_MASK      0x00000FFF /* DMA Coalescing Transmit  							* Threshold */ @@ -458,6 +460,7 @@  #define E1000_ERR_INVALID_ARGUMENT  16  #define E1000_ERR_NO_SPACE          17  #define E1000_ERR_NVM_PBA_SECTION   18 +#define E1000_ERR_INVM_VALUE_NOT_FOUND	19  /* Loop limit on how long we wait for auto-negotiation to complete */  #define COPPER_LINK_UP_LIMIT              10 @@ -595,6 +598,25 @@  #define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */  #define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */  #define E1000_EECD_SIZE_EX_SHIFT     11 +#define E1000_EECD_FLUPD_I210		0x00800000 /* Update FLASH */ +#define E1000_EECD_FLUDONE_I210		0x04000000 /* Update FLASH done*/ +#define E1000_FLUDONE_ATTEMPTS		20000 +#define E1000_EERD_EEWR_MAX_COUNT	512 /* buffered EEPROM words rw */ +#define E1000_I210_FIFO_SEL_RX		0x00 +#define E1000_I210_FIFO_SEL_TX_QAV(_i)	(0x02 + (_i)) +#define E1000_I210_FIFO_SEL_TX_LEGACY	E1000_I210_FIFO_SEL_TX_QAV(0) +#define E1000_I210_FIFO_SEL_BMC2OS_TX	0x06 +#define E1000_I210_FIFO_SEL_BMC2OS_RX	0x01 +#define E1000_EECD_FLUPD_I210		0x00800000 /* Update FLASH */ +#define E1000_EECD_FLUDONE_I210		0x04000000 /* Update FLASH done*/ +#define E1000_FLUDONE_ATTEMPTS		20000 +#define E1000_EERD_EEWR_MAX_COUNT	512 /* buffered EEPROM words rw */ +#define E1000_I210_FIFO_SEL_RX		0x00 +#define E1000_I210_FIFO_SEL_TX_QAV(_i)	(0x02 + (_i)) +#define E1000_I210_FIFO_SEL_TX_LEGACY	E1000_I210_FIFO_SEL_TX_QAV(0) +#define E1000_I210_FIFO_SEL_BMC2OS_TX	0x06 +#define E1000_I210_FIFO_SEL_BMC2OS_RX	0x01 +  /* Offset to data in NVM read/write registers */  #define E1000_NVM_RW_REG_DATA   16 @@ -613,6 +635,16 @@  #define NVM_CHECKSUM_REG           0x003F  #define NVM_COMPATIBILITY_REG_3    0x0003  #define NVM_COMPATIBILITY_BIT_MASK 0x8000 +#define NVM_MAC_ADDR               0x0000 +#define NVM_SUB_DEV_ID             0x000B +#define NVM_SUB_VEN_ID             0x000C +#define NVM_DEV_ID                 0x000D +#define NVM_VEN_ID                 0x000E +#define NVM_INIT_CTRL_2            0x000F +#define NVM_INIT_CTRL_4            0x0013 +#define NVM_LED_1_CFG              0x001C +#define NVM_LED_0_2_CFG            0x001F +  #define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */  #define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */ @@ -639,6 +671,7 @@  #define NVM_PBA_OFFSET_0           8  #define NVM_PBA_OFFSET_1           9 +#define NVM_RESERVED_WORD		0xFFFF  #define NVM_PBA_PTR_GUARD          0xFAFA  #define NVM_WORD_SIZE_BASE_SHIFT   6 @@ -696,6 +729,7 @@  #define I82580_I_PHY_ID      0x015403A0  #define I350_I_PHY_ID        0x015403B0  #define M88_VENDOR           0x0141 +#define I210_I_PHY_ID        0x01410C00  /* M88E1000 Specific Registers */  #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */ @@ -815,6 +849,7 @@  #define E1000_IPCNFG_EEE_100M_AN     0x00000004  /* EEE Enable 100M AN */  #define E1000_EEER_TX_LPI_EN         0x00010000  /* EEE Tx LPI Enable */  #define E1000_EEER_RX_LPI_EN         0x00020000  /* EEE Rx LPI Enable */ +#define E1000_EEER_FRC_AN            0x10000000 /* Enable EEE in loopback */  #define E1000_EEER_LPI_FC            0x00040000  /* EEE Enable on FC */  /* SerDes Control */ diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index f67cbd3fa30..c2a51dcda55 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -63,6 +63,13 @@ struct e1000_hw;  #define E1000_DEV_ID_I350_FIBER               0x1522  #define E1000_DEV_ID_I350_SERDES              0x1523  #define E1000_DEV_ID_I350_SGMII               0x1524 +#define E1000_DEV_ID_I210_COPPER		0x1533 +#define E1000_DEV_ID_I210_COPPER_OEM1		0x1534 +#define E1000_DEV_ID_I210_COPPER_IT		0x1535 +#define E1000_DEV_ID_I210_FIBER			0x1536 +#define E1000_DEV_ID_I210_SERDES		0x1537 +#define E1000_DEV_ID_I210_SGMII			0x1538 +#define E1000_DEV_ID_I211_COPPER		0x1539  #define E1000_REVISION_2 2  #define E1000_REVISION_4 4 @@ -83,6 +90,8 @@ enum e1000_mac_type {  	e1000_82576,  	e1000_82580,  	e1000_i350, +	e1000_i210, +	e1000_i211,  	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */  }; @@ -117,6 +126,7 @@ enum e1000_phy_type {  	e1000_phy_igp_3,  	e1000_phy_ife,  	e1000_phy_82580, +	e1000_phy_i210,  };  enum e1000_bus_type { @@ -313,6 +323,9 @@ struct e1000_mac_operations {  	void (*rar_set)(struct e1000_hw *, u8 *, u32);  	s32  (*read_mac_addr)(struct e1000_hw *);  	s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); +	s32  (*acquire_swfw_sync)(struct e1000_hw *, u16); +	void (*release_swfw_sync)(struct e1000_hw *, u16); +  };  struct e1000_phy_operations { @@ -338,6 +351,7 @@ struct e1000_nvm_operations {  	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);  	s32  (*update)(struct e1000_hw *);  	s32  (*validate)(struct e1000_hw *); +	s32  (*valid_led_default)(struct e1000_hw *, u16 *);  };  struct e1000_info { diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c new file mode 100644 index 00000000000..77a5f939bc7 --- /dev/null +++ b/drivers/net/ethernet/intel/igb/e1000_i210.c @@ -0,0 +1,603 @@ +/******************************************************************************* + +  Intel(R) Gigabit Ethernet Linux driver +  Copyright(c) 2007-2012 Intel Corporation. + +  This program is free software; you can redistribute it and/or modify it +  under the terms and conditions of the GNU General Public License, +  version 2, as published by the Free Software Foundation. + +  This program is distributed in the hope it will be useful, but WITHOUT +  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for +  more details. + +  You should have received a copy of the GNU General Public License along with +  this program; if not, write to the Free Software Foundation, Inc., +  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + +  The full GNU General Public License is included in this distribution in +  the file called "COPYING". + +  Contact Information: +  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> +  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ + +/* e1000_i210 + * e1000_i211 + */ + +#include <linux/types.h> +#include <linux/if_ether.h> + +#include "e1000_hw.h" +#include "e1000_i210.h" + +static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw); +static void igb_put_hw_semaphore_i210(struct e1000_hw *hw); +static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, +				u16 *data); +static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw); + +/** + *  igb_acquire_nvm_i210 - Request for access to EEPROM + *  @hw: pointer to the HW structure + * + *  Acquire the necessary semaphores for exclusive access to the EEPROM. + *  Set the EEPROM access request bit and wait for EEPROM access grant bit. + *  Return successful if access grant bit set, else clear the request for + *  EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 igb_acquire_nvm_i210(struct e1000_hw *hw) +{ +	return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); +} + +/** + *  igb_release_nvm_i210 - Release exclusive access to EEPROM + *  @hw: pointer to the HW structure + * + *  Stop any current commands to the EEPROM and clear the EEPROM request bit, + *  then release the semaphores acquired. + **/ +void igb_release_nvm_i210(struct e1000_hw *hw) +{ +	igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); +} + +/** + *  igb_acquire_swfw_sync_i210 - 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 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) +{ +	u32 swfw_sync; +	u32 swmask = mask; +	u32 fwmask = mask << 16; +	s32 ret_val = E1000_SUCCESS; +	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ + +	while (i < timeout) { +		if (igb_get_hw_semaphore_i210(hw)) { +			ret_val = -E1000_ERR_SWFW_SYNC; +			goto out; +		} + +		swfw_sync = rd32(E1000_SW_FW_SYNC); +		if (!(swfw_sync & fwmask)) +			break; + +		/* +		 * Firmware currently using resource (fwmask) +		 */ +		igb_put_hw_semaphore_i210(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); + +	igb_put_hw_semaphore_i210(hw); +out: +	return ret_val; +} + +/** + *  igb_release_swfw_sync_i210 - 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 igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) +{ +	u32 swfw_sync; + +	while (igb_get_hw_semaphore_i210(hw) != E1000_SUCCESS) +		; /* Empty */ + +	swfw_sync = rd32(E1000_SW_FW_SYNC); +	swfw_sync &= ~mask; +	wr32(E1000_SW_FW_SYNC, swfw_sync); + +	igb_put_hw_semaphore_i210(hw); +} + +/** + *  igb_get_hw_semaphore_i210 - Acquire hardware semaphore + *  @hw: pointer to the HW structure + * + *  Acquire the HW semaphore to access the PHY or NVM + **/ +static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) +{ +	u32 swsm; +	s32 ret_val = E1000_SUCCESS; +	s32 timeout = hw->nvm.word_size + 1; +	s32 i = 0; + +	/* 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; + +		udelay(50); +	} + +	if (i == timeout) { +		/* Release semaphores */ +		igb_put_hw_semaphore(hw); +		hw_dbg("Driver can't access the NVM\n"); +		ret_val = -E1000_ERR_NVM; +		goto out; +	} + +out: +	return ret_val; +} + +/** + *  igb_put_hw_semaphore_i210 - Release hardware semaphore + *  @hw: pointer to the HW structure + * + *  Release hardware semaphore used to access the PHY or NVM + **/ +static void igb_put_hw_semaphore_i210(struct e1000_hw *hw) +{ +	u32 swsm; + +	swsm = rd32(E1000_SWSM); + +	swsm &= ~E1000_SWSM_SWESMBI; + +	wr32(E1000_SWSM, swsm); +} + +/** + *  igb_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register + *  @hw: pointer to the HW structure + *  @offset: offset of word in the Shadow Ram to read + *  @words: number of words to read + *  @data: word read from the Shadow Ram + * + *  Reads a 16 bit word from the Shadow Ram using the EERD register. + *  Uses necessary synchronization semaphores. + **/ +s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, +			     u16 *data) +{ +	s32 status = E1000_SUCCESS; +	u16 i, count; + +	/* We cannot hold synchronization semaphores for too long, +	 * because of forceful takeover procedure. However it is more efficient +	 * to read in bursts than synchronizing access for each word. */ +	for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { +		count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? +			E1000_EERD_EEWR_MAX_COUNT : (words - i); +		if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { +			status = igb_read_nvm_eerd(hw, offset, count, +						     data + i); +			hw->nvm.ops.release(hw); +		} else { +			status = E1000_ERR_SWFW_SYNC; +		} + +		if (status != E1000_SUCCESS) +			break; +	} + +	return status; +} + +/** + *  igb_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR + *  @hw: pointer to the HW structure + *  @offset: offset within the Shadow RAM to be written to + *  @words: number of words to write + *  @data: 16 bit word(s) to be written to the Shadow RAM + * + *  Writes data to Shadow RAM at offset using EEWR register. + * + *  If e1000_update_nvm_checksum is not called after this function , the + *  data will not be committed to FLASH and also Shadow RAM will most likely + *  contain an invalid checksum. + * + *  If error code is returned, data and Shadow RAM may be inconsistent - buffer + *  partially written. + **/ +s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, +			      u16 *data) +{ +	s32 status = E1000_SUCCESS; +	u16 i, count; + +	/* We cannot hold synchronization semaphores for too long, +	 * because of forceful takeover procedure. However it is more efficient +	 * to write in bursts than synchronizing access for each word. */ +	for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { +		count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? +			E1000_EERD_EEWR_MAX_COUNT : (words - i); +		if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { +			status = igb_write_nvm_srwr(hw, offset, count, +						      data + i); +			hw->nvm.ops.release(hw); +		} else { +			status = E1000_ERR_SWFW_SYNC; +		} + +		if (status != E1000_SUCCESS) +			break; +	} + +	return status; +} + +/** + *  igb_write_nvm_srwr - Write to Shadow Ram using EEWR + *  @hw: pointer to the HW structure + *  @offset: offset within the Shadow Ram to be written to + *  @words: number of words to write + *  @data: 16 bit word(s) to be written to the Shadow Ram + * + *  Writes data to Shadow Ram at offset using EEWR register. + * + *  If igb_update_nvm_checksum is not called after this function , the + *  Shadow Ram will most likely contain an invalid checksum. + **/ +static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, +				u16 *data) +{ +	struct e1000_nvm_info *nvm = &hw->nvm; +	u32 i, k, eewr = 0; +	u32 attempts = 100000; +	s32 ret_val = E1000_SUCCESS; + +	/* +	 * A check for invalid values:  offset too large, too many words, +	 * too many words for the offset, and not enough words. +	 */ +	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || +	    (words == 0)) { +		hw_dbg("nvm parameter(s) out of bounds\n"); +		ret_val = -E1000_ERR_NVM; +		goto out; +	} + +	for (i = 0; i < words; i++) { +		eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | +			(data[i] << E1000_NVM_RW_REG_DATA) | +			E1000_NVM_RW_REG_START; + +		wr32(E1000_SRWR, eewr); + +		for (k = 0; k < attempts; k++) { +			if (E1000_NVM_RW_REG_DONE & +			    rd32(E1000_SRWR)) { +				ret_val = E1000_SUCCESS; +				break; +			} +			udelay(5); +	} + +		if (ret_val != E1000_SUCCESS) { +			hw_dbg("Shadow RAM write EEWR timed out\n"); +			break; +		} +	} + +out: +	return ret_val; +} + +/** + *  igb_read_nvm_i211 - Read NVM wrapper function for I211 + *  @hw: pointer to the HW structure + *  @address: the word address (aka eeprom offset) to read + *  @data: pointer to the data read + * + *  Wrapper function to return data formerly found in the NVM. + **/ +s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, +			       u16 *data) +{ +	s32 ret_val = E1000_SUCCESS; + +	/* Only the MAC addr is required to be present in the iNVM */ +	switch (offset) { +	case NVM_MAC_ADDR: +		ret_val = igb_read_invm_i211(hw, offset, &data[0]); +		ret_val |= igb_read_invm_i211(hw, offset+1, &data[1]); +		ret_val |= igb_read_invm_i211(hw, offset+2, &data[2]); +		if (ret_val != E1000_SUCCESS) +			hw_dbg("MAC Addr not found in iNVM\n"); +		break; +	case NVM_ID_LED_SETTINGS: +	case NVM_INIT_CTRL_2: +	case NVM_INIT_CTRL_4: +	case NVM_LED_1_CFG: +	case NVM_LED_0_2_CFG: +		igb_read_invm_i211(hw, offset, data); +		break; +	case NVM_COMPAT: +		*data = ID_LED_DEFAULT_I210; +		break; +	case NVM_SUB_DEV_ID: +		*data = hw->subsystem_device_id; +		break; +	case NVM_SUB_VEN_ID: +		*data = hw->subsystem_vendor_id; +		break; +	case NVM_DEV_ID: +		*data = hw->device_id; +		break; +	case NVM_VEN_ID: +		*data = hw->vendor_id; +		break; +	default: +		hw_dbg("NVM word 0x%02x is not mapped.\n", offset); +		*data = NVM_RESERVED_WORD; +		break; +	} +	return ret_val; +} + +/** + *  igb_read_invm_i211 - Reads OTP + *  @hw: pointer to the HW structure + *  @address: the word address (aka eeprom offset) to read + *  @data: pointer to the data read + * + *  Reads 16-bit words from the OTP. Return error when the word is not + *  stored in OTP. + **/ +s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data) +{ +	s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; +	u32 invm_dword; +	u16 i; +	u8 record_type, word_address; + +	for (i = 0; i < E1000_INVM_SIZE; i++) { +		invm_dword = rd32(E1000_INVM_DATA_REG(i)); +		/* Get record type */ +		record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); +		if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE) +			break; +		if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE) +			i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS; +		if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE) +			i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS; +		if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) { +			word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword); +			if (word_address == (u8)address) { +				*data = INVM_DWORD_TO_WORD_DATA(invm_dword); +				hw_dbg("Read INVM Word 0x%02x = %x", +					  address, *data); +				status = E1000_SUCCESS; +				break; +			} +		} +	} +	if (status != E1000_SUCCESS) +		hw_dbg("Requested word 0x%02x not found in OTP\n", address); +	return status; +} + +/** + *  igb_validate_nvm_checksum_i210 - Validate EEPROM checksum + *  @hw: pointer to the HW structure + * + *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM + *  and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) +{ +	s32 status = E1000_SUCCESS; +	s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); + +	if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + +		/* +		 * Replace the read function with semaphore grabbing with +		 * the one that skips this for a while. +		 * We have semaphore taken already here. +		 */ +		read_op_ptr = hw->nvm.ops.read; +		hw->nvm.ops.read = igb_read_nvm_eerd; + +		status = igb_validate_nvm_checksum(hw); + +		/* Revert original read operation. */ +		hw->nvm.ops.read = read_op_ptr; + +		hw->nvm.ops.release(hw); +	} else { +		status = E1000_ERR_SWFW_SYNC; +	} + +	return status; +} + + +/** + *  igb_update_nvm_checksum_i210 - Update EEPROM checksum + *  @hw: pointer to the HW structure + * + *  Updates the EEPROM checksum by reading/adding each word of the EEPROM + *  up to the checksum.  Then calculates the EEPROM checksum and writes the + *  value to the EEPROM. Next commit EEPROM data onto the Flash. + **/ +s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw) +{ +	s32 ret_val = E1000_SUCCESS; +	u16 checksum = 0; +	u16 i, nvm_data; + +	/* +	 * Read the first word from the EEPROM. If this times out or fails, do +	 * not continue or we could be in for a very long wait while every +	 * EEPROM read fails +	 */ +	ret_val = igb_read_nvm_eerd(hw, 0, 1, &nvm_data); +	if (ret_val != E1000_SUCCESS) { +		hw_dbg("EEPROM read failed\n"); +		goto out; +	} + +	if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { +		/* +		 * Do not use hw->nvm.ops.write, hw->nvm.ops.read +		 * because we do not want to take the synchronization +		 * semaphores twice here. +		 */ + +		for (i = 0; i < NVM_CHECKSUM_REG; i++) { +			ret_val = igb_read_nvm_eerd(hw, i, 1, &nvm_data); +			if (ret_val) { +				hw->nvm.ops.release(hw); +				hw_dbg("NVM Read Error while updating checksum.\n"); +				goto out; +			} +			checksum += nvm_data; +		} +		checksum = (u16) NVM_SUM - checksum; +		ret_val = igb_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, +						&checksum); +		if (ret_val != E1000_SUCCESS) { +			hw->nvm.ops.release(hw); +			hw_dbg("NVM Write Error while updating checksum.\n"); +			goto out; +		} + +		hw->nvm.ops.release(hw); + +		ret_val = igb_update_flash_i210(hw); +	} else { +		ret_val = -E1000_ERR_SWFW_SYNC; +	} +out: +	return ret_val; +} + +/** + *  igb_update_flash_i210 - Commit EEPROM to the flash + *  @hw: pointer to the HW structure + * + **/ +s32 igb_update_flash_i210(struct e1000_hw *hw) +{ +	s32 ret_val = E1000_SUCCESS; +	u32 flup; + +	ret_val = igb_pool_flash_update_done_i210(hw); +	if (ret_val == -E1000_ERR_NVM) { +		hw_dbg("Flash update time out\n"); +		goto out; +	} + +	flup = rd32(E1000_EECD) | E1000_EECD_FLUPD_I210; +	wr32(E1000_EECD, flup); + +	ret_val = igb_pool_flash_update_done_i210(hw); +	if (ret_val == E1000_SUCCESS) +		hw_dbg("Flash update complete\n"); +	else +		hw_dbg("Flash update time out\n"); + +out: +	return ret_val; +} + +/** + *  igb_pool_flash_update_done_i210 - Pool FLUDONE status. + *  @hw: pointer to the HW structure + * + **/ +s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw) +{ +	s32 ret_val = -E1000_ERR_NVM; +	u32 i, reg; + +	for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { +		reg = rd32(E1000_EECD); +		if (reg & E1000_EECD_FLUDONE_I210) { +			ret_val = E1000_SUCCESS; +			break; +		} +		udelay(5); +	} + +	return ret_val; +} + +/** + *  igb_valid_led_default_i210 - Verify a valid default LED config + *  @hw: pointer to the HW structure + *  @data: pointer to the NVM (EEPROM) + * + *  Read the EEPROM for the current default LED configuration.  If the + *  LED configuration is not valid, set to a valid LED configuration. + **/ +s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data) +{ +	s32 ret_val; + +	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); +	if (ret_val) { +		hw_dbg("NVM Read Error\n"); +		goto out; +	} + +	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { +		switch (hw->phy.media_type) { +		case e1000_media_type_internal_serdes: +			*data = ID_LED_DEFAULT_I210_SERDES; +			break; +		case e1000_media_type_copper: +		default: +			*data = ID_LED_DEFAULT_I210; +			break; +		} +	} +out: +	return ret_val; +} diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h new file mode 100644 index 00000000000..5dc2bd3f50b --- /dev/null +++ b/drivers/net/ethernet/intel/igb/e1000_i210.h @@ -0,0 +1,76 @@ +/******************************************************************************* + +  Intel(R) Gigabit Ethernet Linux driver +  Copyright(c) 2007-2012 Intel Corporation. + +  This program is free software; you can redistribute it and/or modify it +  under the terms and conditions of the GNU General Public License, +  version 2, as published by the Free Software Foundation. + +  This program is distributed in the hope it will be useful, but WITHOUT +  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for +  more details. + +  You should have received a copy of the GNU General Public License along with +  this program; if not, write to the Free Software Foundation, Inc., +  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + +  The full GNU General Public License is included in this distribution in +  the file called "COPYING". + +  Contact Information: +  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> +  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_I210_H_ +#define _E1000_I210_H_ + +extern s32 igb_update_flash_i210(struct e1000_hw *hw); +extern s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw); +extern s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw); +extern s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, +			      u16 words, u16 *data); +extern s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, +			     u16 words, u16 *data); +extern s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data); +extern s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask); +extern void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask); +extern s32 igb_acquire_nvm_i210(struct e1000_hw *hw); +extern void igb_release_nvm_i210(struct e1000_hw *hw); +extern s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data); +extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, +			       u16 *data); + +#define E1000_STM_OPCODE		0xDB00 +#define E1000_EEPROM_FLASH_SIZE_WORD	0x11 + +#define INVM_DWORD_TO_RECORD_TYPE(invm_dword) \ +	(u8)((invm_dword) & 0x7) +#define INVM_DWORD_TO_WORD_ADDRESS(invm_dword) \ +	(u8)(((invm_dword) & 0x0000FE00) >> 9) +#define INVM_DWORD_TO_WORD_DATA(invm_dword) \ +	(u16)(((invm_dword) & 0xFFFF0000) >> 16) + +enum E1000_INVM_STRUCTURE_TYPE { +	E1000_INVM_UNINITIALIZED_STRUCTURE		= 0x00, +	E1000_INVM_WORD_AUTOLOAD_STRUCTURE		= 0x01, +	E1000_INVM_CSR_AUTOLOAD_STRUCTURE		= 0x02, +	E1000_INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE	= 0x03, +	E1000_INVM_RSA_KEY_SHA256_STRUCTURE		= 0x04, +	E1000_INVM_INVALIDATED_STRUCTURE		= 0x0F, +}; + +#define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS	8 +#define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS	1 + +#define ID_LED_DEFAULT_I210		((ID_LED_OFF1_ON2  << 8) | \ +					 (ID_LED_OFF1_OFF2 <<  4) | \ +					 (ID_LED_DEF1_DEF2)) +#define ID_LED_DEFAULT_I210_SERDES	((ID_LED_DEF1_DEF2 << 8) | \ +					 (ID_LED_DEF1_DEF2 <<  4) | \ +					 (ID_LED_DEF1_DEF2)) + +#endif diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index f57338afd71..819c145ac76 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -658,6 +658,7 @@ s32 igb_setup_link(struct e1000_hw *hw)  	ret_val = igb_set_fc_watermarks(hw);  out: +  	return ret_val;  } diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c index fa2c6ba6213..aa5fcdf3f35 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.c +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c @@ -710,4 +710,3 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw)  out:  	return ret_val;  } - diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index 789de5b83aa..7be98b6f105 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -35,6 +35,7 @@ static s32  igb_phy_setup_autoneg(struct e1000_hw *hw);  static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,  					       u16 *phy_ctrl);  static s32  igb_wait_autoneg(struct e1000_hw *hw); +static s32  igb_set_master_slave_mode(struct e1000_hw *hw);  /* Cable length tables */  static const u16 e1000_m88_cable_length_table[] = @@ -570,6 +571,11 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw)  		hw_dbg("Error committing the PHY changes\n");  		goto out;  	} +	if (phy->type == e1000_phy_i210) { +		ret_val = igb_set_master_slave_mode(hw); +		if (ret_val) +			return ret_val; +	}  out:  	return ret_val; @@ -1213,12 +1219,22 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)  			goto out;  		if (!link) { -			if (hw->phy.type != e1000_phy_m88 || -			    hw->phy.id == I347AT4_E_PHY_ID || -			    hw->phy.id == M88E1112_E_PHY_ID) { -				hw_dbg("Link taking longer than expected.\n"); -			} else { +			bool reset_dsp = true; +			switch (hw->phy.id) { +			case I347AT4_E_PHY_ID: +			case M88E1112_E_PHY_ID: +			case I210_I_PHY_ID: +				reset_dsp = false; +				break; +			default: +				if (hw->phy.type != e1000_phy_m88) +					reset_dsp = false; +				break; +			} +			if (!reset_dsp) +				hw_dbg("Link taking longer than expected.\n"); +			else {  				/*  				 * We didn't get link.  				 * Reset the DSP and cross our fingers. @@ -1243,7 +1259,8 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)  	if (hw->phy.type != e1000_phy_m88 ||  	    hw->phy.id == I347AT4_E_PHY_ID || -	    hw->phy.id == M88E1112_E_PHY_ID) +	    hw->phy.id == M88E1112_E_PHY_ID || +	    hw->phy.id == I210_I_PHY_ID)  		goto out;  	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); @@ -1441,6 +1458,7 @@ s32 igb_check_downshift(struct e1000_hw *hw)  	u16 phy_data, offset, mask;  	switch (phy->type) { +	case e1000_phy_i210:  	case e1000_phy_m88:  	case e1000_phy_gg82563:  		offset	= M88E1000_PHY_SPEC_STATUS; @@ -1476,7 +1494,7 @@ out:   *   *  Polarity is determined based on the PHY specific status register.   **/ -static s32 igb_check_polarity_m88(struct e1000_hw *hw) +s32 igb_check_polarity_m88(struct e1000_hw *hw)  {  	struct e1000_phy_info *phy = &hw->phy;  	s32 ret_val; @@ -1665,6 +1683,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)  	u16 phy_data, phy_data2, index, default_page, is_cm;  	switch (hw->phy.id) { +	case I210_I_PHY_ID:  	case I347AT4_E_PHY_ID:  		/* Remember the original page select and set it to 7 */  		ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, @@ -2129,10 +2148,16 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw)  void igb_power_up_phy_copper(struct e1000_hw *hw)  {  	u16 mii_reg = 0; +	u16 power_reg = 0;  	/* The PHY will retain its settings across a power down/up cycle */  	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);  	mii_reg &= ~MII_CR_POWER_DOWN; +	if (hw->phy.type == e1000_phy_i210) { +		hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg); +		power_reg &= ~GS40G_CS_POWER_DOWN; +		hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); +	}  	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);  } @@ -2146,10 +2171,18 @@ void igb_power_up_phy_copper(struct e1000_hw *hw)  void igb_power_down_phy_copper(struct e1000_hw *hw)  {  	u16 mii_reg = 0; +	u16 power_reg = 0;  	/* The PHY will retain its settings across a power down/up cycle */  	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);  	mii_reg |= MII_CR_POWER_DOWN; + +	/* i210 Phy requires an additional bit for power up/down */ +	if (hw->phy.type == e1000_phy_i210) { +		hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg); +		power_reg |= GS40G_CS_POWER_DOWN; +		hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); +	}  	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);  	msleep(1);  } @@ -2345,3 +2378,103 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw)  out:  	return ret_val;  } + +/** + *  igb_write_phy_reg_gs40g - Write GS40G PHY register + *  @hw: pointer to the HW structure + *  @offset: lower half is register offset to write to + *     upper half is page to use. + *  @data: data to write at register offset + * + *  Acquires semaphore, if necessary, then writes the data to PHY register + *  at the offset.  Release any acquired semaphores before exiting. + **/ +s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data) +{ +	s32 ret_val; +	u16 page = offset >> GS40G_PAGE_SHIFT; + +	offset = offset & GS40G_OFFSET_MASK; +	ret_val = hw->phy.ops.acquire(hw); +	if (ret_val) +		return ret_val; + +	ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page); +	if (ret_val) +		goto release; +	ret_val = igb_write_phy_reg_mdic(hw, offset, data); + +release: +	hw->phy.ops.release(hw); +	return ret_val; +} + +/** + *  igb_read_phy_reg_gs40g - Read GS40G  PHY register + *  @hw: pointer to the HW structure + *  @offset: lower half is register offset to read to + *     upper half is page to use. + *  @data: data to read at register offset + * + *  Acquires semaphore, if necessary, then reads the data in the PHY register + *  at the offset.  Release any acquired semaphores before exiting. + **/ +s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data) +{ +	s32 ret_val; +	u16 page = offset >> GS40G_PAGE_SHIFT; + +	offset = offset & GS40G_OFFSET_MASK; +	ret_val = hw->phy.ops.acquire(hw); +	if (ret_val) +		return ret_val; + +	ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page); +	if (ret_val) +		goto release; +	ret_val = igb_read_phy_reg_mdic(hw, offset, data); + +release: +	hw->phy.ops.release(hw); +	return ret_val; +} + +/** + *  igb_set_master_slave_mode - Setup PHY for Master/slave mode + *  @hw: pointer to the HW structure + * + *  Sets up Master/slave mode + **/ +static s32 igb_set_master_slave_mode(struct e1000_hw *hw) +{ +	s32 ret_val; +	u16 phy_data; + +	/* Resolve Master/Slave mode */ +	ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data); +	if (ret_val) +		return ret_val; + +	/* load defaults for future use */ +	hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ? +				   ((phy_data & CR_1000T_MS_VALUE) ? +				    e1000_ms_force_master : +				    e1000_ms_force_slave) : e1000_ms_auto; + +	switch (hw->phy.ms_type) { +	case e1000_ms_force_master: +		phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); +		break; +	case e1000_ms_force_slave: +		phy_data |= CR_1000T_MS_ENABLE; +		phy_data &= ~(CR_1000T_MS_VALUE); +		break; +	case e1000_ms_auto: +		phy_data &= ~CR_1000T_MS_ENABLE; +		/* fall-through */ +	default: +		break; +	} + +	return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data); +} diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h index 4c32ac66ff3..34e40619f16 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.h +++ b/drivers/net/ethernet/intel/igb/e1000_phy.h @@ -73,6 +73,9 @@ s32  igb_copper_link_setup_82580(struct e1000_hw *hw);  s32  igb_get_phy_info_82580(struct e1000_hw *hw);  s32  igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);  s32  igb_get_cable_length_82580(struct e1000_hw *hw); +s32  igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data); +s32  igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data); +s32  igb_check_polarity_m88(struct e1000_hw *hw);  /* IGP01E1000 Specific Registers */  #define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */ @@ -114,6 +117,13 @@ s32  igb_get_cable_length_82580(struct e1000_hw *hw);  /* I82580 PHY Diagnostics Status */  #define I82580_DSTATUS_CABLE_LENGTH       0x03FC  #define I82580_DSTATUS_CABLE_LENGTH_SHIFT 2 + +/* 82580 PHY Power Management */ +#define E1000_82580_PHY_POWER_MGMT	0xE14 +#define E1000_82580_PM_SPD		0x0001 /* Smart Power Down */ +#define E1000_82580_PM_D0_LPLU		0x0002 /* For D0a states */ +#define E1000_82580_PM_D3_LPLU		0x0004 /* For all other states */ +  /* Enable flexible speed on link-up */  #define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */  #define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */ @@ -133,4 +143,16 @@ s32  igb_get_cable_length_82580(struct e1000_hw *hw);  #define E1000_CABLE_LENGTH_UNDEFINED      0xFF +/* GS40G - I210 PHY defines */ +#define GS40G_PAGE_SELECT		0x16 +#define GS40G_PAGE_SHIFT		16 +#define GS40G_OFFSET_MASK		0xFFFF +#define GS40G_PAGE_2			0x20000 +#define GS40G_MAC_REG2			0x15 +#define GS40G_MAC_LB			0x4140 +#define GS40G_MAC_SPEED_1G		0X0006 +#define GS40G_COPPER_SPEC		0x0010 +#define GS40G_CS_POWER_DOWN		0x0002 +#define GS40G_LINE_LB			0x4000 +  #endif diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index ccdf36d503f..35d1e4f2c92 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -352,4 +352,18 @@  #define E1000_O2BGPTC   0x08FE4 /* OS2BMC packets received by BMC */  #define E1000_O2BSPC    0x0415C /* OS2BMC packets transmitted by host */ +#define E1000_SRWR		0x12018  /* Shadow Ram Write Register - RW */ +#define E1000_I210_FLMNGCTL	0x12038 +#define E1000_I210_FLMNGDATA	0x1203C +#define E1000_I210_FLMNGCNT	0x12040 + +#define E1000_I210_FLSWCTL	0x12048 +#define E1000_I210_FLSWDATA	0x1204C +#define E1000_I210_FLSWCNT	0x12050 + +#define E1000_I210_FLA		0x1201C + +#define E1000_INVM_DATA_REG(_n)	(0x12120 + 4*(_n)) +#define E1000_INVM_SIZE		64 /* Number of INVM Data Registers */ +  #endif diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 8e33bdd33ee..ae6d3f393a5 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -35,8 +35,8 @@  #include "e1000_82575.h"  #include <linux/clocksource.h> -#include <linux/timecompare.h>  #include <linux/net_tstamp.h> +#include <linux/ptp_clock_kernel.h>  #include <linux/bitops.h>  #include <linux/if_vlan.h> @@ -65,10 +65,13 @@ struct igb_adapter;  #define MAX_Q_VECTORS                      8  /* Transmit and receive queues */ -#define IGB_MAX_RX_QUEUES                  (adapter->vfs_allocated_count ? 2 : \ -                                           (hw->mac.type > e1000_82575 ? 8 : 4)) +#define IGB_MAX_RX_QUEUES		((adapter->vfs_allocated_count ? 2 : \ +					(hw->mac.type > e1000_82575 ? 8 : 4))) +#define IGB_MAX_RX_QUEUES_I210             4 +#define IGB_MAX_RX_QUEUES_I211             2  #define IGB_MAX_TX_QUEUES                  16 - +#define IGB_MAX_TX_QUEUES_I210             4 +#define IGB_MAX_TX_QUEUES_I211             2  #define IGB_MAX_VF_MC_ENTRIES              30  #define IGB_MAX_VF_FUNCTIONS               8  #define IGB_MAX_VFTA_ENTRIES               128 @@ -328,9 +331,6 @@ struct igb_adapter {  	/* OS defined structs */  	struct pci_dev *pdev; -	struct cyclecounter cycles; -	struct timecounter clock; -	struct timecompare compare;  	struct hwtstamp_config hwtstamp_config;  	spinlock_t stats64_lock; @@ -364,6 +364,13 @@ struct igb_adapter {  	u32 wvbr;  	int node;  	u32 *shadow_vfta; + +	struct ptp_clock *ptp_clock; +	struct ptp_clock_info caps; +	struct delayed_work overflow_work; +	spinlock_t tmreg_lock; +	struct cyclecounter cc; +	struct timecounter tc;  };  #define IGB_FLAG_HAS_MSI           (1 << 0) @@ -378,7 +385,6 @@ struct igb_adapter {  #define IGB_DMCTLX_DCFLUSH_DIS     0x80000000  /* Disable DMA Coal Flush */  #define IGB_82576_TSYNC_SHIFT 19 -#define IGB_82580_TSYNC_SHIFT 24  #define IGB_TS_HDR_LEN        16  enum e1000_state_t {  	__IGB_TESTING, @@ -414,7 +420,15 @@ extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *);  extern bool igb_has_link(struct igb_adapter *adapter);  extern void igb_set_ethtool_ops(struct net_device *);  extern void igb_power_up_link(struct igb_adapter *); +#ifdef CONFIG_IGB_PTP +extern void igb_ptp_init(struct igb_adapter *adapter); +extern void igb_ptp_remove(struct igb_adapter *adapter); +extern void igb_systim_to_hwtstamp(struct igb_adapter *adapter, +				   struct skb_shared_hwtstamps *hwtstamps, +				   u64 systim); + +#endif  static inline s32 igb_reset_phy(struct e1000_hw *hw)  {  	if (hw->phy.ops.reset) diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index e10821a0f24..812d4f963bd 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -335,7 +335,7 @@ static void igb_set_msglevel(struct net_device *netdev, u32 data)  static int igb_get_regs_len(struct net_device *netdev)  { -#define IGB_REGS_LEN 551 +#define IGB_REGS_LEN 739  	return IGB_REGS_LEN * sizeof(u32);  } @@ -552,10 +552,49 @@ static void igb_get_regs(struct net_device *netdev,  	regs_buff[548] = rd32(E1000_TDFT);  	regs_buff[549] = rd32(E1000_TDFHS);  	regs_buff[550] = rd32(E1000_TDFPC); -	regs_buff[551] = adapter->stats.o2bgptc; -	regs_buff[552] = adapter->stats.b2ospc; -	regs_buff[553] = adapter->stats.o2bspc; -	regs_buff[554] = adapter->stats.b2ogprc; + +	if (hw->mac.type > e1000_82580) { +		regs_buff[551] = adapter->stats.o2bgptc; +		regs_buff[552] = adapter->stats.b2ospc; +		regs_buff[553] = adapter->stats.o2bspc; +		regs_buff[554] = adapter->stats.b2ogprc; +	} + +	if (hw->mac.type != e1000_82576) +		return; +	for (i = 0; i < 12; i++) +		regs_buff[555 + i] = rd32(E1000_SRRCTL(i + 4)); +	for (i = 0; i < 4; i++) +		regs_buff[567 + i] = rd32(E1000_PSRTYPE(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[571 + i] = rd32(E1000_RDBAL(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[583 + i] = rd32(E1000_RDBAH(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[595 + i] = rd32(E1000_RDLEN(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[607 + i] = rd32(E1000_RDH(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[619 + i] = rd32(E1000_RDT(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[631 + i] = rd32(E1000_RXDCTL(i + 4)); + +	for (i = 0; i < 12; i++) +		regs_buff[643 + i] = rd32(E1000_TDBAL(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[655 + i] = rd32(E1000_TDBAH(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[667 + i] = rd32(E1000_TDLEN(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[679 + i] = rd32(E1000_TDH(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[691 + i] = rd32(E1000_TDT(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[703 + i] = rd32(E1000_TXDCTL(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[715 + i] = rd32(E1000_TDWBAL(i + 4)); +	for (i = 0; i < 12; i++) +		regs_buff[727 + i] = rd32(E1000_TDWBAH(i + 4));  }  static int igb_get_eeprom_len(struct net_device *netdev) @@ -624,6 +663,9 @@ static int igb_set_eeprom(struct net_device *netdev,  	if (eeprom->len == 0)  		return -EOPNOTSUPP; +	if (hw->mac.type == e1000_i211) +		return -EOPNOTSUPP; +  	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))  		return -EFAULT; @@ -851,6 +893,36 @@ struct igb_reg_test {  #define TABLE64_TEST_LO	5  #define TABLE64_TEST_HI	6 +/* i210 reg test */ +static struct igb_reg_test reg_test_i210[] = { +	{ E1000_FCAL,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, +	{ E1000_FCAH,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, +	{ E1000_FCT,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, +	{ E1000_RDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, +	{ E1000_RDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, +	{ E1000_RDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, +	/* RDH is read-only for i210, only test RDT. */ +	{ E1000_RDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, +	{ E1000_FCRTH,	   0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, +	{ E1000_FCTTV,	   0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, +	{ E1000_TIPG,	   0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, +	{ E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, +	{ E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, +	{ E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, +	{ E1000_TDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, +	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, +	{ E1000_RA,	   0, 16, TABLE64_TEST_LO, +						0xFFFFFFFF, 0xFFFFFFFF }, +	{ E1000_RA,	   0, 16, TABLE64_TEST_HI, +						0x900FFFFF, 0xFFFFFFFF }, +	{ E1000_MTA,	   0, 128, TABLE32_TEST, +						0xFFFFFFFF, 0xFFFFFFFF }, +	{ 0, 0, 0, 0, 0 } +}; +  /* i350 reg test */  static struct igb_reg_test reg_test_i350[] = {  	{ E1000_FCAL,	   0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, @@ -1073,6 +1145,11 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)  		test = reg_test_i350;  		toggle = 0x7FEFF3FF;  		break; +	case e1000_i210: +	case e1000_i211: +		test = reg_test_i210; +		toggle = 0x7FEFF3FF; +		break;  	case e1000_82580:  		test = reg_test_82580;  		toggle = 0x7FEFF3FF; @@ -1154,23 +1231,13 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)  static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data)  { -	u16 temp; -	u16 checksum = 0; -	u16 i; -  	*data = 0; -	/* Read and add up the contents of the EEPROM */ -	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { -		if ((adapter->hw.nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) { -			*data = 1; -			break; -		} -		checksum += temp; -	} -	/* If Checksum is not Correct return error else test passed */ -	if ((checksum != (u16) NVM_SUM) && !(*data)) -		*data = 2; +	/* Validate eeprom on all parts but i211 */ +	if (adapter->hw.mac.type != e1000_i211) { +		if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0) +			*data = 2; +	}  	return *data;  } @@ -1236,6 +1303,8 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  		ics_mask = 0x77DCFED5;  		break;  	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  		ics_mask = 0x77DCFED5;  		break;  	default: @@ -1402,23 +1471,35 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)  {  	struct e1000_hw *hw = &adapter->hw;  	u32 ctrl_reg = 0; +	u16 phy_reg = 0;  	hw->mac.autoneg = false; -	if (hw->phy.type == e1000_phy_m88) { +	switch (hw->phy.type) { +	case e1000_phy_m88:  		/* Auto-MDI/MDIX Off */  		igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);  		/* reset to update Auto-MDI/MDIX */  		igb_write_phy_reg(hw, PHY_CONTROL, 0x9140);  		/* autoneg off */  		igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); -	} else if (hw->phy.type == e1000_phy_82580) { +		break; +	case e1000_phy_82580:  		/* enable MII loopback */  		igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041); +		break; +	case e1000_phy_i210: +		/* set loopback speed in PHY */ +		igb_read_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), +					&phy_reg); +		phy_reg |= GS40G_MAC_SPEED_1G; +		igb_write_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), +					phy_reg); +		ctrl_reg = rd32(E1000_CTRL_EXT); +	default: +		break;  	} -	ctrl_reg = rd32(E1000_CTRL); -  	/* force 1000, set loopback */  	igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); @@ -1431,7 +1512,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)  		     E1000_CTRL_FD |	 /* Force Duplex to FULL */  		     E1000_CTRL_SLU);	 /* Set link up enable bit */ -	if (hw->phy.type == e1000_phy_m88) +	if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210))  		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */  	wr32(E1000_CTRL, ctrl_reg); @@ -1439,7 +1520,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)  	/* Disable the receiver on the PHY so when a cable is plugged in, the  	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.  	 */ -	if (hw->phy.type == e1000_phy_m88) +	if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210))  		igb_phy_disable_receiver(adapter);  	udelay(500); @@ -1704,6 +1785,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)  		*data = 0;  		goto out;  	} +	if ((adapter->hw.mac.type == e1000_i210) +		|| (adapter->hw.mac.type == e1000_i210)) { +		dev_err(&adapter->pdev->dev, +			"Loopback test not supported " +			"on this part at this time.\n"); +		*data = 0; +		goto out; +	}  	*data = igb_setup_desc_rings(adapter);  	if (*data)  		goto out; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 5ec31598ee4..dd3bfe8cd36 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -60,8 +60,8 @@  #include "igb.h"  #define MAJ 3 -#define MIN 2 -#define BUILD 10 +#define MIN 4 +#define BUILD 7  #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \  __stringify(BUILD) "-k"  char igb_driver_name[] = "igb"; @@ -75,6 +75,11 @@ static const struct e1000_info *igb_info_tbl[] = {  };  static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { +	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 }, +	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 }, +	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 }, +	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 }, +	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 },  	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 }, @@ -114,7 +119,6 @@ static void igb_free_all_rx_resources(struct igb_adapter *);  static void igb_setup_mrqc(struct igb_adapter *);  static int igb_probe(struct pci_dev *, const struct pci_device_id *);  static void __devexit igb_remove(struct pci_dev *pdev); -static void igb_init_hw_timer(struct igb_adapter *adapter);  static int igb_sw_init(struct igb_adapter *);  static int igb_open(struct net_device *);  static int igb_close(struct net_device *); @@ -565,33 +569,6 @@ exit:  	return;  } - -/** - * igb_read_clock - read raw cycle counter (to be used by time counter) - */ -static cycle_t igb_read_clock(const struct cyclecounter *tc) -{ -	struct igb_adapter *adapter = -		container_of(tc, struct igb_adapter, cycles); -	struct e1000_hw *hw = &adapter->hw; -	u64 stamp = 0; -	int shift = 0; - -	/* -	 * The timestamp latches on lowest register read. For the 82580 -	 * the lowest register is SYSTIMR instead of SYSTIML.  However we never -	 * adjusted TIMINCA so SYSTIMR will just read as all 0s so ignore it. -	 */ -	if (hw->mac.type >= e1000_82580) { -		stamp = rd32(E1000_SYSTIMR) >> 8; -		shift = IGB_82580_TSYNC_SHIFT; -	} - -	stamp |= (u64)rd32(E1000_SYSTIML) << shift; -	stamp |= (u64)rd32(E1000_SYSTIMH) << (shift + 32); -	return stamp; -} -  /**   * igb_get_hw_dev - return device   * used by hardware layer to print debugging information @@ -669,6 +646,8 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)  	case e1000_82575:  	case e1000_82580:  	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  	default:  		for (; i < adapter->num_rx_queues; i++)  			adapter->rx_ring[i]->reg_idx = rbase_offset + i; @@ -755,8 +734,11 @@ static int igb_alloc_queues(struct igb_adapter *adapter)  		if (adapter->hw.mac.type >= e1000_82576)  			set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags); -		/* On i350, loopback VLAN packets have the tag byte-swapped. */ -		if (adapter->hw.mac.type == e1000_i350) +		/* +		 * On i350, i210, and i211, loopback VLAN packets +		 * have the tag byte-swapped. +		 * */ +		if (adapter->hw.mac.type >= e1000_i350)  			set_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags);  		adapter->rx_ring[i] = ring; @@ -850,6 +832,8 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)  		break;  	case e1000_82580:  	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  		/*  		 * On 82580 and newer adapters the scheme is similar to 82576  		 * however instead of ordering column-major we have things @@ -916,6 +900,8 @@ static void igb_configure_msix(struct igb_adapter *adapter)  	case e1000_82576:  	case e1000_82580:  	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  		/* Turn on MSI-X capability first, or our settings  		 * won't stick.  And it will take days to debug. */  		wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE | @@ -1062,6 +1048,11 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter)  	if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))  		numvecs += adapter->num_tx_queues; +	/* i210 and i211 can only have 4 MSIX vectors for rx/tx queues. */ +	if ((adapter->hw.mac.type == e1000_i210) +		|| (adapter->hw.mac.type == e1000_i211)) +		numvecs = 4; +  	/* store the number of vectors reserved for queues */  	adapter->num_q_vectors = numvecs; @@ -1069,6 +1060,7 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter)  	numvecs++;  	adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),  					GFP_KERNEL); +  	if (!adapter->msix_entries)  		goto msi_only; @@ -1111,9 +1103,12 @@ msi_only:  		adapter->flags |= IGB_FLAG_HAS_MSI;  out:  	/* Notify the stack of the (possibly) reduced queue counts. */ +	rtnl_lock();  	netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues); -	return netif_set_real_num_rx_queues(adapter->netdev, -					    adapter->num_rx_queues); +	err = netif_set_real_num_rx_queues(adapter->netdev, +		adapter->num_rx_queues); +	rtnl_unlock(); +	return err;  }  /** @@ -1659,6 +1654,8 @@ void igb_reset(struct igb_adapter *adapter)  		pba &= E1000_RXPBS_SIZE_MASK_82576;  		break;  	case e1000_82575: +	case e1000_i210: +	case e1000_i211:  	default:  		pba = E1000_PBA_34K;  		break; @@ -1743,6 +1740,13 @@ void igb_reset(struct igb_adapter *adapter)  	if (hw->mac.ops.init_hw(hw))  		dev_err(&pdev->dev, "Hardware Error\n"); +	/* +	 * Flow control settings reset on hardware reset, so guarantee flow +	 * control is off when forcing speed. +	 */ +	if (!hw->mac.autoneg) +		igb_force_mac_fc(hw); +  	igb_init_dmac(adapter, pba);  	if (!netif_running(adapter->netdev))  		igb_power_down_link(adapter); @@ -1847,7 +1851,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,  	 */  	if (pdev->is_virtfn) {  		WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n", -		     pci_name(pdev), pdev->vendor, pdev->device); +			pci_name(pdev), pdev->vendor, pdev->device);  		return -EINVAL;  	} @@ -2001,11 +2005,16 @@ static int __devinit igb_probe(struct pci_dev *pdev,  	 * known good starting state */  	hw->mac.ops.reset_hw(hw); -	/* make sure the NVM is good */ -	if (hw->nvm.ops.validate(hw) < 0) { -		dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); -		err = -EIO; -		goto err_eeprom; +	/* +	 * make sure the NVM is good , i211 parts have special NVM that +	 * doesn't contain a checksum +	 */ +	if (hw->mac.type != e1000_i211) { +		if (hw->nvm.ops.validate(hw) < 0) { +			dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); +			err = -EIO; +			goto err_eeprom; +		}  	}  	/* copy the MAC address out of the NVM */ @@ -2110,9 +2119,11 @@ static int __devinit igb_probe(struct pci_dev *pdev,  	}  #endif +#ifdef CONFIG_IGB_PTP  	/* do hw tstamp init after resetting */ -	igb_init_hw_timer(adapter); +	igb_ptp_init(adapter); +#endif  	dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");  	/* print bus type/speed/width info */  	dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n", @@ -2137,6 +2148,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,  		adapter->num_rx_queues, adapter->num_tx_queues);  	switch (hw->mac.type) {  	case e1000_i350: +	case e1000_i210: +	case e1000_i211:  		igb_set_eee_i350(hw);  		break;  	default: @@ -2184,7 +2197,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)  	struct e1000_hw *hw = &adapter->hw;  	pm_runtime_get_noresume(&pdev->dev); +#ifdef CONFIG_IGB_PTP +	igb_ptp_remove(adapter); +#endif  	/*  	 * The watchdog timer may be rescheduled, so explicitly  	 * disable watchdog from being rescheduled. @@ -2260,9 +2276,14 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)  {  #ifdef CONFIG_PCI_IOV  	struct pci_dev *pdev = adapter->pdev; +	struct e1000_hw *hw = &adapter->hw;  	int old_vfs = igb_find_enabled_vfs(adapter);  	int i; +	/* Virtualization features not supported on i210 family. */ +	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) +		return; +  	if (old_vfs) {  		dev_info(&pdev->dev, "%d pre-allocated VFs found - override "  			 "max_vfs setting of %d\n", old_vfs, max_vfs); @@ -2274,6 +2295,7 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)  	adapter->vf_data = kcalloc(adapter->vfs_allocated_count,  				sizeof(struct vf_data_storage), GFP_KERNEL); +  	/* if allocation failed then we do not support SR-IOV */  	if (!adapter->vf_data) {  		adapter->vfs_allocated_count = 0; @@ -2304,112 +2326,6 @@ out:  }  /** - * igb_init_hw_timer - Initialize hardware timer used with IEEE 1588 timestamp - * @adapter: board private structure to initialize - * - * igb_init_hw_timer initializes the function pointer and values for the hw - * timer found in hardware. - **/ -static void igb_init_hw_timer(struct igb_adapter *adapter) -{ -	struct e1000_hw *hw = &adapter->hw; - -	switch (hw->mac.type) { -	case e1000_i350: -	case e1000_82580: -		memset(&adapter->cycles, 0, sizeof(adapter->cycles)); -		adapter->cycles.read = igb_read_clock; -		adapter->cycles.mask = CLOCKSOURCE_MASK(64); -		adapter->cycles.mult = 1; -		/* -		 * The 82580 timesync updates the system timer every 8ns by 8ns -		 * and the value cannot be shifted.  Instead we need to shift -		 * the registers to generate a 64bit timer value.  As a result -		 * SYSTIMR/L/H, TXSTMPL/H, RXSTMPL/H all have to be shifted by -		 * 24 in order to generate a larger value for synchronization. -		 */ -		adapter->cycles.shift = IGB_82580_TSYNC_SHIFT; -		/* disable system timer temporarily by setting bit 31 */ -		wr32(E1000_TSAUXC, 0x80000000); -		wrfl(); - -		/* Set registers so that rollover occurs soon to test this. */ -		wr32(E1000_SYSTIMR, 0x00000000); -		wr32(E1000_SYSTIML, 0x80000000); -		wr32(E1000_SYSTIMH, 0x000000FF); -		wrfl(); - -		/* enable system timer by clearing bit 31 */ -		wr32(E1000_TSAUXC, 0x0); -		wrfl(); - -		timecounter_init(&adapter->clock, -				 &adapter->cycles, -				 ktime_to_ns(ktime_get_real())); -		/* -		 * Synchronize our NIC clock against system wall clock. NIC -		 * time stamp reading requires ~3us per sample, each sample -		 * was pretty stable even under load => only require 10 -		 * samples for each offset comparison. -		 */ -		memset(&adapter->compare, 0, sizeof(adapter->compare)); -		adapter->compare.source = &adapter->clock; -		adapter->compare.target = ktime_get_real; -		adapter->compare.num_samples = 10; -		timecompare_update(&adapter->compare, 0); -		break; -	case e1000_82576: -		/* -		 * Initialize hardware timer: we keep it running just in case -		 * that some program needs it later on. -		 */ -		memset(&adapter->cycles, 0, sizeof(adapter->cycles)); -		adapter->cycles.read = igb_read_clock; -		adapter->cycles.mask = CLOCKSOURCE_MASK(64); -		adapter->cycles.mult = 1; -		/** -		 * Scale the NIC clock cycle by a large factor so that -		 * relatively small clock corrections can be added or -		 * subtracted at each clock tick. The drawbacks of a large -		 * factor are a) that the clock register overflows more quickly -		 * (not such a big deal) and b) that the increment per tick has -		 * to fit into 24 bits.  As a result we need to use a shift of -		 * 19 so we can fit a value of 16 into the TIMINCA register. -		 */ -		adapter->cycles.shift = IGB_82576_TSYNC_SHIFT; -		wr32(E1000_TIMINCA, -		                (1 << E1000_TIMINCA_16NS_SHIFT) | -		                (16 << IGB_82576_TSYNC_SHIFT)); - -		/* Set registers so that rollover occurs soon to test this. */ -		wr32(E1000_SYSTIML, 0x00000000); -		wr32(E1000_SYSTIMH, 0xFF800000); -		wrfl(); - -		timecounter_init(&adapter->clock, -				 &adapter->cycles, -				 ktime_to_ns(ktime_get_real())); -		/* -		 * Synchronize our NIC clock against system wall clock. NIC -		 * time stamp reading requires ~3us per sample, each sample -		 * was pretty stable even under load => only require 10 -		 * samples for each offset comparison. -		 */ -		memset(&adapter->compare, 0, sizeof(adapter->compare)); -		adapter->compare.source = &adapter->clock; -		adapter->compare.target = ktime_get_real; -		adapter->compare.num_samples = 10; -		timecompare_update(&adapter->compare, 0); -		break; -	case e1000_82575: -		/* 82575 does not support timesync */ -	default: -		break; -	} - -} - -/**   * igb_sw_init - Initialize general software structures (struct igb_adapter)   * @adapter: board private structure to initialize   * @@ -2454,11 +2370,28 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)  		} else  			adapter->vfs_allocated_count = max_vfs;  		break; +	case e1000_i210: +	case e1000_i211: +		adapter->vfs_allocated_count = 0; +		break;  	default:  		break;  	}  #endif /* CONFIG_PCI_IOV */ -	adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus()); +	switch (hw->mac.type) { +	case e1000_i210: +		adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I210, +			num_online_cpus()); +		break; +	case e1000_i211: +		adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I211, +			num_online_cpus()); +		break; +	default: +		adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, +		num_online_cpus()); +		break; +	}  	/* i350 cannot do RSS and SR-IOV at the same time */  	if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count)  		adapter->rss_queues = 1; @@ -2488,7 +2421,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)  	/* Explicitly disable IRQ since the NIC can be in any state. */  	igb_irq_disable(adapter); -	if (hw->mac.type == e1000_i350) +	if (hw->mac.type >= e1000_i350)  		adapter->flags &= ~IGB_FLAG_DMAC;  	set_bit(__IGB_DOWN, &adapter->state); @@ -2771,8 +2704,6 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,  	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;  	wr32(E1000_TXDCTL(reg_idx), txdctl); - -	netdev_tx_reset_queue(txring_txq(ring));  }  /** @@ -2943,6 +2874,17 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)  	/* Don't need to set TUOFL or IPOFL, they default to 1 */  	wr32(E1000_RXCSUM, rxcsum); +	/* +	 * Generate RSS hash based on TCP port numbers and/or +	 * IPv4/v6 src and dst addresses since UDP cannot be +	 * hashed reliably due to IP fragmentation +	 */ + +	mrqc = E1000_MRQC_RSS_FIELD_IPV4 | +	       E1000_MRQC_RSS_FIELD_IPV4_TCP | +	       E1000_MRQC_RSS_FIELD_IPV6 | +	       E1000_MRQC_RSS_FIELD_IPV6_TCP | +	       E1000_MRQC_RSS_FIELD_IPV6_TCP_EX;  	/* If VMDq is enabled then we set the appropriate mode for that, else  	 * we default to RSS so that an RSS hash is calculated per packet even @@ -2958,25 +2900,15 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)  			wr32(E1000_VT_CTL, vtctl);  		}  		if (adapter->rss_queues > 1) -			mrqc = E1000_MRQC_ENABLE_VMDQ_RSS_2Q; +			mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_2Q;  		else -			mrqc = E1000_MRQC_ENABLE_VMDQ; +			mrqc |= E1000_MRQC_ENABLE_VMDQ;  	} else { -		mrqc = E1000_MRQC_ENABLE_RSS_4Q; +		if (hw->mac.type != e1000_i211) +			mrqc |= E1000_MRQC_ENABLE_RSS_4Q;  	}  	igb_vmm_control(adapter); -	/* -	 * Generate RSS hash based on TCP port numbers and/or -	 * IPv4/v6 src and dst addresses since UDP cannot be -	 * hashed reliably due to IP fragmentation -	 */ -	mrqc |= E1000_MRQC_RSS_FIELD_IPV4 | -		E1000_MRQC_RSS_FIELD_IPV4_TCP | -		E1000_MRQC_RSS_FIELD_IPV6 | -		E1000_MRQC_RSS_FIELD_IPV6_TCP | -		E1000_MRQC_RSS_FIELD_IPV6_TCP_EX; -  	wr32(E1000_MRQC, mrqc);  } @@ -3282,6 +3214,8 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring)  		igb_unmap_and_free_tx_resource(tx_ring, buffer_info);  	} +	netdev_tx_reset_queue(txring_txq(tx_ring)); +  	size = sizeof(struct igb_tx_buffer) * tx_ring->count;  	memset(tx_ring->tx_buffer_info, 0, size); @@ -3576,7 +3510,7 @@ static void igb_set_rx_mode(struct net_device *netdev)  	 * we will have issues with VLAN tag stripping not being done for frames  	 * that are only arriving because we are the default pool  	 */ -	if (hw->mac.type < e1000_82576) +	if ((hw->mac.type < e1000_82576) || (hw->mac.type > e1000_i350))  		return;  	vmolr |= rd32(E1000_VMOLR(vfn)) & @@ -3673,7 +3607,7 @@ static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event)  	bool ret = false;  	u32 ctrl_ext, thstat; -	/* check for thermal sensor event on i350, copper only */ +	/* check for thermal sensor event on i350 copper only */  	if (hw->mac.type == e1000_i350) {  		thstat = rd32(E1000_THSTAT);  		ctrl_ext = rd32(E1000_CTRL_EXT); @@ -5718,35 +5652,7 @@ static int igb_poll(struct napi_struct *napi, int budget)  	return 0;  } -/** - * igb_systim_to_hwtstamp - convert system time value to hw timestamp - * @adapter: board private structure - * @shhwtstamps: timestamp structure to update - * @regval: unsigned 64bit system time value. - * - * We need to convert the system time value stored in the RX/TXSTMP registers - * into a hwtstamp which can be used by the upper level timestamping functions - */ -static void igb_systim_to_hwtstamp(struct igb_adapter *adapter, -                                   struct skb_shared_hwtstamps *shhwtstamps, -                                   u64 regval) -{ -	u64 ns; - -	/* -	 * The 82580 starts with 1ns at bit 0 in RX/TXSTMPL, shift this up to -	 * 24 to match clock shift we setup earlier. -	 */ -	if (adapter->hw.mac.type >= e1000_82580) -		regval <<= IGB_82580_TSYNC_SHIFT; - -	ns = timecounter_cyc2time(&adapter->clock, regval); -	timecompare_update(&adapter->compare, ns); -	memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); -	shhwtstamps->hwtstamp = ns_to_ktime(ns); -	shhwtstamps->syststamp = timecompare_transform(&adapter->compare, ns); -} - +#ifdef CONFIG_IGB_PTP  /**   * igb_tx_hwtstamp - utility function which checks for TX time stamp   * @q_vector: pointer to q_vector containing needed info @@ -5776,6 +5682,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector,  	skb_tstamp_tx(buffer_info->skb, &shhwtstamps);  } +#endif  /**   * igb_clean_tx_irq - Reclaim resources after transmit completes   * @q_vector: pointer to q_vector containing needed info @@ -5819,9 +5726,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)  		total_bytes += tx_buffer->bytecount;  		total_packets += tx_buffer->gso_segs; +#ifdef CONFIG_IGB_PTP  		/* retrieve hardware timestamp */  		igb_tx_hwtstamp(q_vector, tx_buffer); +#endif  		/* free the skb */  		dev_kfree_skb_any(tx_buffer->skb);  		tx_buffer->skb = NULL; @@ -5993,6 +5902,7 @@ static inline void igb_rx_hash(struct igb_ring *ring,  		skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);  } +#ifdef CONFIG_IGB_PTP  static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,  			    union e1000_adv_rx_desc *rx_desc,  			    struct sk_buff *skb) @@ -6032,6 +5942,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,  	igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);  } +#endif  static void igb_rx_vlan(struct igb_ring *ring,  			union e1000_adv_rx_desc *rx_desc,  			struct sk_buff *skb) @@ -6142,7 +6053,9 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)  			goto next_desc;  		} +#ifdef CONFIG_IGB_PTP  		igb_rx_hwtstamp(q_vector, rx_desc, skb); +#endif  		igb_rx_hash(rx_ring, rx_desc, skb);  		igb_rx_checksum(rx_ring, rx_desc, skb);  		igb_rx_vlan(rx_ring, rx_desc, skb); @@ -6796,18 +6709,7 @@ static int igb_resume(struct device *dev)  	pci_enable_wake(pdev, PCI_D3hot, 0);  	pci_enable_wake(pdev, PCI_D3cold, 0); -	if (!rtnl_is_locked()) { -		/* -		 * shut up ASSERT_RTNL() warning in -		 * netif_set_real_num_tx/rx_queues. -		 */ -		rtnl_lock(); -		err = igb_init_interrupt_scheme(adapter); -		rtnl_unlock(); -	} else { -		err = igb_init_interrupt_scheme(adapter); -	} -	if (err) { +	if (igb_init_interrupt_scheme(adapter)) {  		dev_err(&pdev->dev, "Unable to allocate memory for queues\n");  		return -ENOMEM;  	} @@ -7170,6 +7072,8 @@ static void igb_vmm_control(struct igb_adapter *adapter)  	switch (hw->mac.type) {  	case e1000_82575: +	case e1000_i210: +	case e1000_i211:  	default:  		/* replication is not supported for 82575 */  		return; @@ -7243,6 +7147,9 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)  			/* watchdog timer= +-1000 usec in 32usec intervals */  			reg |= (1000 >> 5); + +			/* Disable BMC-to-OS Watchdog Enable */ +			reg &= ~E1000_DMACR_DC_BMC2OSW_EN;  			wr32(E1000_DMACR, reg);  			/* diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c new file mode 100644 index 00000000000..d5ee7fa5072 --- /dev/null +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -0,0 +1,385 @@ +/* + * PTP Hardware Clock (PHC) driver for the Intel 82576 and 82580 + * + * Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/module.h> +#include <linux/device.h> +#include <linux/pci.h> + +#include "igb.h" + +#define INCVALUE_MASK		0x7fffffff +#define ISGN			0x80000000 + +/* + * The 82580 timesync updates the system timer every 8ns by 8ns, + * and this update value cannot be reprogrammed. + * + * Neither the 82576 nor the 82580 offer registers wide enough to hold + * nanoseconds time values for very long. For the 82580, SYSTIM always + * counts nanoseconds, but the upper 24 bits are not availible. The + * frequency is adjusted by changing the 32 bit fractional nanoseconds + * register, TIMINCA. + * + * For the 82576, the SYSTIM register time unit is affect by the + * choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this + * field are needed to provide the nominal 16 nanosecond period, + * leaving 19 bits for fractional nanoseconds. + * + * We scale the NIC clock cycle by a large factor so that relatively + * small clock corrections can be added or subtracted at each clock + * tick. The drawbacks of a large factor are a) that the clock + * register overflows more quickly (not such a big deal) and b) that + * the increment per tick has to fit into 24 bits.  As a result we + * need to use a shift of 19 so we can fit a value of 16 into the + * TIMINCA register. + * + * + *             SYSTIMH            SYSTIML + *        +--------------+   +---+---+------+ + *  82576 |      32      |   | 8 | 5 |  19  | + *        +--------------+   +---+---+------+ + *         \________ 45 bits _______/  fract + * + *        +----------+---+   +--------------+ + *  82580 |    24    | 8 |   |      32      | + *        +----------+---+   +--------------+ + *          reserved  \______ 40 bits _____/ + * + * + * The 45 bit 82576 SYSTIM overflows every + *   2^45 * 10^-9 / 3600 = 9.77 hours. + * + * The 40 bit 82580 SYSTIM overflows every + *   2^40 * 10^-9 /  60  = 18.3 minutes. + */ + +#define IGB_OVERFLOW_PERIOD	(HZ * 60 * 9) +#define INCPERIOD_82576		(1 << E1000_TIMINCA_16NS_SHIFT) +#define INCVALUE_82576_MASK	((1 << E1000_TIMINCA_16NS_SHIFT) - 1) +#define INCVALUE_82576		(16 << IGB_82576_TSYNC_SHIFT) +#define IGB_NBITS_82580		40 + +/* + * SYSTIM read access for the 82576 + */ + +static cycle_t igb_82576_systim_read(const struct cyclecounter *cc) +{ +	u64 val; +	u32 lo, hi; +	struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); +	struct e1000_hw *hw = &igb->hw; + +	lo = rd32(E1000_SYSTIML); +	hi = rd32(E1000_SYSTIMH); + +	val = ((u64) hi) << 32; +	val |= lo; + +	return val; +} + +/* + * SYSTIM read access for the 82580 + */ + +static cycle_t igb_82580_systim_read(const struct cyclecounter *cc) +{ +	u64 val; +	u32 lo, hi, jk; +	struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); +	struct e1000_hw *hw = &igb->hw; + +	/* +	 * The timestamp latches on lowest register read. For the 82580 +	 * the lowest register is SYSTIMR instead of SYSTIML.  However we only +	 * need to provide nanosecond resolution, so we just ignore it. +	 */ +	jk = rd32(E1000_SYSTIMR); +	lo = rd32(E1000_SYSTIML); +	hi = rd32(E1000_SYSTIMH); + +	val = ((u64) hi) << 32; +	val |= lo; + +	return val; +} + +/* + * PTP clock operations + */ + +static int ptp_82576_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ +	u64 rate; +	u32 incvalue; +	int neg_adj = 0; +	struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); +	struct e1000_hw *hw = &igb->hw; + +	if (ppb < 0) { +		neg_adj = 1; +		ppb = -ppb; +	} +	rate = ppb; +	rate <<= 14; +	rate = div_u64(rate, 1953125); + +	incvalue = 16 << IGB_82576_TSYNC_SHIFT; + +	if (neg_adj) +		incvalue -= rate; +	else +		incvalue += rate; + +	wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK)); + +	return 0; +} + +static int ptp_82580_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ +	u64 rate; +	u32 inca; +	int neg_adj = 0; +	struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); +	struct e1000_hw *hw = &igb->hw; + +	if (ppb < 0) { +		neg_adj = 1; +		ppb = -ppb; +	} +	rate = ppb; +	rate <<= 26; +	rate = div_u64(rate, 1953125); + +	inca = rate & INCVALUE_MASK; +	if (neg_adj) +		inca |= ISGN; + +	wr32(E1000_TIMINCA, inca); + +	return 0; +} + +static int igb_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ +	s64 now; +	unsigned long flags; +	struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + +	spin_lock_irqsave(&igb->tmreg_lock, flags); + +	now = timecounter_read(&igb->tc); +	now += delta; +	timecounter_init(&igb->tc, &igb->cc, now); + +	spin_unlock_irqrestore(&igb->tmreg_lock, flags); + +	return 0; +} + +static int igb_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ +	u64 ns; +	u32 remainder; +	unsigned long flags; +	struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + +	spin_lock_irqsave(&igb->tmreg_lock, flags); + +	ns = timecounter_read(&igb->tc); + +	spin_unlock_irqrestore(&igb->tmreg_lock, flags); + +	ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); +	ts->tv_nsec = remainder; + +	return 0; +} + +static int igb_settime(struct ptp_clock_info *ptp, const struct timespec *ts) +{ +	u64 ns; +	unsigned long flags; +	struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + +	ns = ts->tv_sec * 1000000000ULL; +	ns += ts->tv_nsec; + +	spin_lock_irqsave(&igb->tmreg_lock, flags); + +	timecounter_init(&igb->tc, &igb->cc, ns); + +	spin_unlock_irqrestore(&igb->tmreg_lock, flags); + +	return 0; +} + +static int ptp_82576_enable(struct ptp_clock_info *ptp, +			    struct ptp_clock_request *rq, int on) +{ +	return -EOPNOTSUPP; +} + +static int ptp_82580_enable(struct ptp_clock_info *ptp, +			    struct ptp_clock_request *rq, int on) +{ +	return -EOPNOTSUPP; +} + +static void igb_overflow_check(struct work_struct *work) +{ +	struct timespec ts; +	struct igb_adapter *igb = +		container_of(work, struct igb_adapter, overflow_work.work); + +	igb_gettime(&igb->caps, &ts); + +	pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec); + +	schedule_delayed_work(&igb->overflow_work, IGB_OVERFLOW_PERIOD); +} + +void igb_ptp_init(struct igb_adapter *adapter) +{ +	struct e1000_hw *hw = &adapter->hw; + +	switch (hw->mac.type) { +	case e1000_i210: +	case e1000_i211: +	case e1000_i350: +	case e1000_82580: +		adapter->caps.owner	= THIS_MODULE; +		strcpy(adapter->caps.name, "igb-82580"); +		adapter->caps.max_adj	= 62499999; +		adapter->caps.n_ext_ts	= 0; +		adapter->caps.pps	= 0; +		adapter->caps.adjfreq	= ptp_82580_adjfreq; +		adapter->caps.adjtime	= igb_adjtime; +		adapter->caps.gettime	= igb_gettime; +		adapter->caps.settime	= igb_settime; +		adapter->caps.enable	= ptp_82580_enable; +		adapter->cc.read	= igb_82580_systim_read; +		adapter->cc.mask	= CLOCKSOURCE_MASK(IGB_NBITS_82580); +		adapter->cc.mult	= 1; +		adapter->cc.shift	= 0; +		/* Enable the timer functions by clearing bit 31. */ +		wr32(E1000_TSAUXC, 0x0); +		break; + +	case e1000_82576: +		adapter->caps.owner	= THIS_MODULE; +		strcpy(adapter->caps.name, "igb-82576"); +		adapter->caps.max_adj	= 1000000000; +		adapter->caps.n_ext_ts	= 0; +		adapter->caps.pps	= 0; +		adapter->caps.adjfreq	= ptp_82576_adjfreq; +		adapter->caps.adjtime	= igb_adjtime; +		adapter->caps.gettime	= igb_gettime; +		adapter->caps.settime	= igb_settime; +		adapter->caps.enable	= ptp_82576_enable; +		adapter->cc.read	= igb_82576_systim_read; +		adapter->cc.mask	= CLOCKSOURCE_MASK(64); +		adapter->cc.mult	= 1; +		adapter->cc.shift	= IGB_82576_TSYNC_SHIFT; +		/* Dial the nominal frequency. */ +		wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); +		break; + +	default: +		adapter->ptp_clock = NULL; +		return; +	} + +	wrfl(); + +	timecounter_init(&adapter->tc, &adapter->cc, +			 ktime_to_ns(ktime_get_real())); + +	INIT_DELAYED_WORK(&adapter->overflow_work, igb_overflow_check); + +	spin_lock_init(&adapter->tmreg_lock); + +	schedule_delayed_work(&adapter->overflow_work, IGB_OVERFLOW_PERIOD); + +	adapter->ptp_clock = ptp_clock_register(&adapter->caps); +	if (IS_ERR(adapter->ptp_clock)) { +		adapter->ptp_clock = NULL; +		dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); +	} else +		dev_info(&adapter->pdev->dev, "added PHC on %s\n", +			 adapter->netdev->name); +} + +void igb_ptp_remove(struct igb_adapter *adapter) +{ +	cancel_delayed_work_sync(&adapter->overflow_work); + +	if (adapter->ptp_clock) { +		ptp_clock_unregister(adapter->ptp_clock); +		dev_info(&adapter->pdev->dev, "removed PHC on %s\n", +			 adapter->netdev->name); +	} +} + +/** + * igb_systim_to_hwtstamp - convert system time value to hw timestamp + * @adapter: board private structure + * @hwtstamps: timestamp structure to update + * @systim: unsigned 64bit system time value. + * + * We need to convert the system time value stored in the RX/TXSTMP registers + * into a hwtstamp which can be used by the upper level timestamping functions. + * + * The 'tmreg_lock' spinlock is used to protect the consistency of the + * system time value. This is needed because reading the 64 bit time + * value involves reading two (or three) 32 bit registers. The first + * read latches the value. Ditto for writing. + * + * In addition, here have extended the system time with an overflow + * counter in software. + **/ +void igb_systim_to_hwtstamp(struct igb_adapter *adapter, +			    struct skb_shared_hwtstamps *hwtstamps, +			    u64 systim) +{ +	u64 ns; +	unsigned long flags; + +	switch (adapter->hw.mac.type) { +	case e1000_i210: +	case e1000_i211: +	case e1000_i350: +	case e1000_82580: +	case e1000_82576: +		break; +	default: +		return; +	} + +	spin_lock_irqsave(&adapter->tmreg_lock, flags); + +	ns = timecounter_cyc2time(&adapter->tc, systim); + +	spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + +	memset(hwtstamps, 0, sizeof(*hwtstamps)); +	hwtstamps->hwtstamp = ns_to_ktime(ns); +}  |