16a14ee0cSDon Skidmore /*******************************************************************************
26a14ee0cSDon Skidmore  *
36a14ee0cSDon Skidmore  *  Intel 10 Gigabit PCI Express Linux driver
46a14ee0cSDon Skidmore  *  Copyright(c) 1999 - 2014 Intel Corporation.
56a14ee0cSDon Skidmore  *
66a14ee0cSDon Skidmore  *  This program is free software; you can redistribute it and/or modify it
76a14ee0cSDon Skidmore  *  under the terms and conditions of the GNU General Public License,
86a14ee0cSDon Skidmore  *  version 2, as published by the Free Software Foundation.
96a14ee0cSDon Skidmore  *
106a14ee0cSDon Skidmore  *  This program is distributed in the hope it will be useful, but WITHOUT
116a14ee0cSDon Skidmore  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
126a14ee0cSDon Skidmore  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
136a14ee0cSDon Skidmore  *  more details.
146a14ee0cSDon Skidmore  *
156a14ee0cSDon Skidmore  *  The full GNU General Public License is included in this distribution in
166a14ee0cSDon Skidmore  *  the file called "COPYING".
176a14ee0cSDon Skidmore  *
186a14ee0cSDon Skidmore  *  Contact Information:
196a14ee0cSDon Skidmore  *  Linux NICS <linux.nics@intel.com>
206a14ee0cSDon Skidmore  *  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
216a14ee0cSDon Skidmore  *  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
226a14ee0cSDon Skidmore  *
236a14ee0cSDon Skidmore  ******************************************************************************/
246a14ee0cSDon Skidmore #include "ixgbe_x540.h"
256a14ee0cSDon Skidmore #include "ixgbe_type.h"
266a14ee0cSDon Skidmore #include "ixgbe_common.h"
276a14ee0cSDon Skidmore #include "ixgbe_phy.h"
286a14ee0cSDon Skidmore 
296a14ee0cSDon Skidmore /** ixgbe_identify_phy_x550em - Get PHY type based on device id
306a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
316a14ee0cSDon Skidmore  *
326a14ee0cSDon Skidmore  *  Returns error code
336a14ee0cSDon Skidmore  */
346a14ee0cSDon Skidmore static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
356a14ee0cSDon Skidmore {
366a14ee0cSDon Skidmore 	u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
376a14ee0cSDon Skidmore 
386a14ee0cSDon Skidmore 	switch (hw->device_id) {
396a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_SFP:
406a14ee0cSDon Skidmore 		/* set up for CS4227 usage */
416a14ee0cSDon Skidmore 		hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
426a14ee0cSDon Skidmore 		if (hw->bus.lan_id) {
436a14ee0cSDon Skidmore 			esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
446a14ee0cSDon Skidmore 			esdp |= IXGBE_ESDP_SDP1_DIR;
456a14ee0cSDon Skidmore 		}
466a14ee0cSDon Skidmore 		esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
476a14ee0cSDon Skidmore 		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
486a14ee0cSDon Skidmore 
496a14ee0cSDon Skidmore 		return ixgbe_identify_module_generic(hw);
506a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_KX4:
516a14ee0cSDon Skidmore 		hw->phy.type = ixgbe_phy_x550em_kx4;
526a14ee0cSDon Skidmore 		break;
536a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_KR:
546a14ee0cSDon Skidmore 		hw->phy.type = ixgbe_phy_x550em_kr;
556a14ee0cSDon Skidmore 		break;
566a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_1G_T:
576a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_10G_T:
586a14ee0cSDon Skidmore 		return ixgbe_identify_phy_generic(hw);
596a14ee0cSDon Skidmore 	default:
606a14ee0cSDon Skidmore 		break;
616a14ee0cSDon Skidmore 	}
626a14ee0cSDon Skidmore 	return 0;
636a14ee0cSDon Skidmore }
646a14ee0cSDon Skidmore 
656a14ee0cSDon Skidmore static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
666a14ee0cSDon Skidmore 				     u32 device_type, u16 *phy_data)
676a14ee0cSDon Skidmore {
686a14ee0cSDon Skidmore 	return IXGBE_NOT_IMPLEMENTED;
696a14ee0cSDon Skidmore }
706a14ee0cSDon Skidmore 
716a14ee0cSDon Skidmore static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
726a14ee0cSDon Skidmore 				      u32 device_type, u16 phy_data)
736a14ee0cSDon Skidmore {
746a14ee0cSDon Skidmore 	return IXGBE_NOT_IMPLEMENTED;
756a14ee0cSDon Skidmore }
766a14ee0cSDon Skidmore 
776a14ee0cSDon Skidmore /** ixgbe_init_eeprom_params_X550 - Initialize EEPROM params
786a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
796a14ee0cSDon Skidmore  *
806a14ee0cSDon Skidmore  *  Initializes the EEPROM parameters ixgbe_eeprom_info within the
816a14ee0cSDon Skidmore  *  ixgbe_hw struct in order to set up EEPROM access.
826a14ee0cSDon Skidmore  **/
836a14ee0cSDon Skidmore s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
846a14ee0cSDon Skidmore {
856a14ee0cSDon Skidmore 	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
866a14ee0cSDon Skidmore 	u32 eec;
876a14ee0cSDon Skidmore 	u16 eeprom_size;
886a14ee0cSDon Skidmore 
896a14ee0cSDon Skidmore 	if (eeprom->type == ixgbe_eeprom_uninitialized) {
906a14ee0cSDon Skidmore 		eeprom->semaphore_delay = 10;
916a14ee0cSDon Skidmore 		eeprom->type = ixgbe_flash;
926a14ee0cSDon Skidmore 
936a14ee0cSDon Skidmore 		eec = IXGBE_READ_REG(hw, IXGBE_EEC);
946a14ee0cSDon Skidmore 		eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
956a14ee0cSDon Skidmore 				    IXGBE_EEC_SIZE_SHIFT);
966a14ee0cSDon Skidmore 		eeprom->word_size = 1 << (eeprom_size +
976a14ee0cSDon Skidmore 					  IXGBE_EEPROM_WORD_SIZE_SHIFT);
986a14ee0cSDon Skidmore 
996a14ee0cSDon Skidmore 		hw_dbg(hw, "Eeprom params: type = %d, size = %d\n",
1006a14ee0cSDon Skidmore 		       eeprom->type, eeprom->word_size);
1016a14ee0cSDon Skidmore 	}
1026a14ee0cSDon Skidmore 
1036a14ee0cSDon Skidmore 	return 0;
1046a14ee0cSDon Skidmore }
1056a14ee0cSDon Skidmore 
1066a14ee0cSDon Skidmore /** ixgbe_read_iosf_sb_reg_x550 - Writes a value to specified register of the
1076a14ee0cSDon Skidmore  *  IOSF device
1086a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
1096a14ee0cSDon Skidmore  *  @reg_addr: 32 bit PHY register to write
1106a14ee0cSDon Skidmore  *  @device_type: 3 bit device type
1116a14ee0cSDon Skidmore  *  @phy_data: Pointer to read data from the register
1126a14ee0cSDon Skidmore  **/
1136a14ee0cSDon Skidmore s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
1146a14ee0cSDon Skidmore 				u32 device_type, u32 *data)
1156a14ee0cSDon Skidmore {
1166a14ee0cSDon Skidmore 	u32 i, command, error;
1176a14ee0cSDon Skidmore 
1186a14ee0cSDon Skidmore 	command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
1196a14ee0cSDon Skidmore 		   (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
1206a14ee0cSDon Skidmore 
1216a14ee0cSDon Skidmore 	/* Write IOSF control register */
1226a14ee0cSDon Skidmore 	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
1236a14ee0cSDon Skidmore 
1246a14ee0cSDon Skidmore 	/* Check every 10 usec to see if the address cycle completed.
1256a14ee0cSDon Skidmore 	 * The SB IOSF BUSY bit will clear when the operation is
1266a14ee0cSDon Skidmore 	 * complete
1276a14ee0cSDon Skidmore 	 */
1286a14ee0cSDon Skidmore 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
1296a14ee0cSDon Skidmore 		usleep_range(10, 20);
1306a14ee0cSDon Skidmore 
1316a14ee0cSDon Skidmore 		command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
1326a14ee0cSDon Skidmore 		if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
1336a14ee0cSDon Skidmore 			break;
1346a14ee0cSDon Skidmore 	}
1356a14ee0cSDon Skidmore 
1366a14ee0cSDon Skidmore 	if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
1376a14ee0cSDon Skidmore 		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
1386a14ee0cSDon Skidmore 			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
1396a14ee0cSDon Skidmore 		hw_dbg(hw, "Failed to read, error %x\n", error);
1406a14ee0cSDon Skidmore 		return IXGBE_ERR_PHY;
1416a14ee0cSDon Skidmore 	}
1426a14ee0cSDon Skidmore 
1436a14ee0cSDon Skidmore 	if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
1446a14ee0cSDon Skidmore 		hw_dbg(hw, "Read timed out\n");
1456a14ee0cSDon Skidmore 		return IXGBE_ERR_PHY;
1466a14ee0cSDon Skidmore 	}
1476a14ee0cSDon Skidmore 
1486a14ee0cSDon Skidmore 	*data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA);
1496a14ee0cSDon Skidmore 
1506a14ee0cSDon Skidmore 	return 0;
1516a14ee0cSDon Skidmore }
1526a14ee0cSDon Skidmore 
1536a14ee0cSDon Skidmore /** ixgbe_read_ee_hostif_data_X550 - Read EEPROM word using a host interface
1546a14ee0cSDon Skidmore  *  command assuming that the semaphore is already obtained.
1556a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
1566a14ee0cSDon Skidmore  *  @offset: offset of  word in the EEPROM to read
1576a14ee0cSDon Skidmore  *  @data: word read from the EEPROM
1586a14ee0cSDon Skidmore  *
1596a14ee0cSDon Skidmore  *  Reads a 16 bit word from the EEPROM using the hostif.
1606a14ee0cSDon Skidmore  **/
1616a14ee0cSDon Skidmore s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
1626a14ee0cSDon Skidmore {
1636a14ee0cSDon Skidmore 	s32 status;
1646a14ee0cSDon Skidmore 	struct ixgbe_hic_read_shadow_ram buffer;
1656a14ee0cSDon Skidmore 
1666a14ee0cSDon Skidmore 	buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
1676a14ee0cSDon Skidmore 	buffer.hdr.req.buf_lenh = 0;
1686a14ee0cSDon Skidmore 	buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
1696a14ee0cSDon Skidmore 	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
1706a14ee0cSDon Skidmore 
1716a14ee0cSDon Skidmore 	/* convert offset from words to bytes */
1726a14ee0cSDon Skidmore 	buffer.address = cpu_to_be32(offset * 2);
1736a14ee0cSDon Skidmore 	/* one word */
1746a14ee0cSDon Skidmore 	buffer.length = cpu_to_be16(sizeof(u16));
1756a14ee0cSDon Skidmore 
1766a14ee0cSDon Skidmore 	status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
1776a14ee0cSDon Skidmore 					      sizeof(buffer),
1786a14ee0cSDon Skidmore 					      IXGBE_HI_COMMAND_TIMEOUT, false);
1796a14ee0cSDon Skidmore 	if (status)
1806a14ee0cSDon Skidmore 		return status;
1816a14ee0cSDon Skidmore 
1826a14ee0cSDon Skidmore 	*data = (u16)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG,
1836a14ee0cSDon Skidmore 					  FW_NVM_DATA_OFFSET);
1846a14ee0cSDon Skidmore 
1856a14ee0cSDon Skidmore 	return 0;
1866a14ee0cSDon Skidmore }
1876a14ee0cSDon Skidmore 
1886a14ee0cSDon Skidmore /** ixgbe_read_ee_hostif_buffer_X550- Read EEPROM word(s) using hostif
1896a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
1906a14ee0cSDon Skidmore  *  @offset: offset of  word in the EEPROM to read
1916a14ee0cSDon Skidmore  *  @words: number of words
1926a14ee0cSDon Skidmore  *  @data: word(s) read from the EEPROM
1936a14ee0cSDon Skidmore  *
1946a14ee0cSDon Skidmore  *  Reads a 16 bit word(s) from the EEPROM using the hostif.
1956a14ee0cSDon Skidmore  **/
1966a14ee0cSDon Skidmore s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
1976a14ee0cSDon Skidmore 				     u16 offset, u16 words, u16 *data)
1986a14ee0cSDon Skidmore {
1996a14ee0cSDon Skidmore 	struct ixgbe_hic_read_shadow_ram buffer;
2006a14ee0cSDon Skidmore 	u32 current_word = 0;
2016a14ee0cSDon Skidmore 	u16 words_to_read;
2026a14ee0cSDon Skidmore 	s32 status;
2036a14ee0cSDon Skidmore 	u32 i;
2046a14ee0cSDon Skidmore 
2056a14ee0cSDon Skidmore 	/* Take semaphore for the entire operation. */
2066a14ee0cSDon Skidmore 	status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
2076a14ee0cSDon Skidmore 	if (status) {
2086a14ee0cSDon Skidmore 		hw_dbg(hw, "EEPROM read buffer - semaphore failed\n");
2096a14ee0cSDon Skidmore 		return status;
2106a14ee0cSDon Skidmore 	}
2116a14ee0cSDon Skidmore 
2126a14ee0cSDon Skidmore 	while (words) {
2136a14ee0cSDon Skidmore 		if (words > FW_MAX_READ_BUFFER_SIZE / 2)
2146a14ee0cSDon Skidmore 			words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
2156a14ee0cSDon Skidmore 		else
2166a14ee0cSDon Skidmore 			words_to_read = words;
2176a14ee0cSDon Skidmore 
2186a14ee0cSDon Skidmore 		buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
2196a14ee0cSDon Skidmore 		buffer.hdr.req.buf_lenh = 0;
2206a14ee0cSDon Skidmore 		buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
2216a14ee0cSDon Skidmore 		buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
2226a14ee0cSDon Skidmore 
2236a14ee0cSDon Skidmore 		/* convert offset from words to bytes */
2246a14ee0cSDon Skidmore 		buffer.address = cpu_to_be32((offset + current_word) * 2);
2256a14ee0cSDon Skidmore 		buffer.length = cpu_to_be16(words_to_read * 2);
2266a14ee0cSDon Skidmore 
2276a14ee0cSDon Skidmore 		status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
2286a14ee0cSDon Skidmore 						      sizeof(buffer),
2296a14ee0cSDon Skidmore 						      IXGBE_HI_COMMAND_TIMEOUT,
2306a14ee0cSDon Skidmore 						      false);
2316a14ee0cSDon Skidmore 		if (status) {
2326a14ee0cSDon Skidmore 			hw_dbg(hw, "Host interface command failed\n");
2336a14ee0cSDon Skidmore 			goto out;
2346a14ee0cSDon Skidmore 		}
2356a14ee0cSDon Skidmore 
2366a14ee0cSDon Skidmore 		for (i = 0; i < words_to_read; i++) {
2376a14ee0cSDon Skidmore 			u32 reg = IXGBE_FLEX_MNG + (FW_NVM_DATA_OFFSET << 2) +
2386a14ee0cSDon Skidmore 				  2 * i;
2396a14ee0cSDon Skidmore 			u32 value = IXGBE_READ_REG(hw, reg);
2406a14ee0cSDon Skidmore 
2416a14ee0cSDon Skidmore 			data[current_word] = (u16)(value & 0xffff);
2426a14ee0cSDon Skidmore 			current_word++;
2436a14ee0cSDon Skidmore 			i++;
2446a14ee0cSDon Skidmore 			if (i < words_to_read) {
2456a14ee0cSDon Skidmore 				value >>= 16;
2466a14ee0cSDon Skidmore 				data[current_word] = (u16)(value & 0xffff);
2476a14ee0cSDon Skidmore 				current_word++;
2486a14ee0cSDon Skidmore 			}
2496a14ee0cSDon Skidmore 		}
2506a14ee0cSDon Skidmore 		words -= words_to_read;
2516a14ee0cSDon Skidmore 	}
2526a14ee0cSDon Skidmore 
2536a14ee0cSDon Skidmore out:
2546a14ee0cSDon Skidmore 	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
2556a14ee0cSDon Skidmore 	return status;
2566a14ee0cSDon Skidmore }
2576a14ee0cSDon Skidmore 
2586a14ee0cSDon Skidmore /** ixgbe_checksum_ptr_x550 - Checksum one pointer region
2596a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
2606a14ee0cSDon Skidmore  *  @ptr: pointer offset in eeprom
2616a14ee0cSDon Skidmore  *  @size: size of section pointed by ptr, if 0 first word will be used as size
2626a14ee0cSDon Skidmore  *  @csum: address of checksum to update
2636a14ee0cSDon Skidmore  *
2646a14ee0cSDon Skidmore  *  Returns error status for any failure
2656a14ee0cSDon Skidmore  **/
2666a14ee0cSDon Skidmore static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
2676a14ee0cSDon Skidmore 				   u16 size, u16 *csum, u16 *buffer,
2686a14ee0cSDon Skidmore 				   u32 buffer_size)
2696a14ee0cSDon Skidmore {
2706a14ee0cSDon Skidmore 	u16 buf[256];
2716a14ee0cSDon Skidmore 	s32 status;
2726a14ee0cSDon Skidmore 	u16 length, bufsz, i, start;
2736a14ee0cSDon Skidmore 	u16 *local_buffer;
2746a14ee0cSDon Skidmore 
2756a14ee0cSDon Skidmore 	bufsz = sizeof(buf) / sizeof(buf[0]);
2766a14ee0cSDon Skidmore 
2776a14ee0cSDon Skidmore 	/* Read a chunk at the pointer location */
2786a14ee0cSDon Skidmore 	if (!buffer) {
2796a14ee0cSDon Skidmore 		status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf);
2806a14ee0cSDon Skidmore 		if (status) {
2816a14ee0cSDon Skidmore 			hw_dbg(hw, "Failed to read EEPROM image\n");
2826a14ee0cSDon Skidmore 			return status;
2836a14ee0cSDon Skidmore 		}
2846a14ee0cSDon Skidmore 		local_buffer = buf;
2856a14ee0cSDon Skidmore 	} else {
2866a14ee0cSDon Skidmore 		if (buffer_size < ptr)
2876a14ee0cSDon Skidmore 			return  IXGBE_ERR_PARAM;
2886a14ee0cSDon Skidmore 		local_buffer = &buffer[ptr];
2896a14ee0cSDon Skidmore 	}
2906a14ee0cSDon Skidmore 
2916a14ee0cSDon Skidmore 	if (size) {
2926a14ee0cSDon Skidmore 		start = 0;
2936a14ee0cSDon Skidmore 		length = size;
2946a14ee0cSDon Skidmore 	} else {
2956a14ee0cSDon Skidmore 		start = 1;
2966a14ee0cSDon Skidmore 		length = local_buffer[0];
2976a14ee0cSDon Skidmore 
2986a14ee0cSDon Skidmore 		/* Skip pointer section if length is invalid. */
2996a14ee0cSDon Skidmore 		if (length == 0xFFFF || length == 0 ||
3006a14ee0cSDon Skidmore 		    (ptr + length) >= hw->eeprom.word_size)
3016a14ee0cSDon Skidmore 			return 0;
3026a14ee0cSDon Skidmore 	}
3036a14ee0cSDon Skidmore 
3046a14ee0cSDon Skidmore 	if (buffer && ((u32)start + (u32)length > buffer_size))
3056a14ee0cSDon Skidmore 		return IXGBE_ERR_PARAM;
3066a14ee0cSDon Skidmore 
3076a14ee0cSDon Skidmore 	for (i = start; length; i++, length--) {
3086a14ee0cSDon Skidmore 		if (i == bufsz && !buffer) {
3096a14ee0cSDon Skidmore 			ptr += bufsz;
3106a14ee0cSDon Skidmore 			i = 0;
3116a14ee0cSDon Skidmore 			if (length < bufsz)
3126a14ee0cSDon Skidmore 				bufsz = length;
3136a14ee0cSDon Skidmore 
3146a14ee0cSDon Skidmore 			/* Read a chunk at the pointer location */
3156a14ee0cSDon Skidmore 			status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr,
3166a14ee0cSDon Skidmore 								  bufsz, buf);
3176a14ee0cSDon Skidmore 			if (status) {
3186a14ee0cSDon Skidmore 				hw_dbg(hw, "Failed to read EEPROM image\n");
3196a14ee0cSDon Skidmore 				return status;
3206a14ee0cSDon Skidmore 			}
3216a14ee0cSDon Skidmore 		}
3226a14ee0cSDon Skidmore 		*csum += local_buffer[i];
3236a14ee0cSDon Skidmore 	}
3246a14ee0cSDon Skidmore 	return 0;
3256a14ee0cSDon Skidmore }
3266a14ee0cSDon Skidmore 
3276a14ee0cSDon Skidmore /** ixgbe_calc_checksum_X550 - Calculates and returns the checksum
3286a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
3296a14ee0cSDon Skidmore  *  @buffer: pointer to buffer containing calculated checksum
3306a14ee0cSDon Skidmore  *  @buffer_size: size of buffer
3316a14ee0cSDon Skidmore  *
3326a14ee0cSDon Skidmore  *  Returns a negative error code on error, or the 16-bit checksum
3336a14ee0cSDon Skidmore  **/
3346a14ee0cSDon Skidmore s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size)
3356a14ee0cSDon Skidmore {
3366a14ee0cSDon Skidmore 	u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1];
3376a14ee0cSDon Skidmore 	u16 *local_buffer;
3386a14ee0cSDon Skidmore 	s32 status;
3396a14ee0cSDon Skidmore 	u16 checksum = 0;
3406a14ee0cSDon Skidmore 	u16 pointer, i, size;
3416a14ee0cSDon Skidmore 
3426a14ee0cSDon Skidmore 	hw->eeprom.ops.init_params(hw);
3436a14ee0cSDon Skidmore 
3446a14ee0cSDon Skidmore 	if (!buffer) {
3456a14ee0cSDon Skidmore 		/* Read pointer area */
3466a14ee0cSDon Skidmore 		status = ixgbe_read_ee_hostif_buffer_X550(hw, 0,
3476a14ee0cSDon Skidmore 						IXGBE_EEPROM_LAST_WORD + 1,
3486a14ee0cSDon Skidmore 						eeprom_ptrs);
3496a14ee0cSDon Skidmore 		if (status) {
3506a14ee0cSDon Skidmore 			hw_dbg(hw, "Failed to read EEPROM image\n");
3516a14ee0cSDon Skidmore 			return status;
3526a14ee0cSDon Skidmore 		}
3536a14ee0cSDon Skidmore 		local_buffer = eeprom_ptrs;
3546a14ee0cSDon Skidmore 	} else {
3556a14ee0cSDon Skidmore 		if (buffer_size < IXGBE_EEPROM_LAST_WORD)
3566a14ee0cSDon Skidmore 			return IXGBE_ERR_PARAM;
3576a14ee0cSDon Skidmore 		local_buffer = buffer;
3586a14ee0cSDon Skidmore 	}
3596a14ee0cSDon Skidmore 
3606a14ee0cSDon Skidmore 	/* For X550 hardware include 0x0-0x41 in the checksum, skip the
3616a14ee0cSDon Skidmore 	 * checksum word itself
3626a14ee0cSDon Skidmore 	 */
3636a14ee0cSDon Skidmore 	for (i = 0; i <= IXGBE_EEPROM_LAST_WORD; i++)
3646a14ee0cSDon Skidmore 		if (i != IXGBE_EEPROM_CHECKSUM)
3656a14ee0cSDon Skidmore 			checksum += local_buffer[i];
3666a14ee0cSDon Skidmore 
3676a14ee0cSDon Skidmore 	/* Include all data from pointers 0x3, 0x6-0xE.  This excludes the
3686a14ee0cSDon Skidmore 	 * FW, PHY module, and PCIe Expansion/Option ROM pointers.
3696a14ee0cSDon Skidmore 	 */
3706a14ee0cSDon Skidmore 	for (i = IXGBE_PCIE_ANALOG_PTR_X550; i < IXGBE_FW_PTR; i++) {
3716a14ee0cSDon Skidmore 		if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
3726a14ee0cSDon Skidmore 			continue;
3736a14ee0cSDon Skidmore 
3746a14ee0cSDon Skidmore 		pointer = local_buffer[i];
3756a14ee0cSDon Skidmore 
3766a14ee0cSDon Skidmore 		/* Skip pointer section if the pointer is invalid. */
3776a14ee0cSDon Skidmore 		if (pointer == 0xFFFF || pointer == 0 ||
3786a14ee0cSDon Skidmore 		    pointer >= hw->eeprom.word_size)
3796a14ee0cSDon Skidmore 			continue;
3806a14ee0cSDon Skidmore 
3816a14ee0cSDon Skidmore 		switch (i) {
3826a14ee0cSDon Skidmore 		case IXGBE_PCIE_GENERAL_PTR:
3836a14ee0cSDon Skidmore 			size = IXGBE_IXGBE_PCIE_GENERAL_SIZE;
3846a14ee0cSDon Skidmore 			break;
3856a14ee0cSDon Skidmore 		case IXGBE_PCIE_CONFIG0_PTR:
3866a14ee0cSDon Skidmore 		case IXGBE_PCIE_CONFIG1_PTR:
3876a14ee0cSDon Skidmore 			size = IXGBE_PCIE_CONFIG_SIZE;
3886a14ee0cSDon Skidmore 			break;
3896a14ee0cSDon Skidmore 		default:
3906a14ee0cSDon Skidmore 			size = 0;
3916a14ee0cSDon Skidmore 			break;
3926a14ee0cSDon Skidmore 		}
3936a14ee0cSDon Skidmore 
3946a14ee0cSDon Skidmore 		status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum,
3956a14ee0cSDon Skidmore 						 buffer, buffer_size);
3966a14ee0cSDon Skidmore 		if (status)
3976a14ee0cSDon Skidmore 			return status;
3986a14ee0cSDon Skidmore 	}
3996a14ee0cSDon Skidmore 
4006a14ee0cSDon Skidmore 	checksum = (u16)IXGBE_EEPROM_SUM - checksum;
4016a14ee0cSDon Skidmore 
4026a14ee0cSDon Skidmore 	return (s32)checksum;
4036a14ee0cSDon Skidmore }
4046a14ee0cSDon Skidmore 
4056a14ee0cSDon Skidmore /** ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum
4066a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
4076a14ee0cSDon Skidmore  *
4086a14ee0cSDon Skidmore  *  Returns a negative error code on error, or the 16-bit checksum
4096a14ee0cSDon Skidmore  **/
4106a14ee0cSDon Skidmore s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
4116a14ee0cSDon Skidmore {
4126a14ee0cSDon Skidmore 	return ixgbe_calc_checksum_X550(hw, NULL, 0);
4136a14ee0cSDon Skidmore }
4146a14ee0cSDon Skidmore 
4156a14ee0cSDon Skidmore /** ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command
4166a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
4176a14ee0cSDon Skidmore  *  @offset: offset of  word in the EEPROM to read
4186a14ee0cSDon Skidmore  *  @data: word read from the EEPROM
4196a14ee0cSDon Skidmore  *
4206a14ee0cSDon Skidmore  *   Reads a 16 bit word from the EEPROM using the hostif.
4216a14ee0cSDon Skidmore  **/
4226a14ee0cSDon Skidmore s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
4236a14ee0cSDon Skidmore {
4246a14ee0cSDon Skidmore 	s32 status = 0;
4256a14ee0cSDon Skidmore 
4266a14ee0cSDon Skidmore 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
4276a14ee0cSDon Skidmore 		status = ixgbe_read_ee_hostif_data_X550(hw, offset, data);
4286a14ee0cSDon Skidmore 		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
4296a14ee0cSDon Skidmore 	} else {
4306a14ee0cSDon Skidmore 		status = IXGBE_ERR_SWFW_SYNC;
4316a14ee0cSDon Skidmore 	}
4326a14ee0cSDon Skidmore 
4336a14ee0cSDon Skidmore 	return status;
4346a14ee0cSDon Skidmore }
4356a14ee0cSDon Skidmore 
4366a14ee0cSDon Skidmore /** ixgbe_validate_eeprom_checksum_X550 - Validate EEPROM checksum
4376a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
4386a14ee0cSDon Skidmore  *  @checksum_val: calculated checksum
4396a14ee0cSDon Skidmore  *
4406a14ee0cSDon Skidmore  *  Performs checksum calculation and validates the EEPROM checksum.  If the
4416a14ee0cSDon Skidmore  *  caller does not need checksum_val, the value can be NULL.
4426a14ee0cSDon Skidmore  **/
4436a14ee0cSDon Skidmore s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val)
4446a14ee0cSDon Skidmore {
4456a14ee0cSDon Skidmore 	s32 status;
4466a14ee0cSDon Skidmore 	u16 checksum;
4476a14ee0cSDon Skidmore 	u16 read_checksum = 0;
4486a14ee0cSDon Skidmore 
4496a14ee0cSDon Skidmore 	/* Read the first word from the EEPROM. If this times out or fails, do
4506a14ee0cSDon Skidmore 	 * not continue or we could be in for a very long wait while every
4516a14ee0cSDon Skidmore 	 * EEPROM read fails
4526a14ee0cSDon Skidmore 	 */
4536a14ee0cSDon Skidmore 	status = hw->eeprom.ops.read(hw, 0, &checksum);
4546a14ee0cSDon Skidmore 	if (status) {
4556a14ee0cSDon Skidmore 		hw_dbg(hw, "EEPROM read failed\n");
4566a14ee0cSDon Skidmore 		return status;
4576a14ee0cSDon Skidmore 	}
4586a14ee0cSDon Skidmore 
4596a14ee0cSDon Skidmore 	status = hw->eeprom.ops.calc_checksum(hw);
4606a14ee0cSDon Skidmore 	if (status < 0)
4616a14ee0cSDon Skidmore 		return status;
4626a14ee0cSDon Skidmore 
4636a14ee0cSDon Skidmore 	checksum = (u16)(status & 0xffff);
4646a14ee0cSDon Skidmore 
4656a14ee0cSDon Skidmore 	status = ixgbe_read_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
4666a14ee0cSDon Skidmore 					   &read_checksum);
4676a14ee0cSDon Skidmore 	if (status)
4686a14ee0cSDon Skidmore 		return status;
4696a14ee0cSDon Skidmore 
4706a14ee0cSDon Skidmore 	/* Verify read checksum from EEPROM is the same as
4716a14ee0cSDon Skidmore 	 * calculated checksum
4726a14ee0cSDon Skidmore 	 */
4736a14ee0cSDon Skidmore 	if (read_checksum != checksum) {
4746a14ee0cSDon Skidmore 		status = IXGBE_ERR_EEPROM_CHECKSUM;
4756a14ee0cSDon Skidmore 		hw_dbg(hw, "Invalid EEPROM checksum");
4766a14ee0cSDon Skidmore 	}
4776a14ee0cSDon Skidmore 
4786a14ee0cSDon Skidmore 	/* If the user cares, return the calculated checksum */
4796a14ee0cSDon Skidmore 	if (checksum_val)
4806a14ee0cSDon Skidmore 		*checksum_val = checksum;
4816a14ee0cSDon Skidmore 
4826a14ee0cSDon Skidmore 	return status;
4836a14ee0cSDon Skidmore }
4846a14ee0cSDon Skidmore 
4856a14ee0cSDon Skidmore /** ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
4866a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
4876a14ee0cSDon Skidmore  *  @offset: offset of  word in the EEPROM to write
4886a14ee0cSDon Skidmore  *  @data: word write to the EEPROM
4896a14ee0cSDon Skidmore  *
4906a14ee0cSDon Skidmore  *  Write a 16 bit word to the EEPROM using the hostif.
4916a14ee0cSDon Skidmore  **/
4926a14ee0cSDon Skidmore s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
4936a14ee0cSDon Skidmore {
4946a14ee0cSDon Skidmore 	s32 status;
4956a14ee0cSDon Skidmore 	struct ixgbe_hic_write_shadow_ram buffer;
4966a14ee0cSDon Skidmore 
4976a14ee0cSDon Skidmore 	buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
4986a14ee0cSDon Skidmore 	buffer.hdr.req.buf_lenh = 0;
4996a14ee0cSDon Skidmore 	buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
5006a14ee0cSDon Skidmore 	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
5016a14ee0cSDon Skidmore 
5026a14ee0cSDon Skidmore 	/* one word */
5036a14ee0cSDon Skidmore 	buffer.length = cpu_to_be16(sizeof(u16));
5046a14ee0cSDon Skidmore 	buffer.data = data;
5056a14ee0cSDon Skidmore 	buffer.address = cpu_to_be32(offset * 2);
5066a14ee0cSDon Skidmore 
5076a14ee0cSDon Skidmore 	status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
5086a14ee0cSDon Skidmore 					      sizeof(buffer),
5096a14ee0cSDon Skidmore 					      IXGBE_HI_COMMAND_TIMEOUT, false);
5106a14ee0cSDon Skidmore 	return status;
5116a14ee0cSDon Skidmore }
5126a14ee0cSDon Skidmore 
5136a14ee0cSDon Skidmore /** ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
5146a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
5156a14ee0cSDon Skidmore  *  @offset: offset of  word in the EEPROM to write
5166a14ee0cSDon Skidmore  *  @data: word write to the EEPROM
5176a14ee0cSDon Skidmore  *
5186a14ee0cSDon Skidmore  *  Write a 16 bit word to the EEPROM using the hostif.
5196a14ee0cSDon Skidmore  **/
5206a14ee0cSDon Skidmore s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
5216a14ee0cSDon Skidmore {
5226a14ee0cSDon Skidmore 	s32 status = 0;
5236a14ee0cSDon Skidmore 
5246a14ee0cSDon Skidmore 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
5256a14ee0cSDon Skidmore 		status = ixgbe_write_ee_hostif_data_X550(hw, offset, data);
5266a14ee0cSDon Skidmore 		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
5276a14ee0cSDon Skidmore 	} else {
5286a14ee0cSDon Skidmore 		hw_dbg(hw, "write ee hostif failed to get semaphore");
5296a14ee0cSDon Skidmore 		status = IXGBE_ERR_SWFW_SYNC;
5306a14ee0cSDon Skidmore 	}
5316a14ee0cSDon Skidmore 
5326a14ee0cSDon Skidmore 	return status;
5336a14ee0cSDon Skidmore }
5346a14ee0cSDon Skidmore 
5356a14ee0cSDon Skidmore /** ixgbe_update_flash_X550 - Instruct HW to copy EEPROM to Flash device
5366a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
5376a14ee0cSDon Skidmore  *
5386a14ee0cSDon Skidmore  *  Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash.
5396a14ee0cSDon Skidmore  **/
5406a14ee0cSDon Skidmore s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
5416a14ee0cSDon Skidmore {
5426a14ee0cSDon Skidmore 	s32 status = 0;
5436a14ee0cSDon Skidmore 	union ixgbe_hic_hdr2 buffer;
5446a14ee0cSDon Skidmore 
5456a14ee0cSDon Skidmore 	buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD;
5466a14ee0cSDon Skidmore 	buffer.req.buf_lenh = 0;
5476a14ee0cSDon Skidmore 	buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
5486a14ee0cSDon Skidmore 	buffer.req.checksum = FW_DEFAULT_CHECKSUM;
5496a14ee0cSDon Skidmore 
5506a14ee0cSDon Skidmore 	status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
5516a14ee0cSDon Skidmore 					      sizeof(buffer),
5526a14ee0cSDon Skidmore 					      IXGBE_HI_COMMAND_TIMEOUT, false);
5536a14ee0cSDon Skidmore 	return status;
5546a14ee0cSDon Skidmore }
5556a14ee0cSDon Skidmore 
5566a14ee0cSDon Skidmore /** ixgbe_update_eeprom_checksum_X550 - Updates the EEPROM checksum and flash
5576a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
5586a14ee0cSDon Skidmore  *
5596a14ee0cSDon Skidmore  *  After writing EEPROM to shadow RAM using EEWR register, software calculates
5606a14ee0cSDon Skidmore  *  checksum and updates the EEPROM and instructs the hardware to update
5616a14ee0cSDon Skidmore  *  the flash.
5626a14ee0cSDon Skidmore  **/
5636a14ee0cSDon Skidmore s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
5646a14ee0cSDon Skidmore {
5656a14ee0cSDon Skidmore 	s32 status;
5666a14ee0cSDon Skidmore 	u16 checksum = 0;
5676a14ee0cSDon Skidmore 
5686a14ee0cSDon Skidmore 	/* Read the first word from the EEPROM. If this times out or fails, do
5696a14ee0cSDon Skidmore 	 * not continue or we could be in for a very long wait while every
5706a14ee0cSDon Skidmore 	 * EEPROM read fails
5716a14ee0cSDon Skidmore 	 */
5726a14ee0cSDon Skidmore 	status = ixgbe_read_ee_hostif_X550(hw, 0, &checksum);
5736a14ee0cSDon Skidmore 	if (status) {
5746a14ee0cSDon Skidmore 		hw_dbg(hw, "EEPROM read failed\n");
5756a14ee0cSDon Skidmore 		return status;
5766a14ee0cSDon Skidmore 	}
5776a14ee0cSDon Skidmore 
5786a14ee0cSDon Skidmore 	status = ixgbe_calc_eeprom_checksum_X550(hw);
5796a14ee0cSDon Skidmore 	if (status < 0)
5806a14ee0cSDon Skidmore 		return status;
5816a14ee0cSDon Skidmore 
5826a14ee0cSDon Skidmore 	checksum = (u16)(status & 0xffff);
5836a14ee0cSDon Skidmore 
5846a14ee0cSDon Skidmore 	status = ixgbe_write_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
5856a14ee0cSDon Skidmore 					    checksum);
5866a14ee0cSDon Skidmore 	if (status)
5876a14ee0cSDon Skidmore 		return status;
5886a14ee0cSDon Skidmore 
5896a14ee0cSDon Skidmore 	status = ixgbe_update_flash_X550(hw);
5906a14ee0cSDon Skidmore 
5916a14ee0cSDon Skidmore 	return status;
5926a14ee0cSDon Skidmore }
5936a14ee0cSDon Skidmore 
5946a14ee0cSDon Skidmore /** ixgbe_write_ee_hostif_buffer_X550 - Write EEPROM word(s) using hostif
5956a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
5966a14ee0cSDon Skidmore  *  @offset: offset of  word in the EEPROM to write
5976a14ee0cSDon Skidmore  *  @words: number of words
5986a14ee0cSDon Skidmore  *  @data: word(s) write to the EEPROM
5996a14ee0cSDon Skidmore  *
6006a14ee0cSDon Skidmore  *
6016a14ee0cSDon Skidmore  *  Write a 16 bit word(s) to the EEPROM using the hostif.
6026a14ee0cSDon Skidmore  **/
6036a14ee0cSDon Skidmore s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
6046a14ee0cSDon Skidmore 				      u16 offset, u16 words, u16 *data)
6056a14ee0cSDon Skidmore {
6066a14ee0cSDon Skidmore 	s32 status = 0;
6076a14ee0cSDon Skidmore 	u32 i = 0;
6086a14ee0cSDon Skidmore 
6096a14ee0cSDon Skidmore 	/* Take semaphore for the entire operation. */
6106a14ee0cSDon Skidmore 	status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
6116a14ee0cSDon Skidmore 	if (status) {
6126a14ee0cSDon Skidmore 		hw_dbg(hw, "EEPROM write buffer - semaphore failed\n");
6136a14ee0cSDon Skidmore 		return status;
6146a14ee0cSDon Skidmore 	}
6156a14ee0cSDon Skidmore 
6166a14ee0cSDon Skidmore 	for (i = 0; i < words; i++) {
6176a14ee0cSDon Skidmore 		status = ixgbe_write_ee_hostif_data_X550(hw, offset + i,
6186a14ee0cSDon Skidmore 							 data[i]);
6196a14ee0cSDon Skidmore 		if (status) {
6206a14ee0cSDon Skidmore 			hw_dbg(hw, "Eeprom buffered write failed\n");
6216a14ee0cSDon Skidmore 			break;
6226a14ee0cSDon Skidmore 		}
6236a14ee0cSDon Skidmore 	}
6246a14ee0cSDon Skidmore 
6256a14ee0cSDon Skidmore 	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
6266a14ee0cSDon Skidmore 
6276a14ee0cSDon Skidmore 	return status;
6286a14ee0cSDon Skidmore }
6296a14ee0cSDon Skidmore 
6306a14ee0cSDon Skidmore /** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
6316a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
6326a14ee0cSDon Skidmore  **/
6336a14ee0cSDon Skidmore void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
6346a14ee0cSDon Skidmore {
6356a14ee0cSDon Skidmore 	struct ixgbe_mac_info *mac = &hw->mac;
6366a14ee0cSDon Skidmore 
6376a14ee0cSDon Skidmore 	/* CS4227 does not support autoneg, so disable the laser control
6386a14ee0cSDon Skidmore 	 * functions for SFP+ fiber
6396a14ee0cSDon Skidmore 	 */
6406a14ee0cSDon Skidmore 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
6416a14ee0cSDon Skidmore 		mac->ops.disable_tx_laser = NULL;
6426a14ee0cSDon Skidmore 		mac->ops.enable_tx_laser = NULL;
6436a14ee0cSDon Skidmore 		mac->ops.flap_tx_laser = NULL;
6446a14ee0cSDon Skidmore 	}
6456a14ee0cSDon Skidmore }
6466a14ee0cSDon Skidmore 
6476a14ee0cSDon Skidmore /** ixgbe_setup_sfp_modules_X550em - Setup SFP module
6486a14ee0cSDon Skidmore  * @hw: pointer to hardware structure
6496a14ee0cSDon Skidmore  */
6506a14ee0cSDon Skidmore s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
6516a14ee0cSDon Skidmore {
6526a14ee0cSDon Skidmore 	bool setup_linear;
6536a14ee0cSDon Skidmore 	u16 reg_slice, edc_mode;
6546a14ee0cSDon Skidmore 	s32 ret_val;
6556a14ee0cSDon Skidmore 
6566a14ee0cSDon Skidmore 	switch (hw->phy.sfp_type) {
6576a14ee0cSDon Skidmore 	case ixgbe_sfp_type_unknown:
6586a14ee0cSDon Skidmore 		return 0;
6596a14ee0cSDon Skidmore 	case ixgbe_sfp_type_not_present:
6606a14ee0cSDon Skidmore 		return IXGBE_ERR_SFP_NOT_PRESENT;
6616a14ee0cSDon Skidmore 	case ixgbe_sfp_type_da_cu_core0:
6626a14ee0cSDon Skidmore 	case ixgbe_sfp_type_da_cu_core1:
6636a14ee0cSDon Skidmore 		setup_linear = true;
6646a14ee0cSDon Skidmore 		break;
6656a14ee0cSDon Skidmore 	case ixgbe_sfp_type_srlr_core0:
6666a14ee0cSDon Skidmore 	case ixgbe_sfp_type_srlr_core1:
6676a14ee0cSDon Skidmore 	case ixgbe_sfp_type_da_act_lmt_core0:
6686a14ee0cSDon Skidmore 	case ixgbe_sfp_type_da_act_lmt_core1:
6696a14ee0cSDon Skidmore 	case ixgbe_sfp_type_1g_sx_core0:
6706a14ee0cSDon Skidmore 	case ixgbe_sfp_type_1g_sx_core1:
6716a14ee0cSDon Skidmore 		setup_linear = false;
6726a14ee0cSDon Skidmore 		break;
6736a14ee0cSDon Skidmore 	default:
6746a14ee0cSDon Skidmore 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
6756a14ee0cSDon Skidmore 	}
6766a14ee0cSDon Skidmore 
6776a14ee0cSDon Skidmore 	ixgbe_init_mac_link_ops_X550em(hw);
6786a14ee0cSDon Skidmore 	hw->phy.ops.reset = NULL;
6796a14ee0cSDon Skidmore 
6806a14ee0cSDon Skidmore 	/* The CS4227 slice address is the base address + the port-pair reg
6816a14ee0cSDon Skidmore 	 * offset. I.e. Slice 0 = 0x12B0 and slice 1 = 0x22B0.
6826a14ee0cSDon Skidmore 	 */
6836a14ee0cSDon Skidmore 	reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->bus.lan_id << 12);
6846a14ee0cSDon Skidmore 
6856a14ee0cSDon Skidmore 	if (setup_linear)
6866a14ee0cSDon Skidmore 		edc_mode = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
6876a14ee0cSDon Skidmore 	else
6886a14ee0cSDon Skidmore 		edc_mode = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
6896a14ee0cSDon Skidmore 
6906a14ee0cSDon Skidmore 	/* Configure CS4227 for connection type. */
6916a14ee0cSDon Skidmore 	ret_val = hw->phy.ops.write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
6926a14ee0cSDon Skidmore 						 edc_mode);
6936a14ee0cSDon Skidmore 
6946a14ee0cSDon Skidmore 	if (ret_val)
6956a14ee0cSDon Skidmore 		ret_val = hw->phy.ops.write_i2c_combined(hw, 0x80, reg_slice,
6966a14ee0cSDon Skidmore 							 edc_mode);
6976a14ee0cSDon Skidmore 
6986a14ee0cSDon Skidmore 	return ret_val;
6996a14ee0cSDon Skidmore }
7006a14ee0cSDon Skidmore 
7016a14ee0cSDon Skidmore /** ixgbe_get_link_capabilities_x550em - Determines link capabilities
7026a14ee0cSDon Skidmore  * @hw: pointer to hardware structure
7036a14ee0cSDon Skidmore  * @speed: pointer to link speed
7046a14ee0cSDon Skidmore  * @autoneg: true when autoneg or autotry is enabled
7056a14ee0cSDon Skidmore  **/
7066a14ee0cSDon Skidmore s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
7076a14ee0cSDon Skidmore 				       ixgbe_link_speed *speed,
7086a14ee0cSDon Skidmore 				       bool *autoneg)
7096a14ee0cSDon Skidmore {
7106a14ee0cSDon Skidmore 	/* SFP */
7116a14ee0cSDon Skidmore 	if (hw->phy.media_type == ixgbe_media_type_fiber) {
7126a14ee0cSDon Skidmore 		/* CS4227 SFP must not enable auto-negotiation */
7136a14ee0cSDon Skidmore 		*autoneg = false;
7146a14ee0cSDon Skidmore 
7156a14ee0cSDon Skidmore 		if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
7166a14ee0cSDon Skidmore 		    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
7176a14ee0cSDon Skidmore 			*speed = IXGBE_LINK_SPEED_1GB_FULL;
7186a14ee0cSDon Skidmore 			return 0;
7196a14ee0cSDon Skidmore 		}
7206a14ee0cSDon Skidmore 
7216a14ee0cSDon Skidmore 		/* Link capabilities are based on SFP */
7226a14ee0cSDon Skidmore 		if (hw->phy.multispeed_fiber)
7236a14ee0cSDon Skidmore 			*speed = IXGBE_LINK_SPEED_10GB_FULL |
7246a14ee0cSDon Skidmore 				 IXGBE_LINK_SPEED_1GB_FULL;
7256a14ee0cSDon Skidmore 		else
7266a14ee0cSDon Skidmore 			*speed = IXGBE_LINK_SPEED_10GB_FULL;
7276a14ee0cSDon Skidmore 	} else {
7286a14ee0cSDon Skidmore 		*speed = IXGBE_LINK_SPEED_10GB_FULL |
7296a14ee0cSDon Skidmore 			 IXGBE_LINK_SPEED_1GB_FULL;
7306a14ee0cSDon Skidmore 		*autoneg = true;
7316a14ee0cSDon Skidmore 	}
7326a14ee0cSDon Skidmore 	return 0;
7336a14ee0cSDon Skidmore }
7346a14ee0cSDon Skidmore 
7356a14ee0cSDon Skidmore /** ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the
7366a14ee0cSDon Skidmore  *  IOSF device
7376a14ee0cSDon Skidmore  *
7386a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
7396a14ee0cSDon Skidmore  *  @reg_addr: 32 bit PHY register to write
7406a14ee0cSDon Skidmore  *  @device_type: 3 bit device type
7416a14ee0cSDon Skidmore  *  @data: Data to write to the register
7426a14ee0cSDon Skidmore  **/
7436a14ee0cSDon Skidmore s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
7446a14ee0cSDon Skidmore 				 u32 device_type, u32 data)
7456a14ee0cSDon Skidmore {
7466a14ee0cSDon Skidmore 	u32 i, command, error;
7476a14ee0cSDon Skidmore 
7486a14ee0cSDon Skidmore 	command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
7496a14ee0cSDon Skidmore 		   (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
7506a14ee0cSDon Skidmore 
7516a14ee0cSDon Skidmore 	/* Write IOSF control register */
7526a14ee0cSDon Skidmore 	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
7536a14ee0cSDon Skidmore 
7546a14ee0cSDon Skidmore 	/* Write IOSF data register */
7556a14ee0cSDon Skidmore 	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data);
7566a14ee0cSDon Skidmore 
7576a14ee0cSDon Skidmore 	/* Check every 10 usec to see if the address cycle completed.
7586a14ee0cSDon Skidmore 	 * The SB IOSF BUSY bit will clear when the operation is
7596a14ee0cSDon Skidmore 	 * complete
7606a14ee0cSDon Skidmore 	 */
7616a14ee0cSDon Skidmore 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
7626a14ee0cSDon Skidmore 		usleep_range(10, 20);
7636a14ee0cSDon Skidmore 
7646a14ee0cSDon Skidmore 		command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
7656a14ee0cSDon Skidmore 		if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
7666a14ee0cSDon Skidmore 			break;
7676a14ee0cSDon Skidmore 	}
7686a14ee0cSDon Skidmore 
7696a14ee0cSDon Skidmore 	if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
7706a14ee0cSDon Skidmore 		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
7716a14ee0cSDon Skidmore 			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
7726a14ee0cSDon Skidmore 		hw_dbg(hw, "Failed to write, error %x\n", error);
7736a14ee0cSDon Skidmore 		return IXGBE_ERR_PHY;
7746a14ee0cSDon Skidmore 	}
7756a14ee0cSDon Skidmore 
7766a14ee0cSDon Skidmore 	if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
7776a14ee0cSDon Skidmore 		hw_dbg(hw, "Write timed out\n");
7786a14ee0cSDon Skidmore 		return IXGBE_ERR_PHY;
7796a14ee0cSDon Skidmore 	}
7806a14ee0cSDon Skidmore 
7816a14ee0cSDon Skidmore 	return 0;
7826a14ee0cSDon Skidmore }
7836a14ee0cSDon Skidmore 
7846a14ee0cSDon Skidmore /** ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
7856a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
7866a14ee0cSDon Skidmore  *  @speed: the link speed to force
7876a14ee0cSDon Skidmore  *
7886a14ee0cSDon Skidmore  *  Configures the integrated KR PHY to use iXFI mode. Used to connect an
7896a14ee0cSDon Skidmore  *  internal and external PHY at a specific speed, without autonegotiation.
7906a14ee0cSDon Skidmore  **/
7916a14ee0cSDon Skidmore static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
7926a14ee0cSDon Skidmore {
7936a14ee0cSDon Skidmore 	s32 status;
7946a14ee0cSDon Skidmore 	u32 reg_val;
7956a14ee0cSDon Skidmore 
7966a14ee0cSDon Skidmore 	/* Disable AN and force speed to 10G Serial. */
7976a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
7986a14ee0cSDon Skidmore 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
7996a14ee0cSDon Skidmore 					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
8006a14ee0cSDon Skidmore 	if (status)
8016a14ee0cSDon Skidmore 		return status;
8026a14ee0cSDon Skidmore 
8036a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
8046a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
8056a14ee0cSDon Skidmore 
8066a14ee0cSDon Skidmore 	/* Select forced link speed for internal PHY. */
8076a14ee0cSDon Skidmore 	switch (*speed) {
8086a14ee0cSDon Skidmore 	case IXGBE_LINK_SPEED_10GB_FULL:
8096a14ee0cSDon Skidmore 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
8106a14ee0cSDon Skidmore 		break;
8116a14ee0cSDon Skidmore 	case IXGBE_LINK_SPEED_1GB_FULL:
8126a14ee0cSDon Skidmore 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
8136a14ee0cSDon Skidmore 		break;
8146a14ee0cSDon Skidmore 	default:
8156a14ee0cSDon Skidmore 		/* Other link speeds are not supported by internal KR PHY. */
8166a14ee0cSDon Skidmore 		return IXGBE_ERR_LINK_SETUP;
8176a14ee0cSDon Skidmore 	}
8186a14ee0cSDon Skidmore 
8196a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
8206a14ee0cSDon Skidmore 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
8216a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
8226a14ee0cSDon Skidmore 	if (status)
8236a14ee0cSDon Skidmore 		return status;
8246a14ee0cSDon Skidmore 
8256a14ee0cSDon Skidmore 	/* Disable training protocol FSM. */
8266a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
8276a14ee0cSDon Skidmore 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
8286a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
8296a14ee0cSDon Skidmore 	if (status)
8306a14ee0cSDon Skidmore 		return status;
8316a14ee0cSDon Skidmore 
8326a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
8336a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
8346a14ee0cSDon Skidmore 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
8356a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
8366a14ee0cSDon Skidmore 	if (status)
8376a14ee0cSDon Skidmore 		return status;
8386a14ee0cSDon Skidmore 
8396a14ee0cSDon Skidmore 	/* Disable Flex from training TXFFE. */
8406a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
8416a14ee0cSDon Skidmore 				IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
8426a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
8436a14ee0cSDon Skidmore 	if (status)
8446a14ee0cSDon Skidmore 		return status;
8456a14ee0cSDon Skidmore 
8466a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
8476a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
8486a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
8496a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
8506a14ee0cSDon Skidmore 				IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
8516a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
8526a14ee0cSDon Skidmore 	if (status)
8536a14ee0cSDon Skidmore 		return status;
8546a14ee0cSDon Skidmore 
8556a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
8566a14ee0cSDon Skidmore 				IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
8576a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
8586a14ee0cSDon Skidmore 	if (status)
8596a14ee0cSDon Skidmore 		return status;
8606a14ee0cSDon Skidmore 
8616a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
8626a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
8636a14ee0cSDon Skidmore 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
8646a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
8656a14ee0cSDon Skidmore 				IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
8666a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
8676a14ee0cSDon Skidmore 	if (status)
8686a14ee0cSDon Skidmore 		return status;
8696a14ee0cSDon Skidmore 
8706a14ee0cSDon Skidmore 	/* Enable override for coefficients. */
8716a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
8726a14ee0cSDon Skidmore 				IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
8736a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
8746a14ee0cSDon Skidmore 	if (status)
8756a14ee0cSDon Skidmore 		return status;
8766a14ee0cSDon Skidmore 
8776a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN;
8786a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN;
8796a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
8806a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
8816a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
8826a14ee0cSDon Skidmore 				IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
8836a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
8846a14ee0cSDon Skidmore 	if (status)
8856a14ee0cSDon Skidmore 		return status;
8866a14ee0cSDon Skidmore 
8876a14ee0cSDon Skidmore 	/* Toggle port SW reset by AN reset. */
8886a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
8896a14ee0cSDon Skidmore 				IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
8906a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
8916a14ee0cSDon Skidmore 	if (status)
8926a14ee0cSDon Skidmore 		return status;
8936a14ee0cSDon Skidmore 
8946a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
8956a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
8966a14ee0cSDon Skidmore 				IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
8976a14ee0cSDon Skidmore 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
8986a14ee0cSDon Skidmore 
8996a14ee0cSDon Skidmore 	return status;
9006a14ee0cSDon Skidmore }
9016a14ee0cSDon Skidmore 
9026a14ee0cSDon Skidmore /** ixgbe_setup_kx4_x550em - Configure the KX4 PHY.
9036a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
9046a14ee0cSDon Skidmore  *
9056a14ee0cSDon Skidmore  *   Configures the integrated KX4 PHY.
9066a14ee0cSDon Skidmore  **/
9076a14ee0cSDon Skidmore s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
9086a14ee0cSDon Skidmore {
9096a14ee0cSDon Skidmore 	s32 status;
9106a14ee0cSDon Skidmore 	u32 reg_val;
9116a14ee0cSDon Skidmore 
9126a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1,
9136a14ee0cSDon Skidmore 					     IXGBE_SB_IOSF_TARGET_KX4_PCS0 +
9146a14ee0cSDon Skidmore 					     hw->bus.lan_id, &reg_val);
9156a14ee0cSDon Skidmore 	if (status)
9166a14ee0cSDon Skidmore 		return status;
9176a14ee0cSDon Skidmore 
9186a14ee0cSDon Skidmore 	reg_val &= ~(IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4 |
9196a14ee0cSDon Skidmore 		     IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX);
9206a14ee0cSDon Skidmore 
9216a14ee0cSDon Skidmore 	reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_ENABLE;
9226a14ee0cSDon Skidmore 
9236a14ee0cSDon Skidmore 	/* Advertise 10G support. */
9246a14ee0cSDon Skidmore 	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
9256a14ee0cSDon Skidmore 		reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4;
9266a14ee0cSDon Skidmore 
9276a14ee0cSDon Skidmore 	/* Advertise 1G support. */
9286a14ee0cSDon Skidmore 	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
9296a14ee0cSDon Skidmore 		reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX;
9306a14ee0cSDon Skidmore 
9316a14ee0cSDon Skidmore 	/* Restart auto-negotiation. */
9326a14ee0cSDon Skidmore 	reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_RESTART;
9336a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1,
9346a14ee0cSDon Skidmore 					      IXGBE_SB_IOSF_TARGET_KX4_PCS0 +
9356a14ee0cSDon Skidmore 					      hw->bus.lan_id, reg_val);
9366a14ee0cSDon Skidmore 
9376a14ee0cSDon Skidmore 	return status;
9386a14ee0cSDon Skidmore }
9396a14ee0cSDon Skidmore 
9406a14ee0cSDon Skidmore /**  ixgbe_setup_kr_x550em - Configure the KR PHY.
9416a14ee0cSDon Skidmore  *   @hw: pointer to hardware structure
9426a14ee0cSDon Skidmore  *
9436a14ee0cSDon Skidmore  *   Configures the integrated KR PHY.
9446a14ee0cSDon Skidmore  **/
9456a14ee0cSDon Skidmore s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
9466a14ee0cSDon Skidmore {
9476a14ee0cSDon Skidmore 	s32 status;
9486a14ee0cSDon Skidmore 	u32 reg_val;
9496a14ee0cSDon Skidmore 
9506a14ee0cSDon Skidmore 	status = ixgbe_read_iosf_sb_reg_x550(hw,
9516a14ee0cSDon Skidmore 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
9526a14ee0cSDon Skidmore 					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
9536a14ee0cSDon Skidmore 	if (status)
9546a14ee0cSDon Skidmore 		return status;
9556a14ee0cSDon Skidmore 
9566a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
9576a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ;
9586a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC;
9596a14ee0cSDon Skidmore 	reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
9606a14ee0cSDon Skidmore 		     IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
9616a14ee0cSDon Skidmore 
9626a14ee0cSDon Skidmore 	/* Advertise 10G support. */
9636a14ee0cSDon Skidmore 	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
9646a14ee0cSDon Skidmore 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
9656a14ee0cSDon Skidmore 
9666a14ee0cSDon Skidmore 	/* Advertise 1G support. */
9676a14ee0cSDon Skidmore 	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
9686a14ee0cSDon Skidmore 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
9696a14ee0cSDon Skidmore 
9706a14ee0cSDon Skidmore 	/* Restart auto-negotiation. */
9716a14ee0cSDon Skidmore 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
9726a14ee0cSDon Skidmore 	status = ixgbe_write_iosf_sb_reg_x550(hw,
9736a14ee0cSDon Skidmore 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
9746a14ee0cSDon Skidmore 					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
9756a14ee0cSDon Skidmore 
9766a14ee0cSDon Skidmore 	return status;
9776a14ee0cSDon Skidmore }
9786a14ee0cSDon Skidmore 
9796a14ee0cSDon Skidmore /** ixgbe_setup_internal_phy_x550em - Configure integrated KR PHY
9806a14ee0cSDon Skidmore  *  @hw: point to hardware structure
9816a14ee0cSDon Skidmore  *
9826a14ee0cSDon Skidmore  *  Configures the integrated KR PHY to talk to the external PHY. The base
9836a14ee0cSDon Skidmore  *  driver will call this function when it gets notification via interrupt from
9846a14ee0cSDon Skidmore  *  the external PHY. This function forces the internal PHY into iXFI mode at
9856a14ee0cSDon Skidmore  *  the correct speed.
9866a14ee0cSDon Skidmore  *
9876a14ee0cSDon Skidmore  *  A return of a non-zero value indicates an error, and the base driver should
9886a14ee0cSDon Skidmore  *  not report link up.
9896a14ee0cSDon Skidmore  **/
9906a14ee0cSDon Skidmore s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
9916a14ee0cSDon Skidmore {
9926a14ee0cSDon Skidmore 	u32 status;
9936a14ee0cSDon Skidmore 	u16 lasi, autoneg_status, speed;
9946a14ee0cSDon Skidmore 	ixgbe_link_speed force_speed;
9956a14ee0cSDon Skidmore 
9966a14ee0cSDon Skidmore 	/* Verify that the external link status has changed */
9976a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_XENPAK_LASI_STATUS,
9986a14ee0cSDon Skidmore 				      IXGBE_MDIO_PMA_PMD_DEV_TYPE, &lasi);
9996a14ee0cSDon Skidmore 	if (status)
10006a14ee0cSDon Skidmore 		return status;
10016a14ee0cSDon Skidmore 
10026a14ee0cSDon Skidmore 	/* If there was no change in link status, we can just exit */
10036a14ee0cSDon Skidmore 	if (!(lasi & IXGBE_XENPAK_LASI_LINK_STATUS_ALARM))
10046a14ee0cSDon Skidmore 		return 0;
10056a14ee0cSDon Skidmore 
10066a14ee0cSDon Skidmore 	/* we read this twice back to back to indicate current status */
10076a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
10086a14ee0cSDon Skidmore 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
10096a14ee0cSDon Skidmore 				      &autoneg_status);
10106a14ee0cSDon Skidmore 	if (status)
10116a14ee0cSDon Skidmore 		return status;
10126a14ee0cSDon Skidmore 
10136a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
10146a14ee0cSDon Skidmore 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
10156a14ee0cSDon Skidmore 				      &autoneg_status);
10166a14ee0cSDon Skidmore 	if (status)
10176a14ee0cSDon Skidmore 		return status;
10186a14ee0cSDon Skidmore 
10196a14ee0cSDon Skidmore 	/* If link is not up return an error indicating treat link as down */
10206a14ee0cSDon Skidmore 	if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
10216a14ee0cSDon Skidmore 		return IXGBE_ERR_INVALID_LINK_SETTINGS;
10226a14ee0cSDon Skidmore 
10236a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
10246a14ee0cSDon Skidmore 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
10256a14ee0cSDon Skidmore 				      &speed);
10266a14ee0cSDon Skidmore 
10276a14ee0cSDon Skidmore 	/* clear everything but the speed and duplex bits */
10286a14ee0cSDon Skidmore 	speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
10296a14ee0cSDon Skidmore 
10306a14ee0cSDon Skidmore 	switch (speed) {
10316a14ee0cSDon Skidmore 	case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL:
10326a14ee0cSDon Skidmore 		force_speed = IXGBE_LINK_SPEED_10GB_FULL;
10336a14ee0cSDon Skidmore 		break;
10346a14ee0cSDon Skidmore 	case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL:
10356a14ee0cSDon Skidmore 		force_speed = IXGBE_LINK_SPEED_1GB_FULL;
10366a14ee0cSDon Skidmore 		break;
10376a14ee0cSDon Skidmore 	default:
10386a14ee0cSDon Skidmore 		/* Internal PHY does not support anything else */
10396a14ee0cSDon Skidmore 		return IXGBE_ERR_INVALID_LINK_SETTINGS;
10406a14ee0cSDon Skidmore 	}
10416a14ee0cSDon Skidmore 
10426a14ee0cSDon Skidmore 	return ixgbe_setup_ixfi_x550em(hw, &force_speed);
10436a14ee0cSDon Skidmore }
10446a14ee0cSDon Skidmore 
10456a14ee0cSDon Skidmore /** ixgbe_init_phy_ops_X550em - PHY/SFP specific init
10466a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
10476a14ee0cSDon Skidmore  *
10486a14ee0cSDon Skidmore  *  Initialize any function pointers that were not able to be
10496a14ee0cSDon Skidmore  *  set during init_shared_code because the PHY/SFP type was
10506a14ee0cSDon Skidmore  *  not known.  Perform the SFP init if necessary.
10516a14ee0cSDon Skidmore  **/
10526a14ee0cSDon Skidmore s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
10536a14ee0cSDon Skidmore {
10546a14ee0cSDon Skidmore 	struct ixgbe_phy_info *phy = &hw->phy;
10556a14ee0cSDon Skidmore 	s32 ret_val;
10566a14ee0cSDon Skidmore 	u32 esdp;
10576a14ee0cSDon Skidmore 
10586a14ee0cSDon Skidmore 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
10596a14ee0cSDon Skidmore 		esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
10606a14ee0cSDon Skidmore 		phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
10616a14ee0cSDon Skidmore 
10626a14ee0cSDon Skidmore 		if (hw->bus.lan_id) {
10636a14ee0cSDon Skidmore 			esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
10646a14ee0cSDon Skidmore 			esdp |= IXGBE_ESDP_SDP1_DIR;
10656a14ee0cSDon Skidmore 		}
10666a14ee0cSDon Skidmore 		esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
10676a14ee0cSDon Skidmore 		IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
10686a14ee0cSDon Skidmore 	}
10696a14ee0cSDon Skidmore 
10706a14ee0cSDon Skidmore 	/* Identify the PHY or SFP module */
10716a14ee0cSDon Skidmore 	ret_val = phy->ops.identify(hw);
10726a14ee0cSDon Skidmore 
10736a14ee0cSDon Skidmore 	/* Setup function pointers based on detected SFP module and speeds */
10746a14ee0cSDon Skidmore 	ixgbe_init_mac_link_ops_X550em(hw);
10756a14ee0cSDon Skidmore 	if (phy->sfp_type != ixgbe_sfp_type_unknown)
10766a14ee0cSDon Skidmore 		phy->ops.reset = NULL;
10776a14ee0cSDon Skidmore 
10786a14ee0cSDon Skidmore 	/* Set functions pointers based on phy type */
10796a14ee0cSDon Skidmore 	switch (hw->phy.type) {
10806a14ee0cSDon Skidmore 	case ixgbe_phy_x550em_kx4:
10816a14ee0cSDon Skidmore 		phy->ops.setup_link = ixgbe_setup_kx4_x550em;
10826a14ee0cSDon Skidmore 		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
10836a14ee0cSDon Skidmore 		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
10846a14ee0cSDon Skidmore 		break;
10856a14ee0cSDon Skidmore 	case ixgbe_phy_x550em_kr:
10866a14ee0cSDon Skidmore 		phy->ops.setup_link = ixgbe_setup_kr_x550em;
10876a14ee0cSDon Skidmore 		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
10886a14ee0cSDon Skidmore 		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
10896a14ee0cSDon Skidmore 		break;
10906a14ee0cSDon Skidmore 	case ixgbe_phy_x550em_ext_t:
10916a14ee0cSDon Skidmore 		phy->ops.setup_internal_link = ixgbe_setup_internal_phy_x550em;
10926a14ee0cSDon Skidmore 		break;
10936a14ee0cSDon Skidmore 	default:
10946a14ee0cSDon Skidmore 		break;
10956a14ee0cSDon Skidmore 	}
10966a14ee0cSDon Skidmore 	return ret_val;
10976a14ee0cSDon Skidmore }
10986a14ee0cSDon Skidmore 
10996a14ee0cSDon Skidmore /** ixgbe_get_media_type_X550em - Get media type
11006a14ee0cSDon Skidmore  *  @hw: pointer to hardware structure
11016a14ee0cSDon Skidmore  *
11026a14ee0cSDon Skidmore  *  Returns the media type (fiber, copper, backplane)
11036a14ee0cSDon Skidmore  *
11046a14ee0cSDon Skidmore  */
11056a14ee0cSDon Skidmore enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
11066a14ee0cSDon Skidmore {
11076a14ee0cSDon Skidmore 	enum ixgbe_media_type media_type;
11086a14ee0cSDon Skidmore 
11096a14ee0cSDon Skidmore 	/* Detect if there is a copper PHY attached. */
11106a14ee0cSDon Skidmore 	switch (hw->device_id) {
11116a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_KR:
11126a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_KX4:
11136a14ee0cSDon Skidmore 		media_type = ixgbe_media_type_backplane;
11146a14ee0cSDon Skidmore 		break;
11156a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_SFP:
11166a14ee0cSDon Skidmore 		media_type = ixgbe_media_type_fiber;
11176a14ee0cSDon Skidmore 		break;
11186a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_1G_T:
11196a14ee0cSDon Skidmore 	case IXGBE_DEV_ID_X550EM_X_10G_T:
11206a14ee0cSDon Skidmore 		 media_type = ixgbe_media_type_copper;
11216a14ee0cSDon Skidmore 		break;
11226a14ee0cSDon Skidmore 	default:
11236a14ee0cSDon Skidmore 		media_type = ixgbe_media_type_unknown;
11246a14ee0cSDon Skidmore 		break;
11256a14ee0cSDon Skidmore 	}
11266a14ee0cSDon Skidmore 	return media_type;
11276a14ee0cSDon Skidmore }
11286a14ee0cSDon Skidmore 
11296a14ee0cSDon Skidmore /** ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY.
11306a14ee0cSDon Skidmore  ** @hw: pointer to hardware structure
11316a14ee0cSDon Skidmore  **/
11326a14ee0cSDon Skidmore s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
11336a14ee0cSDon Skidmore {
11346a14ee0cSDon Skidmore 	u32 status;
11356a14ee0cSDon Skidmore 	u16 reg;
11366a14ee0cSDon Skidmore 	u32 retries = 2;
11376a14ee0cSDon Skidmore 
11386a14ee0cSDon Skidmore 	do {
11396a14ee0cSDon Skidmore 		/* decrement retries counter and exit if we hit 0 */
11406a14ee0cSDon Skidmore 		if (retries < 1) {
11416a14ee0cSDon Skidmore 			hw_dbg(hw, "External PHY not yet finished resetting.");
11426a14ee0cSDon Skidmore 			return IXGBE_ERR_PHY;
11436a14ee0cSDon Skidmore 		}
11446a14ee0cSDon Skidmore 		retries--;
11456a14ee0cSDon Skidmore 
11466a14ee0cSDon Skidmore 		status = hw->phy.ops.read_reg(hw,
11476a14ee0cSDon Skidmore 					      IXGBE_MDIO_TX_VENDOR_ALARMS_3,
11486a14ee0cSDon Skidmore 					      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
11496a14ee0cSDon Skidmore 					      &reg);
11506a14ee0cSDon Skidmore 		if (status)
11516a14ee0cSDon Skidmore 			return status;
11526a14ee0cSDon Skidmore 
11536a14ee0cSDon Skidmore 		/* Verify PHY FW reset has completed */
11546a14ee0cSDon Skidmore 	} while ((reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) != 1);
11556a14ee0cSDon Skidmore 
11566a14ee0cSDon Skidmore 	/* Set port to low power mode */
11576a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw,
11586a14ee0cSDon Skidmore 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
11596a14ee0cSDon Skidmore 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
11606a14ee0cSDon Skidmore 				      &reg);
11616a14ee0cSDon Skidmore 	if (status)
11626a14ee0cSDon Skidmore 		return status;
11636a14ee0cSDon Skidmore 
11646a14ee0cSDon Skidmore 	/* Enable the transmitter */
11656a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw,
11666a14ee0cSDon Skidmore 				      IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
11676a14ee0cSDon Skidmore 				      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
11686a14ee0cSDon Skidmore 				      &reg);
11696a14ee0cSDon Skidmore 	if (status)
11706a14ee0cSDon Skidmore 		return status;
11716a14ee0cSDon Skidmore 
11726a14ee0cSDon Skidmore 	reg &= ~IXGBE_MDIO_PMD_GLOBAL_TX_DISABLE;
11736a14ee0cSDon Skidmore 
11746a14ee0cSDon Skidmore 	status = hw->phy.ops.write_reg(hw,
11756a14ee0cSDon Skidmore 				       IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
11766a14ee0cSDon Skidmore 				       IXGBE_MDIO_PMA_PMD_DEV_TYPE,
11776a14ee0cSDon Skidmore 				       reg);
11786a14ee0cSDon Skidmore 	if (status)
11796a14ee0cSDon Skidmore 		return status;
11806a14ee0cSDon Skidmore 
11816a14ee0cSDon Skidmore 	/* Un-stall the PHY FW */
11826a14ee0cSDon Skidmore 	status = hw->phy.ops.read_reg(hw,
11836a14ee0cSDon Skidmore 				      IXGBE_MDIO_GLOBAL_RES_PR_10,
11846a14ee0cSDon Skidmore 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
11856a14ee0cSDon Skidmore 				      &reg);
11866a14ee0cSDon Skidmore 	if (status)
11876a14ee0cSDon Skidmore 		return status;
11886a14ee0cSDon Skidmore 
11896a14ee0cSDon Skidmore 	reg &= ~IXGBE_MDIO_POWER_UP_STALL;
11906a14ee0cSDon Skidmore 
11916a14ee0cSDon Skidmore 	status = hw->phy.ops.write_reg(hw,
11926a14ee0cSDon Skidmore 				       IXGBE_MDIO_GLOBAL_RES_PR_10,
11936a14ee0cSDon Skidmore 				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
11946a14ee0cSDon Skidmore 				       reg);
11956a14ee0cSDon Skidmore 	return status;
11966a14ee0cSDon Skidmore }
11976a14ee0cSDon Skidmore 
11986a14ee0cSDon Skidmore /**  ixgbe_reset_hw_X550em - Perform hardware reset
11996a14ee0cSDon Skidmore  **  @hw: pointer to hardware structure
12006a14ee0cSDon Skidmore  **
12016a14ee0cSDon Skidmore  **  Resets the hardware by resetting the transmit and receive units, masks
12026a14ee0cSDon Skidmore  **  and clears all interrupts, perform a PHY reset, and perform a link (MAC)
12036a14ee0cSDon Skidmore  **  reset.
12046a14ee0cSDon Skidmore  **/
12056a14ee0cSDon Skidmore s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
12066a14ee0cSDon Skidmore {
12076a14ee0cSDon Skidmore 	ixgbe_link_speed link_speed;
12086a14ee0cSDon Skidmore 	s32 status;
12096a14ee0cSDon Skidmore 	u32 ctrl = 0;
12106a14ee0cSDon Skidmore 	u32 i;
12116a14ee0cSDon Skidmore 	bool link_up = false;
12126a14ee0cSDon Skidmore 
12136a14ee0cSDon Skidmore 	/* Call adapter stop to disable Tx/Rx and clear interrupts */
12146a14ee0cSDon Skidmore 	status = hw->mac.ops.stop_adapter(hw);
12156a14ee0cSDon Skidmore 	if (status)
12166a14ee0cSDon Skidmore 		return status;
12176a14ee0cSDon Skidmore 
12186a14ee0cSDon Skidmore 	/* flush pending Tx transactions */
12196a14ee0cSDon Skidmore 	ixgbe_clear_tx_pending(hw);
12206a14ee0cSDon Skidmore 
12216a14ee0cSDon Skidmore 	/* PHY ops must be identified and initialized prior to reset */
12226a14ee0cSDon Skidmore 
12236a14ee0cSDon Skidmore 	/* Identify PHY and related function pointers */
12246a14ee0cSDon Skidmore 	status = hw->phy.ops.init(hw);
12256a14ee0cSDon Skidmore 
12266a14ee0cSDon Skidmore 	/* start the external PHY */
12276a14ee0cSDon Skidmore 	if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
12286a14ee0cSDon Skidmore 		status = ixgbe_init_ext_t_x550em(hw);
12296a14ee0cSDon Skidmore 		if (status)
12306a14ee0cSDon Skidmore 			return status;
12316a14ee0cSDon Skidmore 	}
12326a14ee0cSDon Skidmore 
12336a14ee0cSDon Skidmore 	/* Setup SFP module if there is one present. */
12346a14ee0cSDon Skidmore 	if (hw->phy.sfp_setup_needed) {
12356a14ee0cSDon Skidmore 		status = hw->mac.ops.setup_sfp(hw);
12366a14ee0cSDon Skidmore 		hw->phy.sfp_setup_needed = false;
12376a14ee0cSDon Skidmore 	}
12386a14ee0cSDon Skidmore 
12396a14ee0cSDon Skidmore 	/* Reset PHY */
12406a14ee0cSDon Skidmore 	if (!hw->phy.reset_disable && hw->phy.ops.reset)
12416a14ee0cSDon Skidmore 		hw->phy.ops.reset(hw);
12426a14ee0cSDon Skidmore 
12436a14ee0cSDon Skidmore mac_reset_top:
12446a14ee0cSDon Skidmore 	/* Issue global reset to the MAC.  Needs to be SW reset if link is up.
12456a14ee0cSDon Skidmore 	 * If link reset is used when link is up, it might reset the PHY when
12466a14ee0cSDon Skidmore 	 * mng is using it.  If link is down or the flag to force full link
12476a14ee0cSDon Skidmore 	 * reset is set, then perform link reset.
12486a14ee0cSDon Skidmore 	 */
12496a14ee0cSDon Skidmore 	ctrl = IXGBE_CTRL_LNK_RST;
12506a14ee0cSDon Skidmore 
12516a14ee0cSDon Skidmore 	if (!hw->force_full_reset) {
12526a14ee0cSDon Skidmore 		hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
12536a14ee0cSDon Skidmore 		if (link_up)
12546a14ee0cSDon Skidmore 			ctrl = IXGBE_CTRL_RST;
12556a14ee0cSDon Skidmore 	}
12566a14ee0cSDon Skidmore 
12576a14ee0cSDon Skidmore 	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
12586a14ee0cSDon Skidmore 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
12596a14ee0cSDon Skidmore 	IXGBE_WRITE_FLUSH(hw);
12606a14ee0cSDon Skidmore 
12616a14ee0cSDon Skidmore 	/* Poll for reset bit to self-clear meaning reset is complete */
12626a14ee0cSDon Skidmore 	for (i = 0; i < 10; i++) {
12636a14ee0cSDon Skidmore 		udelay(1);
12646a14ee0cSDon Skidmore 		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
12656a14ee0cSDon Skidmore 		if (!(ctrl & IXGBE_CTRL_RST_MASK))
12666a14ee0cSDon Skidmore 			break;
12676a14ee0cSDon Skidmore 	}
12686a14ee0cSDon Skidmore 
12696a14ee0cSDon Skidmore 	if (ctrl & IXGBE_CTRL_RST_MASK) {
12706a14ee0cSDon Skidmore 		status = IXGBE_ERR_RESET_FAILED;
12716a14ee0cSDon Skidmore 		hw_dbg(hw, "Reset polling failed to complete.\n");
12726a14ee0cSDon Skidmore 	}
12736a14ee0cSDon Skidmore 
12746a14ee0cSDon Skidmore 	msleep(50);
12756a14ee0cSDon Skidmore 
12766a14ee0cSDon Skidmore 	/* Double resets are required for recovery from certain error
12776a14ee0cSDon Skidmore 	 * clear the multicast table.  Also reset num_rar_entries to 128,
12786a14ee0cSDon Skidmore 	 * since we modify this value when programming the SAN MAC address.
12796a14ee0cSDon Skidmore 	 */
12806a14ee0cSDon Skidmore 	if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
12816a14ee0cSDon Skidmore 		hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
12826a14ee0cSDon Skidmore 		goto mac_reset_top;
12836a14ee0cSDon Skidmore 	}
12846a14ee0cSDon Skidmore 
12856a14ee0cSDon Skidmore 	/* Store the permanent mac address */
12866a14ee0cSDon Skidmore 	hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
12876a14ee0cSDon Skidmore 
12886a14ee0cSDon Skidmore 	/* Store MAC address from RAR0, clear receive address registers, and
12896a14ee0cSDon Skidmore 	 * clear the multicast table.  Also reset num_rar_entries to 128,
12906a14ee0cSDon Skidmore 	 * since we modify this value when programming the SAN MAC address.
12916a14ee0cSDon Skidmore 	 */
12926a14ee0cSDon Skidmore 	hw->mac.num_rar_entries = 128;
12936a14ee0cSDon Skidmore 	hw->mac.ops.init_rx_addrs(hw);
12946a14ee0cSDon Skidmore 
12956a14ee0cSDon Skidmore 	return status;
12966a14ee0cSDon Skidmore }
12976a14ee0cSDon Skidmore 
12986a14ee0cSDon Skidmore #define X550_COMMON_MAC \
12996a14ee0cSDon Skidmore 	.init_hw			= &ixgbe_init_hw_generic, \
13006a14ee0cSDon Skidmore 	.start_hw			= &ixgbe_start_hw_X540, \
13016a14ee0cSDon Skidmore 	.clear_hw_cntrs			= &ixgbe_clear_hw_cntrs_generic, \
13026a14ee0cSDon Skidmore 	.enable_rx_dma			= &ixgbe_enable_rx_dma_generic, \
13036a14ee0cSDon Skidmore 	.get_mac_addr			= &ixgbe_get_mac_addr_generic, \
13046a14ee0cSDon Skidmore 	.get_device_caps		= &ixgbe_get_device_caps_generic, \
13056a14ee0cSDon Skidmore 	.stop_adapter			= &ixgbe_stop_adapter_generic, \
13066a14ee0cSDon Skidmore 	.get_bus_info			= &ixgbe_get_bus_info_generic, \
13076a14ee0cSDon Skidmore 	.set_lan_id			= &ixgbe_set_lan_id_multi_port_pcie, \
13086a14ee0cSDon Skidmore 	.read_analog_reg8		= NULL, \
13096a14ee0cSDon Skidmore 	.write_analog_reg8		= NULL, \
13106a14ee0cSDon Skidmore 	.set_rxpba			= &ixgbe_set_rxpba_generic, \
13116a14ee0cSDon Skidmore 	.check_link			= &ixgbe_check_mac_link_generic, \
13126a14ee0cSDon Skidmore 	.led_on				= &ixgbe_led_on_generic, \
13136a14ee0cSDon Skidmore 	.led_off			= &ixgbe_led_off_generic, \
13146a14ee0cSDon Skidmore 	.blink_led_start		= &ixgbe_blink_led_start_X540, \
13156a14ee0cSDon Skidmore 	.blink_led_stop			= &ixgbe_blink_led_stop_X540, \
13166a14ee0cSDon Skidmore 	.set_rar			= &ixgbe_set_rar_generic, \
13176a14ee0cSDon Skidmore 	.clear_rar			= &ixgbe_clear_rar_generic, \
13186a14ee0cSDon Skidmore 	.set_vmdq			= &ixgbe_set_vmdq_generic, \
13196a14ee0cSDon Skidmore 	.set_vmdq_san_mac		= &ixgbe_set_vmdq_san_mac_generic, \
13206a14ee0cSDon Skidmore 	.clear_vmdq			= &ixgbe_clear_vmdq_generic, \
13216a14ee0cSDon Skidmore 	.init_rx_addrs			= &ixgbe_init_rx_addrs_generic, \
13226a14ee0cSDon Skidmore 	.update_mc_addr_list		= &ixgbe_update_mc_addr_list_generic, \
13236a14ee0cSDon Skidmore 	.enable_mc			= &ixgbe_enable_mc_generic, \
13246a14ee0cSDon Skidmore 	.disable_mc			= &ixgbe_disable_mc_generic, \
13256a14ee0cSDon Skidmore 	.clear_vfta			= &ixgbe_clear_vfta_generic, \
13266a14ee0cSDon Skidmore 	.set_vfta			= &ixgbe_set_vfta_generic, \
13276a14ee0cSDon Skidmore 	.fc_enable			= &ixgbe_fc_enable_generic, \
13286a14ee0cSDon Skidmore 	.set_fw_drv_ver			= &ixgbe_set_fw_drv_ver_generic, \
13296a14ee0cSDon Skidmore 	.init_uta_tables		= &ixgbe_init_uta_tables_generic, \
13306a14ee0cSDon Skidmore 	.set_mac_anti_spoofing		= &ixgbe_set_mac_anti_spoofing, \
13316a14ee0cSDon Skidmore 	.set_vlan_anti_spoofing		= &ixgbe_set_vlan_anti_spoofing, \
13326a14ee0cSDon Skidmore 	.acquire_swfw_sync		= &ixgbe_acquire_swfw_sync_X540, \
13336a14ee0cSDon Skidmore 	.release_swfw_sync		= &ixgbe_release_swfw_sync_X540, \
13346a14ee0cSDon Skidmore 	.disable_rx_buff		= &ixgbe_disable_rx_buff_generic, \
13356a14ee0cSDon Skidmore 	.enable_rx_buff			= &ixgbe_enable_rx_buff_generic, \
13366a14ee0cSDon Skidmore 	.get_thermal_sensor_data	= NULL, \
13376a14ee0cSDon Skidmore 	.init_thermal_sensor_thresh	= NULL, \
13386a14ee0cSDon Skidmore 	.prot_autoc_read		= &prot_autoc_read_generic, \
13396a14ee0cSDon Skidmore 	.prot_autoc_write		= &prot_autoc_write_generic, \
13406a14ee0cSDon Skidmore 
13416a14ee0cSDon Skidmore static struct ixgbe_mac_operations mac_ops_X550 = {
13426a14ee0cSDon Skidmore 	X550_COMMON_MAC
13436a14ee0cSDon Skidmore 	.reset_hw		= &ixgbe_reset_hw_X540,
13446a14ee0cSDon Skidmore 	.get_media_type		= &ixgbe_get_media_type_X540,
13456a14ee0cSDon Skidmore 	.get_san_mac_addr	= &ixgbe_get_san_mac_addr_generic,
13466a14ee0cSDon Skidmore 	.get_wwn_prefix		= &ixgbe_get_wwn_prefix_generic,
13476a14ee0cSDon Skidmore 	.setup_link		= &ixgbe_setup_mac_link_X540,
13486a14ee0cSDon Skidmore 	.set_rxpba		= &ixgbe_set_rxpba_generic,
13496a14ee0cSDon Skidmore 	.get_link_capabilities	= &ixgbe_get_copper_link_capabilities_generic,
13506a14ee0cSDon Skidmore 	.setup_sfp		= NULL,
13516a14ee0cSDon Skidmore };
13526a14ee0cSDon Skidmore 
13536a14ee0cSDon Skidmore static struct ixgbe_mac_operations mac_ops_X550EM_x = {
13546a14ee0cSDon Skidmore 	X550_COMMON_MAC
13556a14ee0cSDon Skidmore 	.reset_hw		= &ixgbe_reset_hw_X550em,
13566a14ee0cSDon Skidmore 	.get_media_type		= &ixgbe_get_media_type_X550em,
13576a14ee0cSDon Skidmore 	.get_san_mac_addr	= NULL,
13586a14ee0cSDon Skidmore 	.get_wwn_prefix		= NULL,
13596a14ee0cSDon Skidmore 	.setup_link		= NULL, /* defined later */
13606a14ee0cSDon Skidmore 	.get_link_capabilities	= &ixgbe_get_link_capabilities_X550em,
13616a14ee0cSDon Skidmore 	.setup_sfp		= ixgbe_setup_sfp_modules_X550em,
13626a14ee0cSDon Skidmore 
13636a14ee0cSDon Skidmore };
13646a14ee0cSDon Skidmore 
13656a14ee0cSDon Skidmore #define X550_COMMON_EEP \
13666a14ee0cSDon Skidmore 	.read			= &ixgbe_read_ee_hostif_X550, \
13676a14ee0cSDon Skidmore 	.read_buffer		= &ixgbe_read_ee_hostif_buffer_X550, \
13686a14ee0cSDon Skidmore 	.write			= &ixgbe_write_ee_hostif_X550, \
13696a14ee0cSDon Skidmore 	.write_buffer		= &ixgbe_write_ee_hostif_buffer_X550, \
13706a14ee0cSDon Skidmore 	.validate_checksum	= &ixgbe_validate_eeprom_checksum_X550, \
13716a14ee0cSDon Skidmore 	.update_checksum	= &ixgbe_update_eeprom_checksum_X550, \
13726a14ee0cSDon Skidmore 	.calc_checksum		= &ixgbe_calc_eeprom_checksum_X550, \
13736a14ee0cSDon Skidmore 
13746a14ee0cSDon Skidmore static struct ixgbe_eeprom_operations eeprom_ops_X550 = {
13756a14ee0cSDon Skidmore 	X550_COMMON_EEP
13766a14ee0cSDon Skidmore 	.init_params		= &ixgbe_init_eeprom_params_X550,
13776a14ee0cSDon Skidmore };
13786a14ee0cSDon Skidmore 
13796a14ee0cSDon Skidmore static struct ixgbe_eeprom_operations eeprom_ops_X550EM_x = {
13806a14ee0cSDon Skidmore 	X550_COMMON_EEP
13816a14ee0cSDon Skidmore 	.init_params		= &ixgbe_init_eeprom_params_X540,
13826a14ee0cSDon Skidmore };
13836a14ee0cSDon Skidmore 
13846a14ee0cSDon Skidmore #define X550_COMMON_PHY	\
13856a14ee0cSDon Skidmore 	.identify_sfp		= &ixgbe_identify_module_generic, \
13866a14ee0cSDon Skidmore 	.reset			= NULL, \
13876a14ee0cSDon Skidmore 	.setup_link_speed	= &ixgbe_setup_phy_link_speed_generic, \
13886a14ee0cSDon Skidmore 	.read_i2c_byte		= &ixgbe_read_i2c_byte_generic, \
13896a14ee0cSDon Skidmore 	.write_i2c_byte		= &ixgbe_write_i2c_byte_generic, \
13906a14ee0cSDon Skidmore 	.read_i2c_sff8472	= &ixgbe_read_i2c_sff8472_generic, \
13916a14ee0cSDon Skidmore 	.read_i2c_eeprom	= &ixgbe_read_i2c_eeprom_generic, \
13926a14ee0cSDon Skidmore 	.write_i2c_eeprom	= &ixgbe_write_i2c_eeprom_generic, \
13936a14ee0cSDon Skidmore 	.check_overtemp		= &ixgbe_tn_check_overtemp, \
13946a14ee0cSDon Skidmore 	.get_firmware_version	= &ixgbe_get_phy_firmware_version_generic,
13956a14ee0cSDon Skidmore 
13966a14ee0cSDon Skidmore static struct ixgbe_phy_operations phy_ops_X550 = {
13976a14ee0cSDon Skidmore 	X550_COMMON_PHY
13986a14ee0cSDon Skidmore 	.init			= NULL,
13996a14ee0cSDon Skidmore 	.identify		= &ixgbe_identify_phy_generic,
14006a14ee0cSDon Skidmore 	.read_reg		= &ixgbe_read_phy_reg_generic,
14016a14ee0cSDon Skidmore 	.write_reg		= &ixgbe_write_phy_reg_generic,
14026a14ee0cSDon Skidmore 	.setup_link		= &ixgbe_setup_phy_link_generic,
14036a14ee0cSDon Skidmore 	.read_i2c_combined	= &ixgbe_read_i2c_combined_generic,
14046a14ee0cSDon Skidmore 	.write_i2c_combined	= &ixgbe_write_i2c_combined_generic,
14056a14ee0cSDon Skidmore };
14066a14ee0cSDon Skidmore 
14076a14ee0cSDon Skidmore static struct ixgbe_phy_operations phy_ops_X550EM_x = {
14086a14ee0cSDon Skidmore 	X550_COMMON_PHY
14096a14ee0cSDon Skidmore 	.init			= &ixgbe_init_phy_ops_X550em,
14106a14ee0cSDon Skidmore 	.identify		= &ixgbe_identify_phy_x550em,
14116a14ee0cSDon Skidmore 	.read_reg		= NULL, /* defined later */
14126a14ee0cSDon Skidmore 	.write_reg		= NULL, /* defined later */
14136a14ee0cSDon Skidmore 	.setup_link		= NULL, /* defined later */
14146a14ee0cSDon Skidmore };
14156a14ee0cSDon Skidmore 
14166a14ee0cSDon Skidmore struct ixgbe_info ixgbe_X550_info = {
14176a14ee0cSDon Skidmore 	.mac			= ixgbe_mac_X550,
14186a14ee0cSDon Skidmore 	.get_invariants		= &ixgbe_get_invariants_X540,
14196a14ee0cSDon Skidmore 	.mac_ops		= &mac_ops_X550,
14206a14ee0cSDon Skidmore 	.eeprom_ops		= &eeprom_ops_X550,
14216a14ee0cSDon Skidmore 	.phy_ops		= &phy_ops_X550,
14226a14ee0cSDon Skidmore 	.mbx_ops		= &mbx_ops_generic,
14236a14ee0cSDon Skidmore };
14246a14ee0cSDon Skidmore 
14256a14ee0cSDon Skidmore struct ixgbe_info ixgbe_X550EM_x_info = {
14266a14ee0cSDon Skidmore 	.mac			= ixgbe_mac_X550EM_x,
14276a14ee0cSDon Skidmore 	.get_invariants		= &ixgbe_get_invariants_X540,
14286a14ee0cSDon Skidmore 	.mac_ops		= &mac_ops_X550EM_x,
14296a14ee0cSDon Skidmore 	.eeprom_ops		= &eeprom_ops_X550EM_x,
14306a14ee0cSDon Skidmore 	.phy_ops		= &phy_ops_X550EM_x,
14316a14ee0cSDon Skidmore 	.mbx_ops		= &mbx_ops_generic,
14326a14ee0cSDon Skidmore };
1433