xref: /openbsd-src/sys/dev/pci/ixgbe_x550.c (revision 54fbbda3b5f8c42357b8601b12a514e2d25a2771)
1*54fbbda3Sjsg /*	$OpenBSD: ixgbe_x550.c,v 1.10 2024/09/01 03:09:00 jsg Exp $	*/
2ac13930bSmikeb 
3ac13930bSmikeb /******************************************************************************
4ac13930bSmikeb 
5d7a8f955Sjmatthew   Copyright (c) 2001-2017, Intel Corporation
6ac13930bSmikeb   All rights reserved.
7ac13930bSmikeb 
8ac13930bSmikeb   Redistribution and use in source and binary forms, with or without
9ac13930bSmikeb   modification, are permitted provided that the following conditions are met:
10ac13930bSmikeb 
11ac13930bSmikeb    1. Redistributions of source code must retain the above copyright notice,
12ac13930bSmikeb       this list of conditions and the following disclaimer.
13ac13930bSmikeb 
14ac13930bSmikeb    2. Redistributions in binary form must reproduce the above copyright
15ac13930bSmikeb       notice, this list of conditions and the following disclaimer in the
16ac13930bSmikeb       documentation and/or other materials provided with the distribution.
17ac13930bSmikeb 
18ac13930bSmikeb    3. Neither the name of the Intel Corporation nor the names of its
19ac13930bSmikeb       contributors may be used to endorse or promote products derived from
20ac13930bSmikeb       this software without specific prior written permission.
21ac13930bSmikeb 
22ac13930bSmikeb   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23ac13930bSmikeb   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24ac13930bSmikeb   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25ac13930bSmikeb   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26ac13930bSmikeb   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27ac13930bSmikeb   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28ac13930bSmikeb   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29ac13930bSmikeb   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30ac13930bSmikeb   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31ac13930bSmikeb   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32ac13930bSmikeb   POSSIBILITY OF SUCH DAMAGE.
33ac13930bSmikeb 
34ac13930bSmikeb ******************************************************************************/
35d7a8f955Sjmatthew /*$FreeBSD: head/sys/dev/ixgbe/ixgbe_x550.c 333870 2018-05-19 05:57:26Z mmacy $*/
36ac13930bSmikeb 
37ac13930bSmikeb #include <dev/pci/ixgbe.h>
38ac13930bSmikeb #include <dev/pci/ixgbe_type.h>
39ac13930bSmikeb 
40ac13930bSmikeb extern int32_t ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw);
41ac13930bSmikeb extern int32_t ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, uint32_t mask);
42ac13930bSmikeb extern void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, uint32_t mask);
43ac13930bSmikeb 
44d7a8f955Sjmatthew int32_t ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, uint32_t mask);
45d7a8f955Sjmatthew void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *, uint32_t mask);
46d7a8f955Sjmatthew int32_t ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw);
47d7a8f955Sjmatthew 
48d7a8f955Sjmatthew int32_t ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw,
49d7a8f955Sjmatthew                                     ixgbe_link_speed speed,
50d7a8f955Sjmatthew                                     bool autoneg_wait_to_complete);
51d7a8f955Sjmatthew 
52d7a8f955Sjmatthew int32_t ixgbe_dmac_config_X550(struct ixgbe_hw *hw);
53d7a8f955Sjmatthew int32_t ixgbe_dmac_config_tcs_X550(struct ixgbe_hw *hw);
54d7a8f955Sjmatthew int32_t ixgbe_dmac_update_tcs_X550(struct ixgbe_hw *hw);
55d7a8f955Sjmatthew 
56ac13930bSmikeb int32_t ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw);
57ac13930bSmikeb int32_t ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw);
58ac13930bSmikeb int32_t ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw);
59ac13930bSmikeb int32_t ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw);
60ac13930bSmikeb int32_t ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, uint16_t *buffer,
61ac13930bSmikeb 				 uint32_t buffer_size);
62ac13930bSmikeb int32_t ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw,
63ac13930bSmikeb 					    uint16_t *checksum_val);
64ac13930bSmikeb int32_t ixgbe_update_flash_X550(struct ixgbe_hw *hw);
65ac13930bSmikeb int32_t ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, uint16_t offset,
66ac13930bSmikeb 			       uint16_t data);
67ac13930bSmikeb int32_t ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
68ac13930bSmikeb 					 uint16_t offset, uint16_t words,
69ac13930bSmikeb 					 uint16_t *data);
70ac13930bSmikeb int32_t ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, uint16_t offset,
71ac13930bSmikeb 				  uint16_t *data);
72ac13930bSmikeb int32_t ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, uint16_t offset,
73ac13930bSmikeb 					uint16_t data);
74d7a8f955Sjmatthew void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable,
75d7a8f955Sjmatthew 					   unsigned int pool);
76ac13930bSmikeb int32_t ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, uint32_t reg_addr,
77ac13930bSmikeb 				     uint32_t device_type, uint32_t data);
78ac13930bSmikeb int32_t ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, uint32_t reg_addr,
79ac13930bSmikeb 				    uint32_t device_type, uint32_t *data);
80d7a8f955Sjmatthew int32_t ixgbe_get_phy_token(struct ixgbe_hw *);
81d7a8f955Sjmatthew int32_t ixgbe_put_phy_token(struct ixgbe_hw *);
82d7a8f955Sjmatthew int32_t ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
83d7a8f955Sjmatthew 	uint32_t device_type, uint32_t data);
84d7a8f955Sjmatthew int32_t ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
85d7a8f955Sjmatthew 	uint32_t device_type, uint32_t *data);
86ac13930bSmikeb enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw);
87ac13930bSmikeb int32_t ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw);
88ac13930bSmikeb int32_t ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
89ac13930bSmikeb 					   ixgbe_link_speed *speed,
90ac13930bSmikeb 					   bool *autoneg);
91ac13930bSmikeb void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw);
92ac13930bSmikeb int32_t ixgbe_reset_hw_X550em(struct ixgbe_hw *hw);
93ac13930bSmikeb int32_t ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw);
94ac13930bSmikeb int32_t ixgbe_setup_kr_x550em(struct ixgbe_hw *hw);
95ac13930bSmikeb int32_t ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw);
96ac13930bSmikeb int32_t ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw);
97ac13930bSmikeb int32_t ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw);
98d7a8f955Sjmatthew uint64_t ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw);
99ac13930bSmikeb void ixgbe_disable_rx_x550(struct ixgbe_hw *hw);
100ac13930bSmikeb int32_t ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed);
101d7a8f955Sjmatthew int32_t ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw);
102ac13930bSmikeb int32_t ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, uint32_t mask);
103ac13930bSmikeb void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, uint32_t mask);
104ac13930bSmikeb int32_t ixgbe_setup_fc_X550em(struct ixgbe_hw *hw);
105ac13930bSmikeb int32_t ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
106ac13930bSmikeb 					ixgbe_link_speed speed,
107ac13930bSmikeb 					bool autoneg_wait_to_complete);
108d7a8f955Sjmatthew int32_t ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
109d7a8f955Sjmatthew 			       uint32_t device_type, uint16_t *phy_data);
110d7a8f955Sjmatthew int32_t ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
111d7a8f955Sjmatthew 				uint32_t device_type, uint16_t phy_data);
112d7a8f955Sjmatthew int32_t ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw);
113d7a8f955Sjmatthew void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw);
114d7a8f955Sjmatthew void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw);
115d7a8f955Sjmatthew void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw);
116ac13930bSmikeb int32_t ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw);
117ac13930bSmikeb int32_t ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
118ac13930bSmikeb 				      ixgbe_link_speed speed,
119ac13930bSmikeb 				      bool autoneg_wait_to_complete);
120ac13930bSmikeb int32_t ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
121ac13930bSmikeb 				  bool *link_up, bool link_up_wait_to_complete);
122ac13930bSmikeb int32_t ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw);
123ac13930bSmikeb int32_t ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw);
124ac13930bSmikeb int32_t ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, uint32_t led_idx);
125ac13930bSmikeb int32_t ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, uint32_t led_idx);
126ac13930bSmikeb 
127ac13930bSmikeb int32_t ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed);
128ac13930bSmikeb 
129d7a8f955Sjmatthew 
130ac13930bSmikeb /**
131ac13930bSmikeb  *  ixgbe_init_ops_X550 - Inits func ptrs and MAC type
132ac13930bSmikeb  *  @hw: pointer to hardware structure
133ac13930bSmikeb  *
134ac13930bSmikeb  *  Initialize the function pointers and assign the MAC type for X550.
135ac13930bSmikeb  *  Does not touch the hardware.
136ac13930bSmikeb  **/
137ac13930bSmikeb int32_t ixgbe_init_ops_X550(struct ixgbe_hw *hw)
138ac13930bSmikeb {
139ac13930bSmikeb 	struct ixgbe_mac_info *mac = &hw->mac;
140ac13930bSmikeb 	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
141ac13930bSmikeb 	int32_t ret_val;
142ac13930bSmikeb 
143ac13930bSmikeb 	DEBUGFUNC("ixgbe_init_ops_X550");
144ac13930bSmikeb 
145ac13930bSmikeb 	ret_val = ixgbe_init_ops_X540(hw);
146d7a8f955Sjmatthew 	mac->ops.dmac_config = ixgbe_dmac_config_X550;
147d7a8f955Sjmatthew 	mac->ops.dmac_config_tcs = ixgbe_dmac_config_tcs_X550;
148d7a8f955Sjmatthew 	mac->ops.dmac_update_tcs = ixgbe_dmac_update_tcs_X550;
149d7a8f955Sjmatthew 	mac->ops.setup_eee = NULL;
150d7a8f955Sjmatthew 	mac->ops.set_source_address_pruning =
151d7a8f955Sjmatthew 			ixgbe_set_source_address_pruning_X550;
152ac13930bSmikeb 
153ac13930bSmikeb 	eeprom->ops.init_params = ixgbe_init_eeprom_params_X550;
154ac13930bSmikeb 	eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550;
155ac13930bSmikeb 	eeprom->ops.read = ixgbe_read_ee_hostif_X550;
156ac13930bSmikeb 	eeprom->ops.write = ixgbe_write_ee_hostif_X550;
157ac13930bSmikeb 	eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550;
158ac13930bSmikeb 	eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550;
159ac13930bSmikeb 
160ac13930bSmikeb 	mac->ops.disable_rx = ixgbe_disable_rx_x550;
161d7a8f955Sjmatthew 	switch (hw->device_id) {
162d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_1G_T:
163d7a8f955Sjmatthew 		hw->mac.ops.led_on = NULL;
164d7a8f955Sjmatthew 		hw->mac.ops.led_off = NULL;
165d7a8f955Sjmatthew 		break;
166d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_10G_T:
167d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_10G_T:
168ac13930bSmikeb 		hw->mac.ops.led_on = ixgbe_led_on_t_X550em;
169ac13930bSmikeb 		hw->mac.ops.led_off = ixgbe_led_off_t_X550em;
170d7a8f955Sjmatthew 		break;
171d7a8f955Sjmatthew 	default:
172d7a8f955Sjmatthew 		break;
173ac13930bSmikeb 	}
174ac13930bSmikeb 	return ret_val;
175ac13930bSmikeb }
176ac13930bSmikeb 
177ac13930bSmikeb /**
178ac13930bSmikeb  * ixgbe_read_cs4227 - Read CS4227 register
179ac13930bSmikeb  * @hw: pointer to hardware structure
180ac13930bSmikeb  * @reg: register number to write
181ac13930bSmikeb  * @value: pointer to receive value read
182ac13930bSmikeb  *
183ac13930bSmikeb  * Returns status code
184ac13930bSmikeb  **/
185ac13930bSmikeb int32_t ixgbe_read_cs4227(struct ixgbe_hw *hw, uint16_t reg, uint16_t *value)
186ac13930bSmikeb {
187d7a8f955Sjmatthew 	return hw->link.ops.read_link_unlocked(hw, hw->link.addr, reg, value);
188ac13930bSmikeb }
189ac13930bSmikeb 
190ac13930bSmikeb /**
191ac13930bSmikeb  * ixgbe_write_cs4227 - Write CS4227 register
192ac13930bSmikeb  * @hw: pointer to hardware structure
193ac13930bSmikeb  * @reg: register number to write
194ac13930bSmikeb  * @value: value to write to register
195ac13930bSmikeb  *
196ac13930bSmikeb  * Returns status code
197ac13930bSmikeb  **/
198ac13930bSmikeb int32_t ixgbe_write_cs4227(struct ixgbe_hw *hw, uint16_t reg, uint16_t value)
199ac13930bSmikeb {
200d7a8f955Sjmatthew 	return hw->link.ops.write_link_unlocked(hw, hw->link.addr, reg, value);
201ac13930bSmikeb }
202ac13930bSmikeb 
203ac13930bSmikeb /**
204ac13930bSmikeb  * ixgbe_read_pe - Read register from port expander
205ac13930bSmikeb  * @hw: pointer to hardware structure
206ac13930bSmikeb  * @reg: register number to read
207ac13930bSmikeb  * @value: pointer to receive read value
208ac13930bSmikeb  *
209ac13930bSmikeb  * Returns status code
210ac13930bSmikeb  **/
211ac13930bSmikeb int32_t ixgbe_read_pe(struct ixgbe_hw *hw, uint8_t reg, uint8_t *value)
212ac13930bSmikeb {
213d7a8f955Sjmatthew 	int32_t status = IXGBE_NOT_IMPLEMENTED;
214ac13930bSmikeb 
215d7a8f955Sjmatthew 	if (hw->phy.ops.read_i2c_byte_unlocked)
216d7a8f955Sjmatthew 		status = hw->phy.ops.read_i2c_byte_unlocked(hw, reg, IXGBE_PE,
217d7a8f955Sjmatthew 		    value);
218ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
219d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
220d7a8f955Sjmatthew 			      "port expander access failed with %d\n", status);
221ac13930bSmikeb 	return status;
222ac13930bSmikeb }
223ac13930bSmikeb 
224ac13930bSmikeb /**
225ac13930bSmikeb  * ixgbe_write_pe - Write register to port expander
226ac13930bSmikeb  * @hw: pointer to hardware structure
227ac13930bSmikeb  * @reg: register number to write
228ac13930bSmikeb  * @value: value to write
229ac13930bSmikeb  *
230ac13930bSmikeb  * Returns status code
231ac13930bSmikeb  **/
232ac13930bSmikeb int32_t ixgbe_write_pe(struct ixgbe_hw *hw, uint8_t reg, uint8_t value)
233ac13930bSmikeb {
234d7a8f955Sjmatthew 	int32_t status = IXGBE_NOT_IMPLEMENTED;
235ac13930bSmikeb 
236d7a8f955Sjmatthew 	if (hw->phy.ops.write_i2c_byte_unlocked)
237d7a8f955Sjmatthew 		status = hw->phy.ops.write_i2c_byte_unlocked(hw, reg, IXGBE_PE,
238d7a8f955Sjmatthew 		    value);
239ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
240d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
241d7a8f955Sjmatthew 			      "port expander access failed with %d\n", status);
242ac13930bSmikeb 	return status;
243ac13930bSmikeb }
244ac13930bSmikeb 
245ac13930bSmikeb /**
246ac13930bSmikeb  * ixgbe_reset_cs4227 - Reset CS4227 using port expander
247ac13930bSmikeb  * @hw: pointer to hardware structure
248ac13930bSmikeb  *
249ac13930bSmikeb  * This function assumes that the caller has acquired the proper semaphore.
250ac13930bSmikeb  * Returns error code
251ac13930bSmikeb  **/
252ac13930bSmikeb int32_t ixgbe_reset_cs4227(struct ixgbe_hw *hw)
253ac13930bSmikeb {
254ac13930bSmikeb 	int32_t status;
255ac13930bSmikeb 	uint32_t retry;
256ac13930bSmikeb 	uint16_t value;
257ac13930bSmikeb 	uint8_t reg;
258ac13930bSmikeb 
259ac13930bSmikeb 	/* Trigger hard reset. */
260ac13930bSmikeb 	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
261ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
262ac13930bSmikeb 		return status;
263ac13930bSmikeb 	reg |= IXGBE_PE_BIT1;
264ac13930bSmikeb 	status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
265ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
266ac13930bSmikeb 		return status;
267ac13930bSmikeb 
268ac13930bSmikeb 	status = ixgbe_read_pe(hw, IXGBE_PE_CONFIG, &reg);
269ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
270ac13930bSmikeb 		return status;
271ac13930bSmikeb 	reg &= ~IXGBE_PE_BIT1;
272ac13930bSmikeb 	status = ixgbe_write_pe(hw, IXGBE_PE_CONFIG, reg);
273ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
274ac13930bSmikeb 		return status;
275ac13930bSmikeb 
276ac13930bSmikeb 	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
277ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
278ac13930bSmikeb 		return status;
279ac13930bSmikeb 	reg &= ~IXGBE_PE_BIT1;
280ac13930bSmikeb 	status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
281ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
282ac13930bSmikeb 		return status;
283ac13930bSmikeb 
284ac13930bSmikeb 	usec_delay(IXGBE_CS4227_RESET_HOLD);
285ac13930bSmikeb 
286ac13930bSmikeb 	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
287ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
288ac13930bSmikeb 		return status;
289ac13930bSmikeb 	reg |= IXGBE_PE_BIT1;
290ac13930bSmikeb 	status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
291ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
292ac13930bSmikeb 		return status;
293ac13930bSmikeb 
294ac13930bSmikeb 	/* Wait for the reset to complete. */
295ac13930bSmikeb 	msec_delay(IXGBE_CS4227_RESET_DELAY);
296ac13930bSmikeb 	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
297ac13930bSmikeb 		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EFUSE_STATUS,
298ac13930bSmikeb 					   &value);
299ac13930bSmikeb 		if (status == IXGBE_SUCCESS &&
300ac13930bSmikeb 		    value == IXGBE_CS4227_EEPROM_LOAD_OK)
301ac13930bSmikeb 			break;
302ac13930bSmikeb 		msec_delay(IXGBE_CS4227_CHECK_DELAY);
303ac13930bSmikeb 	}
304ac13930bSmikeb 	if (retry == IXGBE_CS4227_RETRIES) {
305d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
306d7a8f955Sjmatthew 			"CS4227 reset did not complete.");
307ac13930bSmikeb 		return IXGBE_ERR_PHY;
308ac13930bSmikeb 	}
309ac13930bSmikeb 
310ac13930bSmikeb 	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value);
311ac13930bSmikeb 	if (status != IXGBE_SUCCESS ||
312ac13930bSmikeb 	    !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) {
313d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
314d7a8f955Sjmatthew 			"CS4227 EEPROM did not load successfully.");
315ac13930bSmikeb 		return IXGBE_ERR_PHY;
316ac13930bSmikeb 	}
317ac13930bSmikeb 
318ac13930bSmikeb 	return IXGBE_SUCCESS;
319ac13930bSmikeb }
320ac13930bSmikeb 
321ac13930bSmikeb /**
322ac13930bSmikeb  * ixgbe_check_cs4227 - Check CS4227 and reset as needed
323ac13930bSmikeb  * @hw: pointer to hardware structure
324ac13930bSmikeb  **/
325ac13930bSmikeb void ixgbe_check_cs4227(struct ixgbe_hw *hw)
326ac13930bSmikeb {
327ac13930bSmikeb 	int32_t status = IXGBE_SUCCESS;
328ac13930bSmikeb 	uint32_t swfw_mask = hw->phy.phy_semaphore_mask;
329ac13930bSmikeb 	uint16_t value = 0;
330ac13930bSmikeb 	uint8_t retry;
331ac13930bSmikeb 
332ac13930bSmikeb 	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
333ac13930bSmikeb 		status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
334ac13930bSmikeb 		if (status != IXGBE_SUCCESS) {
335d7a8f955Sjmatthew 			ERROR_REPORT2(IXGBE_ERROR_CAUTION,
336d7a8f955Sjmatthew 				"semaphore failed with %d", status);
337ac13930bSmikeb 			msec_delay(IXGBE_CS4227_CHECK_DELAY);
338ac13930bSmikeb 			continue;
339ac13930bSmikeb 		}
340ac13930bSmikeb 
341ac13930bSmikeb 		/* Get status of reset flow. */
342ac13930bSmikeb 		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
343ac13930bSmikeb 
344ac13930bSmikeb 		if (status == IXGBE_SUCCESS &&
345ac13930bSmikeb 		    value == IXGBE_CS4227_RESET_COMPLETE)
346ac13930bSmikeb 			goto out;
347ac13930bSmikeb 
348ac13930bSmikeb 		if (status != IXGBE_SUCCESS ||
349ac13930bSmikeb 		    value != IXGBE_CS4227_RESET_PENDING)
350ac13930bSmikeb 			break;
351ac13930bSmikeb 
352ac13930bSmikeb 		/* Reset is pending. Wait and check again. */
353ac13930bSmikeb 		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
354ac13930bSmikeb 		msec_delay(IXGBE_CS4227_CHECK_DELAY);
355ac13930bSmikeb 	}
356ac13930bSmikeb 
357ac13930bSmikeb 	/* If still pending, assume other instance failed. */
358ac13930bSmikeb 	if (retry == IXGBE_CS4227_RETRIES) {
359ac13930bSmikeb 		status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
360ac13930bSmikeb 		if (status != IXGBE_SUCCESS) {
361d7a8f955Sjmatthew 			ERROR_REPORT2(IXGBE_ERROR_CAUTION,
362d7a8f955Sjmatthew 				      "semaphore failed with %d", status);
363ac13930bSmikeb 			return;
364ac13930bSmikeb 		}
365ac13930bSmikeb 	}
366ac13930bSmikeb 
367ac13930bSmikeb 	/* Reset the CS4227. */
368ac13930bSmikeb 	status = ixgbe_reset_cs4227(hw);
369ac13930bSmikeb 	if (status != IXGBE_SUCCESS) {
370d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
371d7a8f955Sjmatthew 			"CS4227 reset failed: %d", status);
372ac13930bSmikeb 		goto out;
373ac13930bSmikeb 	}
374ac13930bSmikeb 
375ac13930bSmikeb 	/* Reset takes so long, temporarily release semaphore in case the
376ac13930bSmikeb 	 * other driver instance is waiting for the reset indication.
377ac13930bSmikeb 	 */
378ac13930bSmikeb 	ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
379ac13930bSmikeb 			   IXGBE_CS4227_RESET_PENDING);
380ac13930bSmikeb 	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
381ac13930bSmikeb 	msec_delay(10);
382ac13930bSmikeb 	status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
383ac13930bSmikeb 	if (status != IXGBE_SUCCESS) {
384d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
385d7a8f955Sjmatthew 			"semaphore failed with %d", status);
386ac13930bSmikeb 		return;
387ac13930bSmikeb 	}
388ac13930bSmikeb 
389ac13930bSmikeb 	/* Record completion for next time. */
390ac13930bSmikeb 	status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
391ac13930bSmikeb 		IXGBE_CS4227_RESET_COMPLETE);
392ac13930bSmikeb 
393ac13930bSmikeb out:
394ac13930bSmikeb 	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
395ac13930bSmikeb 	msec_delay(hw->eeprom.semaphore_delay);
396ac13930bSmikeb }
397ac13930bSmikeb 
398ac13930bSmikeb /**
399ac13930bSmikeb  * ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control
400ac13930bSmikeb  * @hw: pointer to hardware structure
401ac13930bSmikeb  **/
402ac13930bSmikeb void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw)
403ac13930bSmikeb {
404ac13930bSmikeb 	uint32_t esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
405ac13930bSmikeb 
406ac13930bSmikeb 	if (hw->bus.lan_id) {
407ac13930bSmikeb 		esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
408ac13930bSmikeb 		esdp |= IXGBE_ESDP_SDP1_DIR;
409ac13930bSmikeb 	}
410ac13930bSmikeb 	esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
411ac13930bSmikeb 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
412ac13930bSmikeb 	IXGBE_WRITE_FLUSH(hw);
413ac13930bSmikeb }
414ac13930bSmikeb 
415ac13930bSmikeb /**
416ac13930bSmikeb  * ixgbe_identify_phy_x550em - Get PHY type based on device id
417ac13930bSmikeb  * @hw: pointer to hardware structure
418ac13930bSmikeb  *
419ac13930bSmikeb  * Returns error code
420ac13930bSmikeb  */
421ac13930bSmikeb int32_t ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
422ac13930bSmikeb {
423d7a8f955Sjmatthew 	hw->mac.ops.set_lan_id(hw);
424d7a8f955Sjmatthew 
425d7a8f955Sjmatthew 	ixgbe_read_mng_if_sel_x550em(hw);
4261544f1b6Smikeb 
427ac13930bSmikeb 	switch (hw->device_id) {
428d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SFP:
429d7a8f955Sjmatthew 		return ixgbe_identify_module_generic(hw);
430ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_SFP:
431ac13930bSmikeb 		/* set up for CS4227 usage */
432ac13930bSmikeb 		ixgbe_setup_mux_ctl(hw);
433ac13930bSmikeb 		ixgbe_check_cs4227(hw);
434d7a8f955Sjmatthew 		/* Fallthrough */
435ac13930bSmikeb 
436d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SFP_N:
437d7a8f955Sjmatthew 		return ixgbe_identify_module_generic(hw);
438ac13930bSmikeb 		break;
439ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_KX4:
440ac13930bSmikeb 		hw->phy.type = ixgbe_phy_x550em_kx4;
441ac13930bSmikeb 		break;
442d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_XFI:
443d7a8f955Sjmatthew 		hw->phy.type = ixgbe_phy_x550em_xfi;
444d7a8f955Sjmatthew 		break;
445ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_KR:
446d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_KR:
447d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_KR_L:
448ac13930bSmikeb 		hw->phy.type = ixgbe_phy_x550em_kr;
449ac13930bSmikeb 		break;
450d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_10G_T:
451ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_10G_T:
452ac13930bSmikeb 		return ixgbe_identify_phy_generic(hw);
453d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_1G_T:
454d7a8f955Sjmatthew 		hw->phy.type = ixgbe_phy_ext_1g_t;
455d7a8f955Sjmatthew 		break;
456d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T:
457d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
458d7a8f955Sjmatthew 		hw->phy.type = ixgbe_phy_fw;
459d7a8f955Sjmatthew 		if (hw->bus.lan_id)
460d7a8f955Sjmatthew 			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
461d7a8f955Sjmatthew 		else
462d7a8f955Sjmatthew 			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
463d7a8f955Sjmatthew 		break;
464ac13930bSmikeb 	default:
465ac13930bSmikeb 		break;
466ac13930bSmikeb 	}
467ac13930bSmikeb 	return IXGBE_SUCCESS;
468ac13930bSmikeb }
469ac13930bSmikeb 
470d7a8f955Sjmatthew /**
471d7a8f955Sjmatthew  * ixgbe_fw_phy_activity - Perform an activity on a PHY
472d7a8f955Sjmatthew  * @hw: pointer to hardware structure
473d7a8f955Sjmatthew  * @activity: activity to perform
474d7a8f955Sjmatthew  * @data: Pointer to 4 32-bit words of data
475d7a8f955Sjmatthew  */
476d7a8f955Sjmatthew int32_t ixgbe_fw_phy_activity(struct ixgbe_hw *hw, uint16_t activity,
477d7a8f955Sjmatthew 			  uint32_t (*data)[FW_PHY_ACT_DATA_COUNT])
478d7a8f955Sjmatthew {
479d7a8f955Sjmatthew 	union {
480d7a8f955Sjmatthew 		struct ixgbe_hic_phy_activity_req cmd;
481d7a8f955Sjmatthew 		struct ixgbe_hic_phy_activity_resp rsp;
482d7a8f955Sjmatthew 	} hic;
483d7a8f955Sjmatthew 	uint16_t retries = FW_PHY_ACT_RETRIES;
484d7a8f955Sjmatthew 	int32_t rc;
485d7a8f955Sjmatthew 	uint16_t i;
486d7a8f955Sjmatthew 
487d7a8f955Sjmatthew 	do {
488d7a8f955Sjmatthew 		memset(&hic, 0, sizeof(hic));
489d7a8f955Sjmatthew 		hic.cmd.hdr.cmd = FW_PHY_ACT_REQ_CMD;
490d7a8f955Sjmatthew 		hic.cmd.hdr.buf_len = FW_PHY_ACT_REQ_LEN;
491d7a8f955Sjmatthew 		hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
492d7a8f955Sjmatthew 		hic.cmd.port_number = hw->bus.lan_id;
493d7a8f955Sjmatthew 		hic.cmd.activity_id = htole16(activity);
494d7a8f955Sjmatthew 		for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i)
495d7a8f955Sjmatthew 			hic.cmd.data[i] = htobe32((*data)[i]);
496d7a8f955Sjmatthew 
497d7a8f955Sjmatthew 		rc = ixgbe_host_interface_command(hw, (uint32_t *)&hic.cmd,
498d7a8f955Sjmatthew 						  sizeof(hic.cmd),
499d7a8f955Sjmatthew 						  IXGBE_HI_COMMAND_TIMEOUT,
500d7a8f955Sjmatthew 						  TRUE);
501d7a8f955Sjmatthew 		if (rc != IXGBE_SUCCESS)
502d7a8f955Sjmatthew 			return rc;
503d7a8f955Sjmatthew 		if (hic.rsp.hdr.cmd_or_resp.ret_status ==
504d7a8f955Sjmatthew 		    FW_CEM_RESP_STATUS_SUCCESS) {
505d7a8f955Sjmatthew 			for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i)
506d7a8f955Sjmatthew 				(*data)[i] = betoh32(hic.rsp.data[i]);
507d7a8f955Sjmatthew 			return IXGBE_SUCCESS;
508d7a8f955Sjmatthew 		}
509d7a8f955Sjmatthew 		usec_delay(20);
510d7a8f955Sjmatthew 		--retries;
511d7a8f955Sjmatthew 	} while (retries > 0);
512d7a8f955Sjmatthew 
513d7a8f955Sjmatthew 	return IXGBE_ERR_HOST_INTERFACE_COMMAND;
514d7a8f955Sjmatthew }
515d7a8f955Sjmatthew 
516d7a8f955Sjmatthew static const struct {
517d7a8f955Sjmatthew 	uint16_t fw_speed;
518d7a8f955Sjmatthew 	ixgbe_link_speed phy_speed;
519d7a8f955Sjmatthew } ixgbe_fw_map[] = {
520d7a8f955Sjmatthew 	{ FW_PHY_ACT_LINK_SPEED_10, IXGBE_LINK_SPEED_10_FULL },
521d7a8f955Sjmatthew 	{ FW_PHY_ACT_LINK_SPEED_100, IXGBE_LINK_SPEED_100_FULL },
522d7a8f955Sjmatthew 	{ FW_PHY_ACT_LINK_SPEED_1G, IXGBE_LINK_SPEED_1GB_FULL },
523d7a8f955Sjmatthew 	{ FW_PHY_ACT_LINK_SPEED_2_5G, IXGBE_LINK_SPEED_2_5GB_FULL },
524d7a8f955Sjmatthew 	{ FW_PHY_ACT_LINK_SPEED_5G, IXGBE_LINK_SPEED_5GB_FULL },
525d7a8f955Sjmatthew 	{ FW_PHY_ACT_LINK_SPEED_10G, IXGBE_LINK_SPEED_10GB_FULL },
526d7a8f955Sjmatthew };
527d7a8f955Sjmatthew 
528d7a8f955Sjmatthew /**
529d7a8f955Sjmatthew  * ixgbe_get_phy_id_fw - Get the phy ID via firmware command
530d7a8f955Sjmatthew  * @hw: pointer to hardware structure
531d7a8f955Sjmatthew  *
532d7a8f955Sjmatthew  * Returns error code
533d7a8f955Sjmatthew  */
534d7a8f955Sjmatthew int32_t ixgbe_get_phy_id_fw(struct ixgbe_hw *hw)
535d7a8f955Sjmatthew {
536d7a8f955Sjmatthew 	uint32_t info[FW_PHY_ACT_DATA_COUNT] = { 0 };
537d7a8f955Sjmatthew 	uint16_t phy_speeds;
538d7a8f955Sjmatthew 	uint16_t phy_id_lo;
539d7a8f955Sjmatthew 	int32_t rc;
540d7a8f955Sjmatthew 	uint16_t i;
541d7a8f955Sjmatthew 
542d7a8f955Sjmatthew 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_PHY_INFO, &info);
543d7a8f955Sjmatthew 	if (rc)
544d7a8f955Sjmatthew 		return rc;
545d7a8f955Sjmatthew 
546d7a8f955Sjmatthew 	hw->phy.speeds_supported = 0;
547d7a8f955Sjmatthew 	phy_speeds = info[0] & FW_PHY_INFO_SPEED_MASK;
548d7a8f955Sjmatthew 	for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) {
549d7a8f955Sjmatthew 		if (phy_speeds & ixgbe_fw_map[i].fw_speed)
550d7a8f955Sjmatthew 			hw->phy.speeds_supported |= ixgbe_fw_map[i].phy_speed;
551d7a8f955Sjmatthew 	}
552d7a8f955Sjmatthew 	if (!hw->phy.autoneg_advertised)
553d7a8f955Sjmatthew 		hw->phy.autoneg_advertised = hw->phy.speeds_supported;
554d7a8f955Sjmatthew 
555d7a8f955Sjmatthew 	hw->phy.id = info[0] & FW_PHY_INFO_ID_HI_MASK;
556d7a8f955Sjmatthew 	phy_id_lo = info[1] & FW_PHY_INFO_ID_LO_MASK;
557d7a8f955Sjmatthew 	hw->phy.id |= phy_id_lo & IXGBE_PHY_REVISION_MASK;
558d7a8f955Sjmatthew 	hw->phy.revision = phy_id_lo & ~IXGBE_PHY_REVISION_MASK;
559d7a8f955Sjmatthew 	if (!hw->phy.id || hw->phy.id == IXGBE_PHY_REVISION_MASK)
560d7a8f955Sjmatthew 		return IXGBE_ERR_PHY_ADDR_INVALID;
561d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
562d7a8f955Sjmatthew }
563d7a8f955Sjmatthew 
564d7a8f955Sjmatthew /**
565d7a8f955Sjmatthew  * ixgbe_identify_phy_fw - Get PHY type based on firmware command
566d7a8f955Sjmatthew  * @hw: pointer to hardware structure
567d7a8f955Sjmatthew  *
568d7a8f955Sjmatthew  * Returns error code
569d7a8f955Sjmatthew  */
570d7a8f955Sjmatthew int32_t ixgbe_identify_phy_fw(struct ixgbe_hw *hw)
571d7a8f955Sjmatthew {
572d7a8f955Sjmatthew 	if (hw->bus.lan_id)
573d7a8f955Sjmatthew 		hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM;
574d7a8f955Sjmatthew 	else
575d7a8f955Sjmatthew 		hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM;
576d7a8f955Sjmatthew 
577d7a8f955Sjmatthew 	hw->phy.type = ixgbe_phy_fw;
578d7a8f955Sjmatthew 	hw->phy.ops.read_reg = NULL;
579d7a8f955Sjmatthew 	hw->phy.ops.write_reg = NULL;
580d7a8f955Sjmatthew 	return ixgbe_get_phy_id_fw(hw);
581d7a8f955Sjmatthew }
582d7a8f955Sjmatthew 
583d7a8f955Sjmatthew /**
584d7a8f955Sjmatthew  * ixgbe_shutdown_fw_phy - Shutdown a firmware-controlled PHY
585d7a8f955Sjmatthew  * @hw: pointer to hardware structure
586d7a8f955Sjmatthew  *
587d7a8f955Sjmatthew  * Returns error code
588d7a8f955Sjmatthew  */
589d7a8f955Sjmatthew int32_t ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw)
590d7a8f955Sjmatthew {
591d7a8f955Sjmatthew 	uint32_t setup[FW_PHY_ACT_DATA_COUNT] = { 0 };
592d7a8f955Sjmatthew 
593d7a8f955Sjmatthew 	setup[0] = FW_PHY_ACT_FORCE_LINK_DOWN_OFF;
594d7a8f955Sjmatthew 	return ixgbe_fw_phy_activity(hw, FW_PHY_ACT_FORCE_LINK_DOWN, &setup);
595d7a8f955Sjmatthew }
596d7a8f955Sjmatthew 
597ac13930bSmikeb int32_t ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, uint32_t reg_addr,
598ac13930bSmikeb 				  uint32_t device_type, uint16_t *phy_data)
599ac13930bSmikeb {
600ac13930bSmikeb 	return IXGBE_NOT_IMPLEMENTED;
601ac13930bSmikeb }
602ac13930bSmikeb 
603ac13930bSmikeb int32_t ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, uint32_t reg_addr,
604ac13930bSmikeb 				   uint32_t device_type, uint16_t phy_data)
605ac13930bSmikeb {
606ac13930bSmikeb 	return IXGBE_NOT_IMPLEMENTED;
607ac13930bSmikeb }
608ac13930bSmikeb 
609ac13930bSmikeb /**
610ac13930bSmikeb *  ixgbe_init_ops_X550EM - Inits func ptrs and MAC type
611ac13930bSmikeb *  @hw: pointer to hardware structure
612ac13930bSmikeb *
613ac13930bSmikeb *  Initialize the function pointers and for MAC type X550EM.
614ac13930bSmikeb *  Does not touch the hardware.
615ac13930bSmikeb **/
616ac13930bSmikeb int32_t ixgbe_init_ops_X550EM(struct ixgbe_hw *hw)
617ac13930bSmikeb {
618ac13930bSmikeb 	struct ixgbe_mac_info *mac = &hw->mac;
619ac13930bSmikeb 	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
620ac13930bSmikeb 	struct ixgbe_phy_info *phy = &hw->phy;
621ac13930bSmikeb 	int32_t ret_val;
622ac13930bSmikeb 
623ac13930bSmikeb 	DEBUGFUNC("ixgbe_init_ops_X550EM");
624ac13930bSmikeb 
625ac13930bSmikeb 	/* Similar to X550 so start there. */
626ac13930bSmikeb 	ret_val = ixgbe_init_ops_X550(hw);
627ac13930bSmikeb 
628ac13930bSmikeb 	/* Since this function eventually calls
629ac13930bSmikeb 	 * ixgbe_init_ops_540 by design, we are setting
630ac13930bSmikeb 	 * the pointers to NULL explicitly here to overwrite
631ac13930bSmikeb 	 * the values being set in the x540 function.
632ac13930bSmikeb 	 */
633ac13930bSmikeb 
634ac13930bSmikeb 	/* IPsec not supported in x550EM */
635ac13930bSmikeb 	mac->ops.disable_sec_rx_path = NULL;
636ac13930bSmikeb 	mac->ops.enable_sec_rx_path = NULL;
637ac13930bSmikeb 
638ac13930bSmikeb 	/* AUTOC register is not present in x550EM. */
639ac13930bSmikeb 	mac->ops.prot_autoc_read = NULL;
640ac13930bSmikeb 	mac->ops.prot_autoc_write = NULL;
641ac13930bSmikeb 
642ac13930bSmikeb 	/* X550EM bus type is internal*/
643ac13930bSmikeb 	hw->bus.type = ixgbe_bus_type_internal;
644ac13930bSmikeb 	mac->ops.get_bus_info = ixgbe_get_bus_info_X550em;
645ac13930bSmikeb 
646d7a8f955Sjmatthew 
647ac13930bSmikeb 	mac->ops.get_media_type = ixgbe_get_media_type_X550em;
648ac13930bSmikeb 	mac->ops.setup_sfp = ixgbe_setup_sfp_modules_X550em;
649ac13930bSmikeb 	mac->ops.get_link_capabilities = ixgbe_get_link_capabilities_X550em;
650ac13930bSmikeb 	mac->ops.reset_hw = ixgbe_reset_hw_X550em;
651ac13930bSmikeb 	mac->ops.get_supported_physical_layer =
652ac13930bSmikeb 				    ixgbe_get_supported_physical_layer_X550em;
653ac13930bSmikeb 
654ac13930bSmikeb 	if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
655ac13930bSmikeb 		mac->ops.setup_fc = ixgbe_setup_fc_generic;
656ac13930bSmikeb 	else
657ac13930bSmikeb 		mac->ops.setup_fc = ixgbe_setup_fc_X550em;
658ac13930bSmikeb 
659ac13930bSmikeb 	/* PHY */
660ac13930bSmikeb 	phy->ops.init = ixgbe_init_phy_ops_X550em;
661d7a8f955Sjmatthew 	switch (hw->device_id) {
662d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T:
663d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
664d7a8f955Sjmatthew 		mac->ops.setup_fc = NULL;
665d7a8f955Sjmatthew 		phy->ops.identify = ixgbe_identify_phy_fw;
666d7a8f955Sjmatthew 		phy->ops.set_phy_power = NULL;
667d7a8f955Sjmatthew 		phy->ops.get_firmware_version = NULL;
668d7a8f955Sjmatthew 		break;
669d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_1G_T:
670d7a8f955Sjmatthew 		mac->ops.setup_fc = NULL;
671ac13930bSmikeb 		phy->ops.identify = ixgbe_identify_phy_x550em;
672d7a8f955Sjmatthew 		phy->ops.set_phy_power = NULL;
673d7a8f955Sjmatthew 		break;
674d7a8f955Sjmatthew 	default:
675d7a8f955Sjmatthew 		phy->ops.identify = ixgbe_identify_phy_x550em;
676d7a8f955Sjmatthew 	}
677d7a8f955Sjmatthew 
678ac13930bSmikeb 	if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper)
679ac13930bSmikeb 		phy->ops.set_phy_power = NULL;
680ac13930bSmikeb 
681ac13930bSmikeb 
682ac13930bSmikeb 	/* EEPROM */
683ac13930bSmikeb 	eeprom->ops.init_params = ixgbe_init_eeprom_params_X540;
684ac13930bSmikeb 	eeprom->ops.read = ixgbe_read_ee_hostif_X550;
685ac13930bSmikeb 	eeprom->ops.write = ixgbe_write_ee_hostif_X550;
686ac13930bSmikeb 	eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550;
687ac13930bSmikeb 	eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550;
688ac13930bSmikeb 	eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550;
689ac13930bSmikeb 
690ac13930bSmikeb 	return ret_val;
691ac13930bSmikeb }
692ac13930bSmikeb 
693ac13930bSmikeb /**
694d7a8f955Sjmatthew  * ixgbe_setup_fw_link - Setup firmware-controlled PHYs
695d7a8f955Sjmatthew  * @hw: pointer to hardware structure
696d7a8f955Sjmatthew  */
697d7a8f955Sjmatthew int32_t ixgbe_setup_fw_link(struct ixgbe_hw *hw)
698d7a8f955Sjmatthew {
699d7a8f955Sjmatthew 	uint32_t setup[FW_PHY_ACT_DATA_COUNT] = { 0 };
700d7a8f955Sjmatthew 	int32_t rc;
701d7a8f955Sjmatthew 	uint16_t i;
702d7a8f955Sjmatthew 
703d7a8f955Sjmatthew 	if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw))
704d7a8f955Sjmatthew 		return 0;
705d7a8f955Sjmatthew 
706d7a8f955Sjmatthew 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
707d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
708d7a8f955Sjmatthew 			      "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
709d7a8f955Sjmatthew 		return IXGBE_ERR_INVALID_LINK_SETTINGS;
710d7a8f955Sjmatthew 	}
711d7a8f955Sjmatthew 
712d7a8f955Sjmatthew 	switch (hw->fc.requested_mode) {
713d7a8f955Sjmatthew 	case ixgbe_fc_full:
714d7a8f955Sjmatthew 		setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RXTX <<
715d7a8f955Sjmatthew 			    FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT;
716d7a8f955Sjmatthew 		break;
717d7a8f955Sjmatthew 	case ixgbe_fc_rx_pause:
718d7a8f955Sjmatthew 		setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RX <<
719d7a8f955Sjmatthew 			    FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT;
720d7a8f955Sjmatthew 		break;
721d7a8f955Sjmatthew 	case ixgbe_fc_tx_pause:
722d7a8f955Sjmatthew 		setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_TX <<
723d7a8f955Sjmatthew 			    FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT;
724d7a8f955Sjmatthew 		break;
725d7a8f955Sjmatthew 	default:
726d7a8f955Sjmatthew 		break;
727d7a8f955Sjmatthew 	}
728d7a8f955Sjmatthew 
729d7a8f955Sjmatthew 	for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) {
730d7a8f955Sjmatthew 		if (hw->phy.autoneg_advertised & ixgbe_fw_map[i].phy_speed)
731d7a8f955Sjmatthew 			setup[0] |= ixgbe_fw_map[i].fw_speed;
732d7a8f955Sjmatthew 	}
733d7a8f955Sjmatthew 	setup[0] |= FW_PHY_ACT_SETUP_LINK_HP | FW_PHY_ACT_SETUP_LINK_AN;
734d7a8f955Sjmatthew 
735d7a8f955Sjmatthew 	if (hw->phy.eee_speeds_advertised)
736d7a8f955Sjmatthew 		setup[0] |= FW_PHY_ACT_SETUP_LINK_EEE;
737d7a8f955Sjmatthew 
738d7a8f955Sjmatthew 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup);
739d7a8f955Sjmatthew 	if (rc)
740d7a8f955Sjmatthew 		return rc;
741d7a8f955Sjmatthew 	if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN)
742d7a8f955Sjmatthew 		return IXGBE_ERR_OVERTEMP;
743d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
744d7a8f955Sjmatthew }
745d7a8f955Sjmatthew 
746d7a8f955Sjmatthew /**
747d7a8f955Sjmatthew  * ixgbe_fc_autoneg_fw _ Set up flow control for FW-controlled PHYs
748d7a8f955Sjmatthew  * @hw: pointer to hardware structure
749d7a8f955Sjmatthew  *
750d7a8f955Sjmatthew  *  Called at init time to set up flow control.
751d7a8f955Sjmatthew  */
752d7a8f955Sjmatthew int32_t ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw)
753d7a8f955Sjmatthew {
754d7a8f955Sjmatthew 	if (hw->fc.requested_mode == ixgbe_fc_default)
755d7a8f955Sjmatthew 		hw->fc.requested_mode = ixgbe_fc_full;
756d7a8f955Sjmatthew 
757d7a8f955Sjmatthew 	return ixgbe_setup_fw_link(hw);
758d7a8f955Sjmatthew }
759d7a8f955Sjmatthew 
760d7a8f955Sjmatthew /**
761d7a8f955Sjmatthew  * ixgbe_setup_eee_fw - Enable/disable EEE support
762d7a8f955Sjmatthew  * @hw: pointer to the HW structure
763d7a8f955Sjmatthew  * @enable_eee: boolean flag to enable EEE
764d7a8f955Sjmatthew  *
765d7a8f955Sjmatthew  * Enable/disable EEE based on enable_eee flag.
766d7a8f955Sjmatthew  * This function controls EEE for firmware-based PHY implementations.
767d7a8f955Sjmatthew  */
768d7a8f955Sjmatthew int32_t ixgbe_setup_eee_fw(struct ixgbe_hw *hw, bool enable_eee)
769d7a8f955Sjmatthew {
770d7a8f955Sjmatthew 	if (!!hw->phy.eee_speeds_advertised == enable_eee)
771d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
772d7a8f955Sjmatthew 	if (enable_eee)
773d7a8f955Sjmatthew 		hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
774d7a8f955Sjmatthew 	else
775d7a8f955Sjmatthew 		hw->phy.eee_speeds_advertised = 0;
776d7a8f955Sjmatthew 	return hw->phy.ops.setup_link(hw);
777d7a8f955Sjmatthew }
778d7a8f955Sjmatthew 
779d7a8f955Sjmatthew /**
780d7a8f955Sjmatthew *  ixgbe_init_ops_X550EM_a - Inits func ptrs and MAC type
781d7a8f955Sjmatthew *  @hw: pointer to hardware structure
782d7a8f955Sjmatthew *
783d7a8f955Sjmatthew *  Initialize the function pointers and for MAC type X550EM_a.
784d7a8f955Sjmatthew *  Does not touch the hardware.
785d7a8f955Sjmatthew **/
786d7a8f955Sjmatthew int32_t ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw)
787d7a8f955Sjmatthew {
788d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
789d7a8f955Sjmatthew 	int32_t ret_val;
790d7a8f955Sjmatthew 
791d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_init_ops_X550EM_a");
792d7a8f955Sjmatthew 
793d7a8f955Sjmatthew 	/* Start with generic X550EM init */
794d7a8f955Sjmatthew 	ret_val = ixgbe_init_ops_X550EM(hw);
795d7a8f955Sjmatthew 
796d7a8f955Sjmatthew 	if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII ||
797d7a8f955Sjmatthew 	    hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L) {
798d7a8f955Sjmatthew 		mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550;
799d7a8f955Sjmatthew 		mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550;
800d7a8f955Sjmatthew 	} else {
801d7a8f955Sjmatthew 		mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550a;
802d7a8f955Sjmatthew 		mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550a;
803d7a8f955Sjmatthew 	}
804d7a8f955Sjmatthew 	mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550a;
805d7a8f955Sjmatthew 	mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550a;
806d7a8f955Sjmatthew 
807d7a8f955Sjmatthew 	switch (mac->ops.get_media_type(hw)) {
808d7a8f955Sjmatthew 	case ixgbe_media_type_fiber:
809d7a8f955Sjmatthew 		mac->ops.setup_fc = NULL;
810d7a8f955Sjmatthew 		mac->ops.fc_autoneg = ixgbe_fc_autoneg_fiber_x550em_a;
811d7a8f955Sjmatthew 		break;
812d7a8f955Sjmatthew 	case ixgbe_media_type_backplane:
813d7a8f955Sjmatthew 		mac->ops.fc_autoneg = ixgbe_fc_autoneg_backplane_x550em_a;
814d7a8f955Sjmatthew 		mac->ops.setup_fc = ixgbe_setup_fc_backplane_x550em_a;
815d7a8f955Sjmatthew 		break;
816d7a8f955Sjmatthew 	default:
817d7a8f955Sjmatthew 		break;
818d7a8f955Sjmatthew 	}
819d7a8f955Sjmatthew 
820d7a8f955Sjmatthew 	switch (hw->device_id) {
821d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T:
822d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
823d7a8f955Sjmatthew 		mac->ops.fc_autoneg = ixgbe_fc_autoneg_sgmii_x550em_a;
824d7a8f955Sjmatthew 		mac->ops.setup_fc = ixgbe_fc_autoneg_fw;
825d7a8f955Sjmatthew 		mac->ops.setup_eee = ixgbe_setup_eee_fw;
826d7a8f955Sjmatthew 		hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_100_FULL |
827d7a8f955Sjmatthew 					       IXGBE_LINK_SPEED_1GB_FULL;
828d7a8f955Sjmatthew 		hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
829d7a8f955Sjmatthew 		break;
830d7a8f955Sjmatthew 	default:
831d7a8f955Sjmatthew 		break;
832d7a8f955Sjmatthew 	}
833d7a8f955Sjmatthew 
834d7a8f955Sjmatthew 	return ret_val;
835d7a8f955Sjmatthew }
836d7a8f955Sjmatthew 
837d7a8f955Sjmatthew /**
838d7a8f955Sjmatthew *  ixgbe_init_ops_X550EM_x - Inits func ptrs and MAC type
839d7a8f955Sjmatthew *  @hw: pointer to hardware structure
840d7a8f955Sjmatthew *
841d7a8f955Sjmatthew *  Initialize the function pointers and for MAC type X550EM_x.
842d7a8f955Sjmatthew *  Does not touch the hardware.
843d7a8f955Sjmatthew **/
844d7a8f955Sjmatthew int32_t ixgbe_init_ops_X550EM_x(struct ixgbe_hw *hw)
845d7a8f955Sjmatthew {
846d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
847d7a8f955Sjmatthew 	struct ixgbe_link_info *link = &hw->link;
848d7a8f955Sjmatthew 	int32_t ret_val;
849d7a8f955Sjmatthew 
850d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_init_ops_X550EM_x");
851d7a8f955Sjmatthew 
852d7a8f955Sjmatthew 	/* Start with generic X550EM init */
853d7a8f955Sjmatthew 	ret_val = ixgbe_init_ops_X550EM(hw);
854d7a8f955Sjmatthew 
855d7a8f955Sjmatthew 	mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550;
856d7a8f955Sjmatthew 	mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550;
857d7a8f955Sjmatthew 	mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em;
858d7a8f955Sjmatthew 	mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em;
859d7a8f955Sjmatthew 	link->ops.read_link = ixgbe_read_i2c_combined_generic;
860d7a8f955Sjmatthew 	link->ops.read_link_unlocked = ixgbe_read_i2c_combined_generic_unlocked;
861d7a8f955Sjmatthew 	link->ops.write_link = ixgbe_write_i2c_combined_generic;
862d7a8f955Sjmatthew 	link->ops.write_link_unlocked =
863d7a8f955Sjmatthew 				      ixgbe_write_i2c_combined_generic_unlocked;
864d7a8f955Sjmatthew 	link->addr = IXGBE_CS4227;
865d7a8f955Sjmatthew 
866d7a8f955Sjmatthew 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_1G_T) {
867d7a8f955Sjmatthew 		mac->ops.setup_fc = NULL;
868d7a8f955Sjmatthew 		mac->ops.setup_eee = NULL;
869d7a8f955Sjmatthew 	}
870d7a8f955Sjmatthew 
871d7a8f955Sjmatthew 	return ret_val;
872d7a8f955Sjmatthew }
873d7a8f955Sjmatthew 
874d7a8f955Sjmatthew /**
875d7a8f955Sjmatthew  *  ixgbe_dmac_config_X550
876d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
877d7a8f955Sjmatthew  *
878d7a8f955Sjmatthew  *  Configure DMA coalescing. If enabling dmac, dmac is activated.
879d7a8f955Sjmatthew  *  When disabling dmac, dmac enable dmac bit is cleared.
880d7a8f955Sjmatthew  **/
881d7a8f955Sjmatthew int32_t ixgbe_dmac_config_X550(struct ixgbe_hw *hw)
882d7a8f955Sjmatthew {
883d7a8f955Sjmatthew 	uint32_t reg;
884d7a8f955Sjmatthew 
885d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_dmac_config_X550");
886d7a8f955Sjmatthew 
887d7a8f955Sjmatthew 	/* Disable DMA coalescing before configuring */
888d7a8f955Sjmatthew 	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
889d7a8f955Sjmatthew 	reg &= ~IXGBE_DMACR_DMAC_EN;
890d7a8f955Sjmatthew 	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
891d7a8f955Sjmatthew 
892d7a8f955Sjmatthew 	/* Disable DMA Coalescing if the watchdog timer is 0 */
893d7a8f955Sjmatthew 	if (!hw->mac.dmac_config.watchdog_timer)
894d7a8f955Sjmatthew 		goto out;
895d7a8f955Sjmatthew 
896d7a8f955Sjmatthew 	ixgbe_dmac_config_tcs_X550(hw);
897d7a8f955Sjmatthew 
898d7a8f955Sjmatthew 	/* Configure DMA Coalescing Control Register */
899d7a8f955Sjmatthew 	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
900d7a8f955Sjmatthew 
901d7a8f955Sjmatthew 	/* Set the watchdog timer in units of 40.96 usec */
902d7a8f955Sjmatthew 	reg &= ~IXGBE_DMACR_DMACWT_MASK;
903d7a8f955Sjmatthew 	reg |= (hw->mac.dmac_config.watchdog_timer * 100) / 4096;
904d7a8f955Sjmatthew 
905d7a8f955Sjmatthew 	reg &= ~IXGBE_DMACR_HIGH_PRI_TC_MASK;
906d7a8f955Sjmatthew 	reg |= IXGBE_DMACR_EN_MNG_IND;
907d7a8f955Sjmatthew 
908d7a8f955Sjmatthew 	/* Enable DMA coalescing after configuration */
909d7a8f955Sjmatthew 	reg |= IXGBE_DMACR_DMAC_EN;
910d7a8f955Sjmatthew 	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
911d7a8f955Sjmatthew 
912d7a8f955Sjmatthew out:
913d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
914d7a8f955Sjmatthew }
915d7a8f955Sjmatthew 
916d7a8f955Sjmatthew /**
917d7a8f955Sjmatthew  *  ixgbe_dmac_config_tcs_X550
918d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
919d7a8f955Sjmatthew  *
920d7a8f955Sjmatthew  *  Configure DMA coalescing threshold per TC. The dmac enable bit must
921d7a8f955Sjmatthew  *  be cleared before configuring.
922d7a8f955Sjmatthew  **/
923d7a8f955Sjmatthew int32_t ixgbe_dmac_config_tcs_X550(struct ixgbe_hw *hw)
924d7a8f955Sjmatthew {
925d7a8f955Sjmatthew 	uint32_t tc, reg, pb_headroom, rx_pb_size, maxframe_size_kb;
926d7a8f955Sjmatthew 
927d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_dmac_config_tcs_X550");
928d7a8f955Sjmatthew 
929d7a8f955Sjmatthew 	/* Configure DMA coalescing enabled */
930d7a8f955Sjmatthew 	switch (hw->mac.dmac_config.link_speed) {
931d7a8f955Sjmatthew 	case IXGBE_LINK_SPEED_10_FULL:
932d7a8f955Sjmatthew 	case IXGBE_LINK_SPEED_100_FULL:
933d7a8f955Sjmatthew 		pb_headroom = IXGBE_DMACRXT_100M;
934d7a8f955Sjmatthew 		break;
935d7a8f955Sjmatthew 	case IXGBE_LINK_SPEED_1GB_FULL:
936d7a8f955Sjmatthew 		pb_headroom = IXGBE_DMACRXT_1G;
937d7a8f955Sjmatthew 		break;
938d7a8f955Sjmatthew 	default:
939d7a8f955Sjmatthew 		pb_headroom = IXGBE_DMACRXT_10G;
940d7a8f955Sjmatthew 		break;
941d7a8f955Sjmatthew 	}
942d7a8f955Sjmatthew 
943d7a8f955Sjmatthew 	maxframe_size_kb = ((IXGBE_READ_REG(hw, IXGBE_MAXFRS) >>
944d7a8f955Sjmatthew 			     IXGBE_MHADD_MFS_SHIFT) / 1024);
945d7a8f955Sjmatthew 
946d7a8f955Sjmatthew 	/* Set the per Rx packet buffer receive threshold */
947d7a8f955Sjmatthew 	for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) {
948d7a8f955Sjmatthew 		reg = IXGBE_READ_REG(hw, IXGBE_DMCTH(tc));
949d7a8f955Sjmatthew 		reg &= ~IXGBE_DMCTH_DMACRXT_MASK;
950d7a8f955Sjmatthew 
951d7a8f955Sjmatthew 		if (tc < hw->mac.dmac_config.num_tcs) {
952d7a8f955Sjmatthew 			/* Get Rx PB size */
953d7a8f955Sjmatthew 			rx_pb_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(tc));
954d7a8f955Sjmatthew 			rx_pb_size = (rx_pb_size & IXGBE_RXPBSIZE_MASK) >>
955d7a8f955Sjmatthew 				IXGBE_RXPBSIZE_SHIFT;
956d7a8f955Sjmatthew 
957d7a8f955Sjmatthew 			/* Calculate receive buffer threshold in kilobytes */
958d7a8f955Sjmatthew 			if (rx_pb_size > pb_headroom)
959d7a8f955Sjmatthew 				rx_pb_size = rx_pb_size - pb_headroom;
960d7a8f955Sjmatthew 			else
961d7a8f955Sjmatthew 				rx_pb_size = 0;
962d7a8f955Sjmatthew 
963d7a8f955Sjmatthew 			/* Minimum of MFS shall be set for DMCTH */
964d7a8f955Sjmatthew 			reg |= (rx_pb_size > maxframe_size_kb) ?
965d7a8f955Sjmatthew 				rx_pb_size : maxframe_size_kb;
966d7a8f955Sjmatthew 		}
967d7a8f955Sjmatthew 		IXGBE_WRITE_REG(hw, IXGBE_DMCTH(tc), reg);
968d7a8f955Sjmatthew 	}
969d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
970d7a8f955Sjmatthew }
971d7a8f955Sjmatthew 
972d7a8f955Sjmatthew /**
973d7a8f955Sjmatthew  *  ixgbe_dmac_update_tcs_X550
974d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
975d7a8f955Sjmatthew  *
976d7a8f955Sjmatthew  *  Disables dmac, updates per TC settings, and then enables dmac.
977d7a8f955Sjmatthew  **/
978d7a8f955Sjmatthew int32_t ixgbe_dmac_update_tcs_X550(struct ixgbe_hw *hw)
979d7a8f955Sjmatthew {
980d7a8f955Sjmatthew 	uint32_t reg;
981d7a8f955Sjmatthew 
982d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_dmac_update_tcs_X550");
983d7a8f955Sjmatthew 
984d7a8f955Sjmatthew 	/* Disable DMA coalescing before configuring */
985d7a8f955Sjmatthew 	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
986d7a8f955Sjmatthew 	reg &= ~IXGBE_DMACR_DMAC_EN;
987d7a8f955Sjmatthew 	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
988d7a8f955Sjmatthew 
989d7a8f955Sjmatthew 	ixgbe_dmac_config_tcs_X550(hw);
990d7a8f955Sjmatthew 
991d7a8f955Sjmatthew 	/* Enable DMA coalescing after configuration */
992d7a8f955Sjmatthew 	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
993d7a8f955Sjmatthew 	reg |= IXGBE_DMACR_DMAC_EN;
994d7a8f955Sjmatthew 	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
995d7a8f955Sjmatthew 
996d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
997d7a8f955Sjmatthew }
998d7a8f955Sjmatthew 
999d7a8f955Sjmatthew /**
1000ac13930bSmikeb  *  ixgbe_init_eeprom_params_X550 - Initialize EEPROM params
1001ac13930bSmikeb  *  @hw: pointer to hardware structure
1002ac13930bSmikeb  *
1003ac13930bSmikeb  *  Initializes the EEPROM parameters ixgbe_eeprom_info within the
1004ac13930bSmikeb  *  ixgbe_hw struct in order to set up EEPROM access.
1005ac13930bSmikeb  **/
1006ac13930bSmikeb int32_t ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
1007ac13930bSmikeb {
1008ac13930bSmikeb 	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
1009ac13930bSmikeb 	uint32_t eec;
1010ac13930bSmikeb 	uint16_t eeprom_size;
1011ac13930bSmikeb 
1012ac13930bSmikeb 	DEBUGFUNC("ixgbe_init_eeprom_params_X550");
1013ac13930bSmikeb 
1014ac13930bSmikeb 	if (eeprom->type == ixgbe_eeprom_uninitialized) {
1015ac13930bSmikeb 		eeprom->semaphore_delay = 10;
1016ac13930bSmikeb 		eeprom->type = ixgbe_flash;
1017ac13930bSmikeb 
1018ac13930bSmikeb 		eec = IXGBE_READ_REG(hw, IXGBE_EEC);
1019ac13930bSmikeb 		eeprom_size = (uint16_t)((eec & IXGBE_EEC_SIZE) >>
1020ac13930bSmikeb 				    IXGBE_EEC_SIZE_SHIFT);
1021ac13930bSmikeb 		eeprom->word_size = 1 << (eeprom_size +
1022ac13930bSmikeb 					  IXGBE_EEPROM_WORD_SIZE_SHIFT);
1023ac13930bSmikeb 
1024ac13930bSmikeb 		DEBUGOUT2("Eeprom params: type = %d, size = %d\n",
1025ac13930bSmikeb 			  eeprom->type, eeprom->word_size);
1026ac13930bSmikeb 	}
1027ac13930bSmikeb 
1028ac13930bSmikeb 	return IXGBE_SUCCESS;
1029ac13930bSmikeb }
1030ac13930bSmikeb 
1031ac13930bSmikeb /**
10324b1a56afSjsg  * ixgbe_set_source_address_pruning_X550 - Enable/Disable source address pruning
1033d7a8f955Sjmatthew  * @hw: pointer to hardware structure
1034d7a8f955Sjmatthew  * @enable: enable or disable source address pruning
1035d7a8f955Sjmatthew  * @pool: Rx pool to set source address pruning for
1036d7a8f955Sjmatthew  **/
1037d7a8f955Sjmatthew void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable,
1038d7a8f955Sjmatthew 					   unsigned int pool)
1039d7a8f955Sjmatthew {
1040d7a8f955Sjmatthew 	uint64_t pfflp;
1041d7a8f955Sjmatthew 
1042d7a8f955Sjmatthew 	/* max rx pool is 63 */
1043d7a8f955Sjmatthew 	if (pool > 63)
1044d7a8f955Sjmatthew 		return;
1045d7a8f955Sjmatthew 
1046d7a8f955Sjmatthew 	pfflp = (uint64_t)IXGBE_READ_REG(hw, IXGBE_PFFLPL);
1047d7a8f955Sjmatthew 	pfflp |= (uint64_t)IXGBE_READ_REG(hw, IXGBE_PFFLPH) << 32;
1048d7a8f955Sjmatthew 
1049d7a8f955Sjmatthew 	if (enable)
1050d7a8f955Sjmatthew 		pfflp |= (1ULL << pool);
1051d7a8f955Sjmatthew 	else
1052d7a8f955Sjmatthew 		pfflp &= ~(1ULL << pool);
1053d7a8f955Sjmatthew 
1054d7a8f955Sjmatthew 	IXGBE_WRITE_REG(hw, IXGBE_PFFLPL, (uint32_t)pfflp);
1055d7a8f955Sjmatthew 	IXGBE_WRITE_REG(hw, IXGBE_PFFLPH, (uint32_t)(pfflp >> 32));
1056d7a8f955Sjmatthew }
1057d7a8f955Sjmatthew 
1058d7a8f955Sjmatthew /**
1059ac13930bSmikeb  * ixgbe_iosf_wait - Wait for IOSF command completion
1060ac13930bSmikeb  * @hw: pointer to hardware structure
1061ac13930bSmikeb  * @ctrl: pointer to location to receive final IOSF control value
1062ac13930bSmikeb  *
1063ac13930bSmikeb  * Returns failing status on timeout
1064ac13930bSmikeb  *
1065ac13930bSmikeb  * Note: ctrl can be NULL if the IOSF control register value is not needed
1066ac13930bSmikeb  **/
1067ac13930bSmikeb int32_t ixgbe_iosf_wait(struct ixgbe_hw *hw, uint32_t *ctrl)
1068ac13930bSmikeb {
1069ac13930bSmikeb 	uint32_t i, command = 0;
1070ac13930bSmikeb 
1071ac13930bSmikeb 	/* Check every 10 usec to see if the address cycle completed.
1072ac13930bSmikeb 	 * The SB IOSF BUSY bit will clear when the operation is
1073ac13930bSmikeb 	 * complete
1074ac13930bSmikeb 	 */
1075ac13930bSmikeb 	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
1076ac13930bSmikeb 		command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
1077ac13930bSmikeb 		if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
1078ac13930bSmikeb 			break;
1079ac13930bSmikeb 		usec_delay(10);
1080ac13930bSmikeb 	}
1081ac13930bSmikeb 	if (ctrl)
1082ac13930bSmikeb 		*ctrl = command;
1083ac13930bSmikeb 	if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
1084d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_POLLING, "Wait timed out\n");
1085ac13930bSmikeb 		return IXGBE_ERR_PHY;
1086ac13930bSmikeb 	}
1087ac13930bSmikeb 
1088ac13930bSmikeb 	return IXGBE_SUCCESS;
1089ac13930bSmikeb }
1090ac13930bSmikeb 
1091ac13930bSmikeb /**
1092d7a8f955Sjmatthew  *  ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register
1093d7a8f955Sjmatthew  *  of the IOSF device
1094ac13930bSmikeb  *  @hw: pointer to hardware structure
1095ac13930bSmikeb  *  @reg_addr: 32 bit PHY register to write
1096ac13930bSmikeb  *  @device_type: 3 bit device type
1097ac13930bSmikeb  *  @data: Data to write to the register
1098ac13930bSmikeb  **/
1099ac13930bSmikeb int32_t ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, uint32_t reg_addr,
1100ac13930bSmikeb 			    uint32_t device_type, uint32_t data)
1101ac13930bSmikeb {
1102ac13930bSmikeb 	uint32_t gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
1103d7a8f955Sjmatthew 	uint32_t command, error __unused;
1104ac13930bSmikeb 	int32_t ret;
1105ac13930bSmikeb 
1106ac13930bSmikeb 	ret = hw->mac.ops.acquire_swfw_sync(hw, gssr);
1107ac13930bSmikeb 	if (ret != IXGBE_SUCCESS)
1108ac13930bSmikeb 		return ret;
1109ac13930bSmikeb 
1110ac13930bSmikeb 	ret = ixgbe_iosf_wait(hw, NULL);
1111ac13930bSmikeb 	if (ret != IXGBE_SUCCESS)
1112ac13930bSmikeb 		goto out;
1113ac13930bSmikeb 
1114ac13930bSmikeb 	command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
1115ac13930bSmikeb 		   (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
1116ac13930bSmikeb 
1117ac13930bSmikeb 	/* Write IOSF control register */
1118ac13930bSmikeb 	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
1119ac13930bSmikeb 
1120ac13930bSmikeb 	/* Write IOSF data register */
1121ac13930bSmikeb 	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data);
1122ac13930bSmikeb 
1123ac13930bSmikeb 	ret = ixgbe_iosf_wait(hw, &command);
1124ac13930bSmikeb 
1125ac13930bSmikeb 	if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
1126ac13930bSmikeb 		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
1127ac13930bSmikeb 			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
1128d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_POLLING,
1129d7a8f955Sjmatthew 			      "Failed to write, error %x\n", error);
1130ac13930bSmikeb 		ret = IXGBE_ERR_PHY;
1131ac13930bSmikeb 	}
1132ac13930bSmikeb 
1133ac13930bSmikeb out:
1134ac13930bSmikeb 	hw->mac.ops.release_swfw_sync(hw, gssr);
1135ac13930bSmikeb 	return ret;
1136ac13930bSmikeb }
1137ac13930bSmikeb 
1138ac13930bSmikeb /**
1139d7a8f955Sjmatthew  *  ixgbe_read_iosf_sb_reg_x550 - Reads specified register of the IOSF device
1140ac13930bSmikeb  *  @hw: pointer to hardware structure
1141ac13930bSmikeb  *  @reg_addr: 32 bit PHY register to write
1142ac13930bSmikeb  *  @device_type: 3 bit device type
1143d7a8f955Sjmatthew  *  @data: Pointer to read data from the register
1144ac13930bSmikeb  **/
1145ac13930bSmikeb int32_t ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, uint32_t reg_addr,
1146ac13930bSmikeb 			   uint32_t device_type, uint32_t *data)
1147ac13930bSmikeb {
1148ac13930bSmikeb 	uint32_t gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
1149d7a8f955Sjmatthew 	uint32_t command, error __unused;
1150ac13930bSmikeb 	int32_t ret;
1151ac13930bSmikeb 
1152ac13930bSmikeb 	ret = hw->mac.ops.acquire_swfw_sync(hw, gssr);
1153ac13930bSmikeb 	if (ret != IXGBE_SUCCESS)
1154ac13930bSmikeb 		return ret;
1155ac13930bSmikeb 
1156ac13930bSmikeb 	ret = ixgbe_iosf_wait(hw, NULL);
1157ac13930bSmikeb 	if (ret != IXGBE_SUCCESS)
1158ac13930bSmikeb 		goto out;
1159ac13930bSmikeb 
1160ac13930bSmikeb 	command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
1161ac13930bSmikeb 		   (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
1162ac13930bSmikeb 
1163ac13930bSmikeb 	/* Write IOSF control register */
1164ac13930bSmikeb 	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
1165ac13930bSmikeb 
1166ac13930bSmikeb 	ret = ixgbe_iosf_wait(hw, &command);
1167ac13930bSmikeb 
1168ac13930bSmikeb 	if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
1169ac13930bSmikeb 		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
1170ac13930bSmikeb 			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
1171d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_POLLING,
1172d7a8f955Sjmatthew 				"Failed to read, error %x\n", error);
1173ac13930bSmikeb 		ret = IXGBE_ERR_PHY;
1174ac13930bSmikeb 	}
1175ac13930bSmikeb 
1176ac13930bSmikeb 	if (ret == IXGBE_SUCCESS)
1177ac13930bSmikeb 		*data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA);
1178ac13930bSmikeb 
1179ac13930bSmikeb out:
1180ac13930bSmikeb 	hw->mac.ops.release_swfw_sync(hw, gssr);
1181ac13930bSmikeb 	return ret;
1182ac13930bSmikeb }
1183ac13930bSmikeb 
1184ac13930bSmikeb /**
1185d7a8f955Sjmatthew  * ixgbe_get_phy_token - Get the token for shared phy access
1186d7a8f955Sjmatthew  * @hw: Pointer to hardware structure
1187d7a8f955Sjmatthew  */
1188d7a8f955Sjmatthew 
1189d7a8f955Sjmatthew int32_t ixgbe_get_phy_token(struct ixgbe_hw *hw)
1190d7a8f955Sjmatthew {
1191d7a8f955Sjmatthew 	struct ixgbe_hic_phy_token_req token_cmd;
1192d7a8f955Sjmatthew 	int32_t status;
1193d7a8f955Sjmatthew 
1194d7a8f955Sjmatthew 	token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD;
1195d7a8f955Sjmatthew 	token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN;
1196d7a8f955Sjmatthew 	token_cmd.hdr.cmd_or_resp.cmd_resv = 0;
1197d7a8f955Sjmatthew 	token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1198d7a8f955Sjmatthew 	token_cmd.port_number = hw->bus.lan_id;
1199d7a8f955Sjmatthew 	token_cmd.command_type = FW_PHY_TOKEN_REQ;
1200d7a8f955Sjmatthew 	token_cmd.pad = 0;
1201d7a8f955Sjmatthew 	status = ixgbe_host_interface_command(hw, (uint32_t *)&token_cmd,
1202d7a8f955Sjmatthew 					      sizeof(token_cmd),
1203d7a8f955Sjmatthew 					      IXGBE_HI_COMMAND_TIMEOUT,
1204d7a8f955Sjmatthew 					      TRUE);
1205d7a8f955Sjmatthew 	if (status) {
1206d7a8f955Sjmatthew 		DEBUGOUT1("Issuing host interface command failed with Status = %d\n",
1207d7a8f955Sjmatthew 			  status);
1208d7a8f955Sjmatthew 		return status;
1209d7a8f955Sjmatthew 	}
1210d7a8f955Sjmatthew 	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
1211d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
1212d7a8f955Sjmatthew 	if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY) {
1213d7a8f955Sjmatthew 		DEBUGOUT1("Host interface command returned 0x%08x , returning IXGBE_ERR_FW_RESP_INVALID\n",
1214d7a8f955Sjmatthew 			  token_cmd.hdr.cmd_or_resp.ret_status);
1215d7a8f955Sjmatthew 		return IXGBE_ERR_FW_RESP_INVALID;
1216d7a8f955Sjmatthew 	}
1217d7a8f955Sjmatthew 
1218d7a8f955Sjmatthew 	DEBUGOUT("Returning  IXGBE_ERR_TOKEN_RETRY\n");
1219d7a8f955Sjmatthew 	return IXGBE_ERR_TOKEN_RETRY;
1220d7a8f955Sjmatthew }
1221d7a8f955Sjmatthew 
1222d7a8f955Sjmatthew /**
1223d7a8f955Sjmatthew  * ixgbe_put_phy_token - Put the token for shared phy access
1224d7a8f955Sjmatthew  * @hw: Pointer to hardware structure
1225d7a8f955Sjmatthew  */
1226d7a8f955Sjmatthew 
1227d7a8f955Sjmatthew int32_t ixgbe_put_phy_token(struct ixgbe_hw *hw)
1228d7a8f955Sjmatthew {
1229d7a8f955Sjmatthew 	struct ixgbe_hic_phy_token_req token_cmd;
1230d7a8f955Sjmatthew 	int32_t status;
1231d7a8f955Sjmatthew 
1232d7a8f955Sjmatthew 	token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD;
1233d7a8f955Sjmatthew 	token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN;
1234d7a8f955Sjmatthew 	token_cmd.hdr.cmd_or_resp.cmd_resv = 0;
1235d7a8f955Sjmatthew 	token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1236d7a8f955Sjmatthew 	token_cmd.port_number = hw->bus.lan_id;
1237d7a8f955Sjmatthew 	token_cmd.command_type = FW_PHY_TOKEN_REL;
1238d7a8f955Sjmatthew 	token_cmd.pad = 0;
1239d7a8f955Sjmatthew 	status = ixgbe_host_interface_command(hw, (uint32_t *)&token_cmd,
1240d7a8f955Sjmatthew 					      sizeof(token_cmd),
1241d7a8f955Sjmatthew 					      IXGBE_HI_COMMAND_TIMEOUT,
1242d7a8f955Sjmatthew 					      TRUE);
1243d7a8f955Sjmatthew 	if (status)
1244d7a8f955Sjmatthew 		return status;
1245d7a8f955Sjmatthew 	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
1246d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
1247d7a8f955Sjmatthew 
1248d7a8f955Sjmatthew 	DEBUGOUT("Put PHY Token host interface command failed");
1249d7a8f955Sjmatthew 	return IXGBE_ERR_FW_RESP_INVALID;
1250d7a8f955Sjmatthew }
1251d7a8f955Sjmatthew 
1252d7a8f955Sjmatthew /**
1253d7a8f955Sjmatthew  *  ixgbe_write_iosf_sb_reg_x550a - Writes a value to specified register
1254d7a8f955Sjmatthew  *  of the IOSF device
1255d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
1256d7a8f955Sjmatthew  *  @reg_addr: 32 bit PHY register to write
1257d7a8f955Sjmatthew  *  @device_type: 3 bit device type
1258d7a8f955Sjmatthew  *  @data: Data to write to the register
1259d7a8f955Sjmatthew  **/
1260d7a8f955Sjmatthew int32_t ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
1261d7a8f955Sjmatthew 				      uint32_t device_type, uint32_t data)
1262d7a8f955Sjmatthew {
1263d7a8f955Sjmatthew 	struct ixgbe_hic_internal_phy_req write_cmd;
1264d7a8f955Sjmatthew 	int32_t status;
1265d7a8f955Sjmatthew 
1266d7a8f955Sjmatthew 	memset(&write_cmd, 0, sizeof(write_cmd));
1267d7a8f955Sjmatthew 	write_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD;
1268d7a8f955Sjmatthew 	write_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN;
1269d7a8f955Sjmatthew 	write_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1270d7a8f955Sjmatthew 	write_cmd.port_number = hw->bus.lan_id;
1271d7a8f955Sjmatthew 	write_cmd.command_type = FW_INT_PHY_REQ_WRITE;
1272d7a8f955Sjmatthew 	write_cmd.address = htobe16(reg_addr);
1273d7a8f955Sjmatthew 	write_cmd.write_data = htobe32(data);
1274d7a8f955Sjmatthew 
1275d7a8f955Sjmatthew 	status = ixgbe_host_interface_command(hw, (uint32_t *)&write_cmd,
1276d7a8f955Sjmatthew 					      sizeof(write_cmd),
1277d7a8f955Sjmatthew 					      IXGBE_HI_COMMAND_TIMEOUT, FALSE);
1278d7a8f955Sjmatthew 
1279d7a8f955Sjmatthew 	return status;
1280d7a8f955Sjmatthew }
1281d7a8f955Sjmatthew 
1282d7a8f955Sjmatthew /**
1283d7a8f955Sjmatthew  *  ixgbe_read_iosf_sb_reg_x550a - Reads specified register of the IOSF device
1284d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
1285d7a8f955Sjmatthew  *  @reg_addr: 32 bit PHY register to write
1286d7a8f955Sjmatthew  *  @device_type: 3 bit device type
1287d7a8f955Sjmatthew  *  @data: Pointer to read data from the register
1288d7a8f955Sjmatthew  **/
1289d7a8f955Sjmatthew int32_t ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
1290d7a8f955Sjmatthew 				     uint32_t device_type, uint32_t *data)
1291d7a8f955Sjmatthew {
1292d7a8f955Sjmatthew 	union {
1293d7a8f955Sjmatthew 		struct ixgbe_hic_internal_phy_req cmd;
1294d7a8f955Sjmatthew 		struct ixgbe_hic_internal_phy_resp rsp;
1295d7a8f955Sjmatthew 	} hic;
1296d7a8f955Sjmatthew 	int32_t status;
1297d7a8f955Sjmatthew 
1298d7a8f955Sjmatthew 	memset(&hic, 0, sizeof(hic));
1299d7a8f955Sjmatthew 	hic.cmd.hdr.cmd = FW_INT_PHY_REQ_CMD;
1300d7a8f955Sjmatthew 	hic.cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN;
1301d7a8f955Sjmatthew 	hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1302d7a8f955Sjmatthew 	hic.cmd.port_number = hw->bus.lan_id;
1303d7a8f955Sjmatthew 	hic.cmd.command_type = FW_INT_PHY_REQ_READ;
1304d7a8f955Sjmatthew 	hic.cmd.address = htobe16(reg_addr);
1305d7a8f955Sjmatthew 
1306d7a8f955Sjmatthew 	status = ixgbe_host_interface_command(hw, (uint32_t *)&hic.cmd,
1307d7a8f955Sjmatthew 					      sizeof(hic.cmd),
1308d7a8f955Sjmatthew 					      IXGBE_HI_COMMAND_TIMEOUT, TRUE);
1309d7a8f955Sjmatthew 
1310d7a8f955Sjmatthew 	/* Extract the register value from the response. */
1311d7a8f955Sjmatthew 	*data = betoh32(hic.rsp.read_data);
1312d7a8f955Sjmatthew 
1313d7a8f955Sjmatthew 	return status;
1314d7a8f955Sjmatthew }
1315d7a8f955Sjmatthew 
1316d7a8f955Sjmatthew /**
1317ac13930bSmikeb  *  ixgbe_get_media_type_X550em - Get media type
1318ac13930bSmikeb  *  @hw: pointer to hardware structure
1319ac13930bSmikeb  *
1320ac13930bSmikeb  *  Returns the media type (fiber, copper, backplane)
1321ac13930bSmikeb  */
1322ac13930bSmikeb enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
1323ac13930bSmikeb {
1324ac13930bSmikeb 	enum ixgbe_media_type media_type;
1325ac13930bSmikeb 
1326ac13930bSmikeb 	DEBUGFUNC("ixgbe_get_media_type_X550em");
1327ac13930bSmikeb 
1328ac13930bSmikeb 	/* Detect if there is a copper PHY attached. */
1329ac13930bSmikeb 	switch (hw->device_id) {
1330ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_KR:
1331ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_KX4:
1332d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_XFI:
1333d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_KR:
1334d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_KR_L:
1335ac13930bSmikeb 		media_type = ixgbe_media_type_backplane;
1336ac13930bSmikeb 		break;
1337ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_SFP:
1338d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SFP:
1339d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SFP_N:
1340d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_QSFP:
1341d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_QSFP_N:
1342ac13930bSmikeb 		media_type = ixgbe_media_type_fiber;
1343ac13930bSmikeb 		break;
1344ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_1G_T:
1345ac13930bSmikeb 	case IXGBE_DEV_ID_X550EM_X_10G_T:
1346d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_10G_T:
1347d7a8f955Sjmatthew 		media_type = ixgbe_media_type_copper;
1348d7a8f955Sjmatthew 		break;
1349d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SGMII:
1350d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
1351d7a8f955Sjmatthew 		media_type = ixgbe_media_type_backplane;
1352d7a8f955Sjmatthew 		hw->phy.type = ixgbe_phy_sgmii;
1353d7a8f955Sjmatthew 		break;
1354d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T:
1355d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
1356ac13930bSmikeb 		media_type = ixgbe_media_type_copper;
1357ac13930bSmikeb 		break;
1358ac13930bSmikeb 	default:
1359ac13930bSmikeb 		media_type = ixgbe_media_type_unknown;
1360ac13930bSmikeb 		break;
1361ac13930bSmikeb 	}
1362ac13930bSmikeb 	return media_type;
1363ac13930bSmikeb }
1364ac13930bSmikeb 
1365ac13930bSmikeb /**
1366ac13930bSmikeb  *  ixgbe_supported_sfp_modules_X550em - Check if SFP module type is supported
1367ac13930bSmikeb  *  @hw: pointer to hardware structure
1368ac13930bSmikeb  *  @linear: TRUE if SFP module is linear
1369ac13930bSmikeb  */
1370ac13930bSmikeb int32_t ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear)
1371ac13930bSmikeb {
1372ac13930bSmikeb 	DEBUGFUNC("ixgbe_supported_sfp_modules_X550em");
1373ac13930bSmikeb 
1374ac13930bSmikeb 	switch (hw->phy.sfp_type) {
1375ac13930bSmikeb 	case ixgbe_sfp_type_not_present:
1376ac13930bSmikeb 		return IXGBE_ERR_SFP_NOT_PRESENT;
1377ac13930bSmikeb 	case ixgbe_sfp_type_da_cu_core0:
1378ac13930bSmikeb 	case ixgbe_sfp_type_da_cu_core1:
1379ac13930bSmikeb 		*linear = TRUE;
1380ac13930bSmikeb 		break;
1381ac13930bSmikeb 	case ixgbe_sfp_type_srlr_core0:
1382ac13930bSmikeb 	case ixgbe_sfp_type_srlr_core1:
1383ac13930bSmikeb 	case ixgbe_sfp_type_da_act_lmt_core0:
1384ac13930bSmikeb 	case ixgbe_sfp_type_da_act_lmt_core1:
1385ac13930bSmikeb 	case ixgbe_sfp_type_1g_sx_core0:
1386ac13930bSmikeb 	case ixgbe_sfp_type_1g_sx_core1:
1387ac13930bSmikeb 	case ixgbe_sfp_type_1g_lx_core0:
1388ac13930bSmikeb 	case ixgbe_sfp_type_1g_lx_core1:
1389ac13930bSmikeb 		*linear = FALSE;
1390ac13930bSmikeb 		break;
1391ac13930bSmikeb 	case ixgbe_sfp_type_unknown:
1392ac13930bSmikeb 	case ixgbe_sfp_type_1g_cu_core0:
1393ac13930bSmikeb 	case ixgbe_sfp_type_1g_cu_core1:
1394ac13930bSmikeb 	default:
1395ac13930bSmikeb 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
1396ac13930bSmikeb 	}
1397ac13930bSmikeb 
1398ac13930bSmikeb 	return IXGBE_SUCCESS;
1399ac13930bSmikeb }
1400ac13930bSmikeb 
1401ac13930bSmikeb /**
1402ac13930bSmikeb  *  ixgbe_identify_sfp_module_X550em - Identifies SFP modules
1403ac13930bSmikeb  *  @hw: pointer to hardware structure
1404ac13930bSmikeb  *
1405ac13930bSmikeb  *  Searches for and identifies the SFP module and assigns appropriate PHY type.
1406ac13930bSmikeb  **/
1407ac13930bSmikeb int32_t ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw)
1408ac13930bSmikeb {
1409ac13930bSmikeb 	int32_t status;
1410ac13930bSmikeb 	bool linear;
1411ac13930bSmikeb 
1412ac13930bSmikeb 	DEBUGFUNC("ixgbe_identify_sfp_module_X550em");
1413ac13930bSmikeb 
1414ac13930bSmikeb 	status = ixgbe_identify_module_generic(hw);
1415ac13930bSmikeb 
1416ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1417ac13930bSmikeb 		return status;
1418ac13930bSmikeb 
1419ac13930bSmikeb 	/* Check if SFP module is supported */
1420ac13930bSmikeb 	status = ixgbe_supported_sfp_modules_X550em(hw, &linear);
1421ac13930bSmikeb 
1422ac13930bSmikeb 	return status;
1423ac13930bSmikeb }
1424ac13930bSmikeb 
1425ac13930bSmikeb /**
1426ac13930bSmikeb  *  ixgbe_setup_sfp_modules_X550em - Setup MAC link ops
1427ac13930bSmikeb  *  @hw: pointer to hardware structure
1428ac13930bSmikeb  */
1429ac13930bSmikeb int32_t ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
1430ac13930bSmikeb {
1431ac13930bSmikeb 	int32_t status;
1432ac13930bSmikeb 	bool linear;
1433ac13930bSmikeb 
1434ac13930bSmikeb 	DEBUGFUNC("ixgbe_setup_sfp_modules_X550em");
1435ac13930bSmikeb 
1436ac13930bSmikeb 	/* Check if SFP module is supported */
1437ac13930bSmikeb 	status = ixgbe_supported_sfp_modules_X550em(hw, &linear);
1438ac13930bSmikeb 
1439ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1440ac13930bSmikeb 		return status;
1441ac13930bSmikeb 
1442ac13930bSmikeb 	ixgbe_init_mac_link_ops_X550em(hw);
1443ac13930bSmikeb 	hw->phy.ops.reset = NULL;
1444ac13930bSmikeb 
1445ac13930bSmikeb 	return IXGBE_SUCCESS;
1446ac13930bSmikeb }
1447ac13930bSmikeb 
1448ac13930bSmikeb /**
1449d7a8f955Sjmatthew *  ixgbe_restart_an_internal_phy_x550em - restart autonegotiation for the
1450d7a8f955Sjmatthew *  internal PHY
1451d7a8f955Sjmatthew *  @hw: pointer to hardware structure
1452d7a8f955Sjmatthew **/
1453d7a8f955Sjmatthew int32_t ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw)
1454d7a8f955Sjmatthew {
1455d7a8f955Sjmatthew 	int32_t status;
1456d7a8f955Sjmatthew 	uint32_t link_ctrl;
1457d7a8f955Sjmatthew 
1458d7a8f955Sjmatthew 	/* Restart auto-negotiation. */
1459d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
1460d7a8f955Sjmatthew 				       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1461d7a8f955Sjmatthew 				       IXGBE_SB_IOSF_TARGET_KR_PHY, &link_ctrl);
1462d7a8f955Sjmatthew 
1463d7a8f955Sjmatthew 	if (status) {
1464d7a8f955Sjmatthew 		DEBUGOUT("Auto-negotiation did not complete\n");
1465d7a8f955Sjmatthew 		return status;
1466d7a8f955Sjmatthew 	}
1467d7a8f955Sjmatthew 
1468d7a8f955Sjmatthew 	link_ctrl |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
1469d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
1470d7a8f955Sjmatthew 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1471d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, link_ctrl);
1472d7a8f955Sjmatthew 
1473d7a8f955Sjmatthew 	if (hw->mac.type == ixgbe_mac_X550EM_a) {
1474d7a8f955Sjmatthew 		uint32_t flx_mask_st20;
1475d7a8f955Sjmatthew 
1476d7a8f955Sjmatthew 		/* Indicate to FW that AN restart has been asserted */
1477d7a8f955Sjmatthew 		status = hw->mac.ops.read_iosf_sb_reg(hw,
1478d7a8f955Sjmatthew 				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1479d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_mask_st20);
1480d7a8f955Sjmatthew 
1481d7a8f955Sjmatthew 		if (status) {
1482d7a8f955Sjmatthew 			DEBUGOUT("Auto-negotiation did not complete\n");
1483d7a8f955Sjmatthew 			return status;
1484d7a8f955Sjmatthew 		}
1485d7a8f955Sjmatthew 
1486d7a8f955Sjmatthew 		flx_mask_st20 |= IXGBE_KRM_PMD_FLX_MASK_ST20_FW_AN_RESTART;
1487d7a8f955Sjmatthew 		status = hw->mac.ops.write_iosf_sb_reg(hw,
1488d7a8f955Sjmatthew 				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1489d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, flx_mask_st20);
1490d7a8f955Sjmatthew 	}
1491d7a8f955Sjmatthew 
1492d7a8f955Sjmatthew 	return status;
1493d7a8f955Sjmatthew }
1494d7a8f955Sjmatthew 
1495d7a8f955Sjmatthew /**
1496d7a8f955Sjmatthew  * ixgbe_setup_sgmii - Set up link for sgmii
1497d7a8f955Sjmatthew  * @hw: pointer to hardware structure
1498d7a8f955Sjmatthew  * @speed: new link speed
1499d7a8f955Sjmatthew  * @autoneg_wait: TRUE when waiting for completion is needed
1500d7a8f955Sjmatthew  */
1501d7a8f955Sjmatthew int32_t ixgbe_setup_sgmii(struct ixgbe_hw *hw, ixgbe_link_speed speed,
1502d7a8f955Sjmatthew 			     bool autoneg_wait)
1503d7a8f955Sjmatthew {
1504d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
1505d7a8f955Sjmatthew 	uint32_t lval, sval, flx_val;
1506d7a8f955Sjmatthew 	int32_t rc;
1507d7a8f955Sjmatthew 
1508d7a8f955Sjmatthew 	rc = mac->ops.read_iosf_sb_reg(hw,
1509d7a8f955Sjmatthew 				       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1510d7a8f955Sjmatthew 				       IXGBE_SB_IOSF_TARGET_KR_PHY, &lval);
1511d7a8f955Sjmatthew 	if (rc)
1512d7a8f955Sjmatthew 		return rc;
1513d7a8f955Sjmatthew 
1514d7a8f955Sjmatthew 	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
1515d7a8f955Sjmatthew 	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
1516d7a8f955Sjmatthew 	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN;
1517d7a8f955Sjmatthew 	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN;
1518d7a8f955Sjmatthew 	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
1519d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1520d7a8f955Sjmatthew 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1521d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, lval);
1522d7a8f955Sjmatthew 	if (rc)
1523d7a8f955Sjmatthew 		return rc;
1524d7a8f955Sjmatthew 
1525d7a8f955Sjmatthew 	rc = mac->ops.read_iosf_sb_reg(hw,
1526d7a8f955Sjmatthew 				       IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1527d7a8f955Sjmatthew 				       IXGBE_SB_IOSF_TARGET_KR_PHY, &sval);
1528d7a8f955Sjmatthew 	if (rc)
1529d7a8f955Sjmatthew 		return rc;
1530d7a8f955Sjmatthew 
1531d7a8f955Sjmatthew 	sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D;
1532d7a8f955Sjmatthew 	sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D;
1533d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1534d7a8f955Sjmatthew 					IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1535d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, sval);
1536d7a8f955Sjmatthew 	if (rc)
1537d7a8f955Sjmatthew 		return rc;
1538d7a8f955Sjmatthew 
1539d7a8f955Sjmatthew 	rc = mac->ops.read_iosf_sb_reg(hw,
1540d7a8f955Sjmatthew 				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1541d7a8f955Sjmatthew 				    IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val);
1542d7a8f955Sjmatthew 	if (rc)
1543d7a8f955Sjmatthew 		return rc;
1544d7a8f955Sjmatthew 
1545d7a8f955Sjmatthew 	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
1546d7a8f955Sjmatthew 	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G;
1547d7a8f955Sjmatthew 	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
1548d7a8f955Sjmatthew 	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
1549d7a8f955Sjmatthew 	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
1550d7a8f955Sjmatthew 
1551d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1552d7a8f955Sjmatthew 				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1553d7a8f955Sjmatthew 				    IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val);
1554d7a8f955Sjmatthew 	if (rc)
1555d7a8f955Sjmatthew 		return rc;
1556d7a8f955Sjmatthew 
1557d7a8f955Sjmatthew 	rc = ixgbe_restart_an_internal_phy_x550em(hw);
1558d7a8f955Sjmatthew 	if (rc)
1559d7a8f955Sjmatthew 		return rc;
1560d7a8f955Sjmatthew 
1561d7a8f955Sjmatthew 	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
1562d7a8f955Sjmatthew }
1563d7a8f955Sjmatthew 
1564d7a8f955Sjmatthew /**
1565d7a8f955Sjmatthew  * ixgbe_setup_sgmii_fw - Set up link for internal PHY SGMII auto-negotiation
1566d7a8f955Sjmatthew  * @hw: pointer to hardware structure
1567d7a8f955Sjmatthew  * @speed: new link speed
1568d7a8f955Sjmatthew  * @autoneg_wait: TRUE when waiting for completion is needed
1569d7a8f955Sjmatthew  */
1570d7a8f955Sjmatthew int32_t ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed,
1571d7a8f955Sjmatthew 				bool autoneg_wait)
1572d7a8f955Sjmatthew {
1573d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
1574d7a8f955Sjmatthew 	uint32_t lval, sval, flx_val;
1575d7a8f955Sjmatthew 	int32_t rc;
1576d7a8f955Sjmatthew 
1577d7a8f955Sjmatthew 	rc = mac->ops.read_iosf_sb_reg(hw,
1578d7a8f955Sjmatthew 				       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1579d7a8f955Sjmatthew 				       IXGBE_SB_IOSF_TARGET_KR_PHY, &lval);
1580d7a8f955Sjmatthew 	if (rc)
1581d7a8f955Sjmatthew 		return rc;
1582d7a8f955Sjmatthew 
1583d7a8f955Sjmatthew 	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
1584d7a8f955Sjmatthew 	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
1585d7a8f955Sjmatthew 	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN;
1586d7a8f955Sjmatthew 	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN;
1587d7a8f955Sjmatthew 	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
1588d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1589d7a8f955Sjmatthew 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1590d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, lval);
1591d7a8f955Sjmatthew 	if (rc)
1592d7a8f955Sjmatthew 		return rc;
1593d7a8f955Sjmatthew 
1594d7a8f955Sjmatthew 	rc = mac->ops.read_iosf_sb_reg(hw,
1595d7a8f955Sjmatthew 				       IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1596d7a8f955Sjmatthew 				       IXGBE_SB_IOSF_TARGET_KR_PHY, &sval);
1597d7a8f955Sjmatthew 	if (rc)
1598d7a8f955Sjmatthew 		return rc;
1599d7a8f955Sjmatthew 
1600d7a8f955Sjmatthew 	sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D;
1601d7a8f955Sjmatthew 	sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D;
1602d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1603d7a8f955Sjmatthew 					IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1604d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, sval);
1605d7a8f955Sjmatthew 	if (rc)
1606d7a8f955Sjmatthew 		return rc;
1607d7a8f955Sjmatthew 
1608d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1609d7a8f955Sjmatthew 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1610d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, lval);
1611d7a8f955Sjmatthew 	if (rc)
1612d7a8f955Sjmatthew 		return rc;
1613d7a8f955Sjmatthew 
1614d7a8f955Sjmatthew 	rc = mac->ops.read_iosf_sb_reg(hw,
1615d7a8f955Sjmatthew 				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1616d7a8f955Sjmatthew 				    IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val);
1617d7a8f955Sjmatthew 	if (rc)
1618d7a8f955Sjmatthew 		return rc;
1619d7a8f955Sjmatthew 
1620d7a8f955Sjmatthew 	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
1621d7a8f955Sjmatthew 	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN;
1622d7a8f955Sjmatthew 	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
1623d7a8f955Sjmatthew 	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
1624d7a8f955Sjmatthew 	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
1625d7a8f955Sjmatthew 
1626d7a8f955Sjmatthew 	rc = mac->ops.write_iosf_sb_reg(hw,
1627d7a8f955Sjmatthew 				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1628d7a8f955Sjmatthew 				    IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val);
1629d7a8f955Sjmatthew 	if (rc)
1630d7a8f955Sjmatthew 		return rc;
1631d7a8f955Sjmatthew 
1632d7a8f955Sjmatthew 	rc = ixgbe_restart_an_internal_phy_x550em(hw);
1633d7a8f955Sjmatthew 
1634d7a8f955Sjmatthew 	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
1635d7a8f955Sjmatthew }
1636d7a8f955Sjmatthew 
1637d7a8f955Sjmatthew /**
1638ac13930bSmikeb  *  ixgbe_init_mac_link_ops_X550em - init mac link function pointers
1639ac13930bSmikeb  *  @hw: pointer to hardware structure
1640ac13930bSmikeb  */
1641ac13930bSmikeb void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
1642ac13930bSmikeb {
1643ac13930bSmikeb 	struct ixgbe_mac_info *mac = &hw->mac;
1644ac13930bSmikeb 
1645ac13930bSmikeb 	DEBUGFUNC("ixgbe_init_mac_link_ops_X550em");
1646ac13930bSmikeb 
1647ac13930bSmikeb 	switch (hw->mac.ops.get_media_type(hw)) {
1648ac13930bSmikeb 	case ixgbe_media_type_fiber:
1649ac13930bSmikeb 		/* CS4227 does not support autoneg, so disable the laser control
1650ac13930bSmikeb 		 * functions for SFP+ fiber
1651ac13930bSmikeb 		 */
1652ac13930bSmikeb 		mac->ops.disable_tx_laser = NULL;
1653ac13930bSmikeb 		mac->ops.enable_tx_laser = NULL;
1654ac13930bSmikeb 		mac->ops.flap_tx_laser = NULL;
1655ac13930bSmikeb 		mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber;
1656ac13930bSmikeb 		mac->ops.set_rate_select_speed =
1657ac13930bSmikeb 					ixgbe_set_soft_rate_select_speed;
1658d7a8f955Sjmatthew 
1659d7a8f955Sjmatthew 		if ((hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) ||
1660d7a8f955Sjmatthew 		    (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP))
1661d7a8f955Sjmatthew 			mac->ops.setup_mac_link =
1662d7a8f955Sjmatthew 						ixgbe_setup_mac_link_sfp_x550a;
1663d7a8f955Sjmatthew 		else
1664d7a8f955Sjmatthew 			mac->ops.setup_mac_link =
1665d7a8f955Sjmatthew 						ixgbe_setup_mac_link_sfp_x550em;
1666ac13930bSmikeb 		break;
1667ac13930bSmikeb 	case ixgbe_media_type_copper:
1668d7a8f955Sjmatthew 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_1G_T)
1669d7a8f955Sjmatthew 			break;
1670d7a8f955Sjmatthew 		if (hw->mac.type == ixgbe_mac_X550EM_a) {
1671d7a8f955Sjmatthew 			if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T ||
1672d7a8f955Sjmatthew 			    hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) {
1673d7a8f955Sjmatthew 				mac->ops.setup_link = ixgbe_setup_sgmii_fw;
1674d7a8f955Sjmatthew 				mac->ops.check_link =
1675d7a8f955Sjmatthew 						   ixgbe_check_mac_link_generic;
1676d7a8f955Sjmatthew 			} else {
1677d7a8f955Sjmatthew 				mac->ops.setup_link =
1678d7a8f955Sjmatthew 						  ixgbe_setup_mac_link_t_X550em;
1679d7a8f955Sjmatthew 			}
1680d7a8f955Sjmatthew 		} else {
1681ac13930bSmikeb 			mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
1682ac13930bSmikeb 			mac->ops.check_link = ixgbe_check_link_t_X550em;
1683d7a8f955Sjmatthew 		}
1684d7a8f955Sjmatthew 		break;
1685d7a8f955Sjmatthew 	case ixgbe_media_type_backplane:
1686d7a8f955Sjmatthew 		if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII ||
1687d7a8f955Sjmatthew 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L)
1688d7a8f955Sjmatthew 			mac->ops.setup_link = ixgbe_setup_sgmii;
1689ac13930bSmikeb 		break;
1690ac13930bSmikeb 	default:
1691ac13930bSmikeb 		break;
1692ac13930bSmikeb 	}
1693ac13930bSmikeb }
1694ac13930bSmikeb 
1695ac13930bSmikeb /**
1696ac13930bSmikeb  *  ixgbe_get_link_capabilities_x550em - Determines link capabilities
1697ac13930bSmikeb  *  @hw: pointer to hardware structure
1698ac13930bSmikeb  *  @speed: pointer to link speed
1699ac13930bSmikeb  *  @autoneg: TRUE when autoneg or autotry is enabled
1700ac13930bSmikeb  */
1701ac13930bSmikeb int32_t ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
1702ac13930bSmikeb 					   ixgbe_link_speed *speed,
1703ac13930bSmikeb 					   bool *autoneg)
1704ac13930bSmikeb {
1705ac13930bSmikeb 	DEBUGFUNC("ixgbe_get_link_capabilities_X550em");
1706ac13930bSmikeb 
1707d7a8f955Sjmatthew 
1708d7a8f955Sjmatthew 	if (hw->phy.type == ixgbe_phy_fw) {
1709d7a8f955Sjmatthew 		*autoneg = TRUE;
1710d7a8f955Sjmatthew 		*speed = hw->phy.speeds_supported;
1711d7a8f955Sjmatthew 		return 0;
1712d7a8f955Sjmatthew 	}
1713d7a8f955Sjmatthew 
1714ac13930bSmikeb 	/* SFP */
1715ac13930bSmikeb 	if (hw->phy.media_type == ixgbe_media_type_fiber) {
1716ac13930bSmikeb 
1717ac13930bSmikeb 		/* CS4227 SFP must not enable auto-negotiation */
1718ac13930bSmikeb 		*autoneg = FALSE;
1719ac13930bSmikeb 
1720ac13930bSmikeb 		/* Check if 1G SFP module. */
1721ac13930bSmikeb 		if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
1722ac13930bSmikeb 		    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1
1723ac13930bSmikeb 		    || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
1724ac13930bSmikeb 		    hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1) {
1725ac13930bSmikeb 			*speed = IXGBE_LINK_SPEED_1GB_FULL;
1726ac13930bSmikeb 			return IXGBE_SUCCESS;
1727ac13930bSmikeb 		}
1728ac13930bSmikeb 
1729ac13930bSmikeb 		/* Link capabilities are based on SFP */
1730ac13930bSmikeb 		if (hw->phy.multispeed_fiber)
1731ac13930bSmikeb 			*speed = IXGBE_LINK_SPEED_10GB_FULL |
1732ac13930bSmikeb 				 IXGBE_LINK_SPEED_1GB_FULL;
1733ac13930bSmikeb 		else
1734ac13930bSmikeb 			*speed = IXGBE_LINK_SPEED_10GB_FULL;
1735ac13930bSmikeb 	} else {
1736d7a8f955Sjmatthew 		switch (hw->phy.type) {
1737d7a8f955Sjmatthew 		case ixgbe_phy_ext_1g_t:
1738d7a8f955Sjmatthew 		case ixgbe_phy_sgmii:
1739d7a8f955Sjmatthew 			*speed = IXGBE_LINK_SPEED_1GB_FULL;
1740d7a8f955Sjmatthew 			break;
1741d7a8f955Sjmatthew 		case ixgbe_phy_x550em_kr:
1742d7a8f955Sjmatthew 			if (hw->mac.type == ixgbe_mac_X550EM_a) {
1743d7a8f955Sjmatthew 				/* check different backplane modes */
1744d7a8f955Sjmatthew 				if (hw->phy.nw_mng_if_sel &
1745d7a8f955Sjmatthew 					   IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G) {
1746d7a8f955Sjmatthew 					*speed = IXGBE_LINK_SPEED_2_5GB_FULL;
1747d7a8f955Sjmatthew 					break;
1748d7a8f955Sjmatthew 				} else if (hw->device_id ==
1749d7a8f955Sjmatthew 						   IXGBE_DEV_ID_X550EM_A_KR_L) {
1750d7a8f955Sjmatthew 					*speed = IXGBE_LINK_SPEED_1GB_FULL;
1751d7a8f955Sjmatthew 					break;
1752d7a8f955Sjmatthew 				}
1753d7a8f955Sjmatthew 			}
1754d7a8f955Sjmatthew 			/* fall through */
1755d7a8f955Sjmatthew 		default:
1756ac13930bSmikeb 			*speed = IXGBE_LINK_SPEED_10GB_FULL |
1757ac13930bSmikeb 				 IXGBE_LINK_SPEED_1GB_FULL;
1758d7a8f955Sjmatthew 			break;
1759d7a8f955Sjmatthew 		}
1760ac13930bSmikeb 		*autoneg = TRUE;
1761ac13930bSmikeb 	}
1762ac13930bSmikeb 
1763ac13930bSmikeb 	return IXGBE_SUCCESS;
1764ac13930bSmikeb }
1765ac13930bSmikeb 
1766ac13930bSmikeb /**
1767*54fbbda3Sjsg  * ixgbe_get_lasi_ext_t_x550em - Determine external Base T PHY interrupt cause
1768ac13930bSmikeb  * @hw: pointer to hardware structure
1769ac13930bSmikeb  * @lsc: pointer to boolean flag which indicates whether external Base T
1770ac13930bSmikeb  *       PHY interrupt is lsc
1771ac13930bSmikeb  *
1772*54fbbda3Sjsg  * Determine if external Base T PHY interrupt cause is high temperature
1773ac13930bSmikeb  * failure alarm or link status change.
1774ac13930bSmikeb  *
1775ac13930bSmikeb  * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
1776ac13930bSmikeb  * failure alarm, else return PHY access status.
1777ac13930bSmikeb  */
1778ac13930bSmikeb int32_t ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
1779ac13930bSmikeb {
1780ac13930bSmikeb 	uint32_t status;
1781ac13930bSmikeb 	uint16_t reg;
1782ac13930bSmikeb 
1783ac13930bSmikeb 	*lsc = FALSE;
1784ac13930bSmikeb 
1785ac13930bSmikeb 	/* Vendor alarm triggered */
1786ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
1787ac13930bSmikeb 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1788ac13930bSmikeb 				      &reg);
1789ac13930bSmikeb 
1790ac13930bSmikeb 	if (status != IXGBE_SUCCESS ||
1791ac13930bSmikeb 	    !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN))
1792ac13930bSmikeb 		return status;
1793ac13930bSmikeb 
1794ac13930bSmikeb 	/* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */
1795ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG,
1796ac13930bSmikeb 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1797ac13930bSmikeb 				      &reg);
1798ac13930bSmikeb 
1799ac13930bSmikeb 	if (status != IXGBE_SUCCESS ||
1800ac13930bSmikeb 	    !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
1801ac13930bSmikeb 	    IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
1802ac13930bSmikeb 		return status;
1803ac13930bSmikeb 
1804ac13930bSmikeb 	/* Global alarm triggered */
1805ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
1806ac13930bSmikeb 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1807ac13930bSmikeb 				      &reg);
1808ac13930bSmikeb 
1809ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1810ac13930bSmikeb 		return status;
1811ac13930bSmikeb 
1812ac13930bSmikeb 	/* If high temperature failure, then return over temp error and exit */
1813ac13930bSmikeb 	if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
1814ac13930bSmikeb 		/* power down the PHY in case the PHY FW didn't already */
1815ac13930bSmikeb 		ixgbe_set_copper_phy_power(hw, FALSE);
1816ac13930bSmikeb 		return IXGBE_ERR_OVERTEMP;
1817ac13930bSmikeb 	} else if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) {
1818ac13930bSmikeb 		/*  device fault alarm triggered */
1819ac13930bSmikeb 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_FAULT_MSG,
1820ac13930bSmikeb 					  IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1821ac13930bSmikeb 					  &reg);
1822ac13930bSmikeb 
1823ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
1824ac13930bSmikeb 			return status;
1825ac13930bSmikeb 
1826ac13930bSmikeb 		/* if device fault was due to high temp alarm handle and exit */
1827ac13930bSmikeb 		if (reg == IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP) {
1828ac13930bSmikeb 			/* power down the PHY in case the PHY FW didn't */
1829ac13930bSmikeb 			ixgbe_set_copper_phy_power(hw, FALSE);
1830ac13930bSmikeb 			return IXGBE_ERR_OVERTEMP;
1831ac13930bSmikeb 		}
1832ac13930bSmikeb 	}
1833ac13930bSmikeb 
1834ac13930bSmikeb 	/* Vendor alarm 2 triggered */
1835ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
1836ac13930bSmikeb 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
1837ac13930bSmikeb 
1838ac13930bSmikeb 	if (status != IXGBE_SUCCESS ||
1839ac13930bSmikeb 	    !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT))
1840ac13930bSmikeb 		return status;
1841ac13930bSmikeb 
1842ac13930bSmikeb 	/* link connect/disconnect event occurred */
1843ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2,
1844ac13930bSmikeb 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
1845ac13930bSmikeb 
1846ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1847ac13930bSmikeb 		return status;
1848ac13930bSmikeb 
1849ac13930bSmikeb 	/* Indicate LSC */
1850ac13930bSmikeb 	if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC)
1851ac13930bSmikeb 		*lsc = TRUE;
1852ac13930bSmikeb 
1853ac13930bSmikeb 	return IXGBE_SUCCESS;
1854ac13930bSmikeb }
1855ac13930bSmikeb 
1856ac13930bSmikeb /**
1857ac13930bSmikeb  * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts
1858ac13930bSmikeb  * @hw: pointer to hardware structure
1859ac13930bSmikeb  *
1860ac13930bSmikeb  * Enable link status change and temperature failure alarm for the external
1861ac13930bSmikeb  * Base T PHY
1862ac13930bSmikeb  *
1863ac13930bSmikeb  * Returns PHY access status
1864ac13930bSmikeb  */
1865ac13930bSmikeb int32_t ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
1866ac13930bSmikeb {
1867ac13930bSmikeb 	uint32_t status;
1868ac13930bSmikeb 	uint16_t reg;
1869ac13930bSmikeb 	bool lsc;
1870ac13930bSmikeb 
1871ac13930bSmikeb 	/* Clear interrupt flags */
1872ac13930bSmikeb 	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
1873ac13930bSmikeb 
1874ac13930bSmikeb 	/* Enable link status change alarm */
1875d7a8f955Sjmatthew 
1876d7a8f955Sjmatthew 	/* Enable the LASI interrupts on X552 devices to receive notifications
1877d7a8f955Sjmatthew 	 * of the link configurations of the external PHY and correspondingly
1878d7a8f955Sjmatthew 	 * support the configuration of the internal iXFI link, since iXFI does
1879d7a8f955Sjmatthew 	 * not support auto-negotiation. This is not required for X553 devices
1880d7a8f955Sjmatthew 	 * having KR support, which performs auto-negotiations and which is used
1881d7a8f955Sjmatthew 	 * as the internal link to the external PHY. Hence adding a check here
1882d7a8f955Sjmatthew 	 * to avoid enabling LASI interrupts for X553 devices.
1883d7a8f955Sjmatthew 	 */
1884d7a8f955Sjmatthew 	if (hw->mac.type != ixgbe_mac_X550EM_a) {
1885d7a8f955Sjmatthew 		status = hw->phy.ops.read_reg(hw,
1886d7a8f955Sjmatthew 					IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
1887ac13930bSmikeb 					IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
1888ac13930bSmikeb 
1889ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
1890ac13930bSmikeb 			return status;
1891ac13930bSmikeb 
1892ac13930bSmikeb 		reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
1893ac13930bSmikeb 
1894d7a8f955Sjmatthew 		status = hw->phy.ops.write_reg(hw,
1895d7a8f955Sjmatthew 					IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
1896ac13930bSmikeb 					IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg);
1897ac13930bSmikeb 
1898ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
1899ac13930bSmikeb 			return status;
1900d7a8f955Sjmatthew 	}
1901ac13930bSmikeb 
1902d7a8f955Sjmatthew 	/* Enable high temperature failure and global fault alarms */
1903ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
1904ac13930bSmikeb 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1905ac13930bSmikeb 				      &reg);
1906ac13930bSmikeb 
1907ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1908ac13930bSmikeb 		return status;
1909ac13930bSmikeb 
1910d7a8f955Sjmatthew 	reg |= (IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN |
1911d7a8f955Sjmatthew 		IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN);
1912ac13930bSmikeb 
1913ac13930bSmikeb 	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
1914ac13930bSmikeb 				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1915ac13930bSmikeb 				       reg);
1916ac13930bSmikeb 
1917ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1918ac13930bSmikeb 		return status;
1919ac13930bSmikeb 
1920ac13930bSmikeb 	/* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */
1921ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
1922ac13930bSmikeb 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1923ac13930bSmikeb 				      &reg);
1924ac13930bSmikeb 
1925ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1926ac13930bSmikeb 		return status;
1927ac13930bSmikeb 
1928ac13930bSmikeb 	reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
1929ac13930bSmikeb 		IXGBE_MDIO_GLOBAL_ALARM_1_INT);
1930ac13930bSmikeb 
1931ac13930bSmikeb 	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
1932ac13930bSmikeb 				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1933ac13930bSmikeb 				       reg);
1934ac13930bSmikeb 
1935ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1936ac13930bSmikeb 		return status;
1937ac13930bSmikeb 
1938ac13930bSmikeb 	/* Enable chip-wide vendor alarm */
1939ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
1940ac13930bSmikeb 				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1941ac13930bSmikeb 				      &reg);
1942ac13930bSmikeb 
1943ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
1944ac13930bSmikeb 		return status;
1945ac13930bSmikeb 
1946ac13930bSmikeb 	reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN;
1947ac13930bSmikeb 
1948ac13930bSmikeb 	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
1949ac13930bSmikeb 				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
1950ac13930bSmikeb 				       reg);
1951ac13930bSmikeb 
1952ac13930bSmikeb 	return status;
1953ac13930bSmikeb }
1954ac13930bSmikeb 
1955ac13930bSmikeb /**
1956ac13930bSmikeb  *  ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed.
1957ac13930bSmikeb  *  @hw: pointer to hardware structure
1958ac13930bSmikeb  *  @speed: link speed
1959ac13930bSmikeb  *
1960ac13930bSmikeb  *  Configures the integrated KR PHY.
1961ac13930bSmikeb  **/
1962ac13930bSmikeb int32_t ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw,
1963ac13930bSmikeb 				    ixgbe_link_speed speed)
1964ac13930bSmikeb {
1965ac13930bSmikeb 	int32_t status;
1966ac13930bSmikeb 	uint32_t reg_val;
1967ac13930bSmikeb 
1968d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
1969ac13930bSmikeb 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1970ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
1971ac13930bSmikeb 	if (status)
1972ac13930bSmikeb 		return status;
1973ac13930bSmikeb 
1974ac13930bSmikeb 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
1975ac13930bSmikeb 	reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
1976ac13930bSmikeb 		     IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
1977ac13930bSmikeb 
1978ac13930bSmikeb 	/* Advertise 10G support. */
1979ac13930bSmikeb 	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
1980ac13930bSmikeb 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
1981ac13930bSmikeb 
1982ac13930bSmikeb 	/* Advertise 1G support. */
1983ac13930bSmikeb 	if (speed & IXGBE_LINK_SPEED_1GB_FULL)
1984ac13930bSmikeb 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
1985ac13930bSmikeb 
1986d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
1987ac13930bSmikeb 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1988ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
1989ac13930bSmikeb 
1990d7a8f955Sjmatthew 	if (hw->mac.type == ixgbe_mac_X550EM_a) {
1991d7a8f955Sjmatthew 		/* Set lane mode  to KR auto negotiation */
1992d7a8f955Sjmatthew 		status = hw->mac.ops.read_iosf_sb_reg(hw,
1993d7a8f955Sjmatthew 				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1994d7a8f955Sjmatthew 				    IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
1995d7a8f955Sjmatthew 
1996d7a8f955Sjmatthew 		if (status)
1997ac13930bSmikeb 			return status;
1998d7a8f955Sjmatthew 
1999d7a8f955Sjmatthew 		reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
2000d7a8f955Sjmatthew 		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN;
2001d7a8f955Sjmatthew 		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
2002d7a8f955Sjmatthew 		reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
2003d7a8f955Sjmatthew 		reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
2004d7a8f955Sjmatthew 
2005d7a8f955Sjmatthew 		status = hw->mac.ops.write_iosf_sb_reg(hw,
2006d7a8f955Sjmatthew 				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2007d7a8f955Sjmatthew 				    IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2008d7a8f955Sjmatthew 	}
2009d7a8f955Sjmatthew 
2010d7a8f955Sjmatthew 	return ixgbe_restart_an_internal_phy_x550em(hw);
2011d7a8f955Sjmatthew }
2012d7a8f955Sjmatthew 
2013d7a8f955Sjmatthew /**
2014d7a8f955Sjmatthew  * ixgbe_reset_phy_fw - Reset firmware-controlled PHYs
2015d7a8f955Sjmatthew  * @hw: pointer to hardware structure
2016d7a8f955Sjmatthew  */
2017d7a8f955Sjmatthew int32_t ixgbe_reset_phy_fw(struct ixgbe_hw *hw)
2018d7a8f955Sjmatthew {
2019d7a8f955Sjmatthew 	uint32_t store[FW_PHY_ACT_DATA_COUNT] = { 0 };
2020d7a8f955Sjmatthew 	int32_t rc;
2021d7a8f955Sjmatthew 
2022d7a8f955Sjmatthew 	if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw))
2023d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
2024d7a8f955Sjmatthew 
2025d7a8f955Sjmatthew 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_PHY_SW_RESET, &store);
2026d7a8f955Sjmatthew 	if (rc)
2027d7a8f955Sjmatthew 		return rc;
2028d7a8f955Sjmatthew 	memset(store, 0, sizeof(store));
2029d7a8f955Sjmatthew 
2030d7a8f955Sjmatthew 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_INIT_PHY, &store);
2031d7a8f955Sjmatthew 	if (rc)
2032d7a8f955Sjmatthew 		return rc;
2033d7a8f955Sjmatthew 
2034d7a8f955Sjmatthew 	return ixgbe_setup_fw_link(hw);
2035d7a8f955Sjmatthew }
2036d7a8f955Sjmatthew 
2037d7a8f955Sjmatthew /**
2038d7a8f955Sjmatthew  * ixgbe_check_overtemp_fw - Check firmware-controlled PHYs for overtemp
2039d7a8f955Sjmatthew  * @hw: pointer to hardware structure
2040d7a8f955Sjmatthew  */
2041d7a8f955Sjmatthew int32_t ixgbe_check_overtemp_fw(struct ixgbe_hw *hw)
2042d7a8f955Sjmatthew {
2043d7a8f955Sjmatthew 	uint32_t store[FW_PHY_ACT_DATA_COUNT] = { 0 };
2044d7a8f955Sjmatthew 	int32_t rc;
2045d7a8f955Sjmatthew 
2046d7a8f955Sjmatthew 	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store);
2047d7a8f955Sjmatthew 	if (rc)
2048d7a8f955Sjmatthew 		return rc;
2049d7a8f955Sjmatthew 
2050d7a8f955Sjmatthew 	if (store[0] & FW_PHY_ACT_GET_LINK_INFO_TEMP) {
2051d7a8f955Sjmatthew 		ixgbe_shutdown_fw_phy(hw);
2052d7a8f955Sjmatthew 		return IXGBE_ERR_OVERTEMP;
2053d7a8f955Sjmatthew 	}
2054d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
2055d7a8f955Sjmatthew }
2056d7a8f955Sjmatthew 
2057d7a8f955Sjmatthew /**
2058d7a8f955Sjmatthew  *  ixgbe_read_mng_if_sel_x550em - Read NW_MNG_IF_SEL register
2059d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
2060d7a8f955Sjmatthew  *
2061d7a8f955Sjmatthew  *  Read NW_MNG_IF_SEL register and save field values, and check for valid field
2062d7a8f955Sjmatthew  *  values.
2063d7a8f955Sjmatthew  **/
2064d7a8f955Sjmatthew int32_t ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw)
2065d7a8f955Sjmatthew {
2066d7a8f955Sjmatthew 	/* Save NW management interface connected on board. This is used
2067d7a8f955Sjmatthew 	 * to determine internal PHY mode.
2068d7a8f955Sjmatthew 	 */
2069d7a8f955Sjmatthew 	hw->phy.nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
2070d7a8f955Sjmatthew 
2071d7a8f955Sjmatthew 	/* If X552 (X550EM_a) and MDIO is connected to external PHY, then set
2072d7a8f955Sjmatthew 	 * PHY address. This register field was has only been used for X552.
2073d7a8f955Sjmatthew 	 */
2074d7a8f955Sjmatthew 	if (hw->mac.type == ixgbe_mac_X550EM_a &&
2075d7a8f955Sjmatthew 	    hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_MDIO_ACT) {
2076d7a8f955Sjmatthew 		hw->phy.addr = (hw->phy.nw_mng_if_sel &
2077d7a8f955Sjmatthew 				IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
2078d7a8f955Sjmatthew 			       IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
2079d7a8f955Sjmatthew 	}
2080d7a8f955Sjmatthew 
2081d7a8f955Sjmatthew 	return IXGBE_SUCCESS;
2082ac13930bSmikeb }
2083ac13930bSmikeb 
2084ac13930bSmikeb /**
2085ac13930bSmikeb  *  ixgbe_init_phy_ops_X550em - PHY/SFP specific init
2086ac13930bSmikeb  *  @hw: pointer to hardware structure
2087ac13930bSmikeb  *
2088ac13930bSmikeb  *  Initialize any function pointers that were not able to be
2089ac13930bSmikeb  *  set during init_shared_code because the PHY/SFP type was
2090ac13930bSmikeb  *  not known.  Perform the SFP init if necessary.
2091ac13930bSmikeb  */
2092ac13930bSmikeb int32_t ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
2093ac13930bSmikeb {
2094ac13930bSmikeb 	struct ixgbe_phy_info *phy = &hw->phy;
2095ac13930bSmikeb 	int32_t ret_val;
2096ac13930bSmikeb 
2097ac13930bSmikeb 	DEBUGFUNC("ixgbe_init_phy_ops_X550em");
2098ac13930bSmikeb 
2099ac13930bSmikeb 	hw->mac.ops.set_lan_id(hw);
2100d7a8f955Sjmatthew 	ixgbe_read_mng_if_sel_x550em(hw);
2101ac13930bSmikeb 
2102ac13930bSmikeb 	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
2103ac13930bSmikeb 		phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
2104ac13930bSmikeb 		ixgbe_setup_mux_ctl(hw);
2105457e2542Sderaadt 		phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em;
21067042a378Sderaadt 	}
21077042a378Sderaadt 
2108d7a8f955Sjmatthew 	switch (hw->device_id) {
2109d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T:
2110d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
2111d7a8f955Sjmatthew 		phy->ops.read_reg_mdi = NULL;
2112d7a8f955Sjmatthew 		phy->ops.write_reg_mdi = NULL;
2113d7a8f955Sjmatthew 		hw->phy.ops.read_reg = NULL;
2114d7a8f955Sjmatthew 		hw->phy.ops.write_reg = NULL;
2115d7a8f955Sjmatthew 		phy->ops.check_overtemp = ixgbe_check_overtemp_fw;
2116d7a8f955Sjmatthew 		if (hw->bus.lan_id)
2117d7a8f955Sjmatthew 			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
2118d7a8f955Sjmatthew 		else
2119d7a8f955Sjmatthew 			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
2120d7a8f955Sjmatthew 
2121d7a8f955Sjmatthew 		break;
2122d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_10G_T:
2123d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SFP:
2124d7a8f955Sjmatthew 		hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
2125d7a8f955Sjmatthew 		hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
2126d7a8f955Sjmatthew 		if (hw->bus.lan_id)
2127d7a8f955Sjmatthew 			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
2128d7a8f955Sjmatthew 		else
2129d7a8f955Sjmatthew 			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
2130d7a8f955Sjmatthew 		break;
2131d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_SFP:
2132d7a8f955Sjmatthew 		/* set up for CS4227 usage */
2133d7a8f955Sjmatthew 		hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
2134d7a8f955Sjmatthew 		break;
2135d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_1G_T:
2136d7a8f955Sjmatthew 		phy->ops.read_reg_mdi = NULL;
2137d7a8f955Sjmatthew 		phy->ops.write_reg_mdi = NULL;
2138d7a8f955Sjmatthew 	default:
2139d7a8f955Sjmatthew 		break;
2140d7a8f955Sjmatthew 	}
2141d7a8f955Sjmatthew 
2142ac13930bSmikeb 	/* Identify the PHY or SFP module */
2143ac13930bSmikeb 	ret_val = phy->ops.identify(hw);
2144d7a8f955Sjmatthew 	if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED ||
2145d7a8f955Sjmatthew 	    ret_val == IXGBE_ERR_PHY_ADDR_INVALID)
2146ac13930bSmikeb 		return ret_val;
2147ac13930bSmikeb 
2148ac13930bSmikeb 	/* Setup function pointers based on detected hardware */
2149ac13930bSmikeb 	ixgbe_init_mac_link_ops_X550em(hw);
2150ac13930bSmikeb 	if (phy->sfp_type != ixgbe_sfp_type_unknown)
2151ac13930bSmikeb 		phy->ops.reset = NULL;
2152ac13930bSmikeb 
2153ac13930bSmikeb 	/* Set functions pointers based on phy type */
2154ac13930bSmikeb 	switch (hw->phy.type) {
2155ac13930bSmikeb 	case ixgbe_phy_x550em_kx4:
2156ac13930bSmikeb 		phy->ops.setup_link = NULL;
2157ac13930bSmikeb 		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
2158ac13930bSmikeb 		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
2159ac13930bSmikeb 		break;
2160ac13930bSmikeb 	case ixgbe_phy_x550em_kr:
2161ac13930bSmikeb 		phy->ops.setup_link = ixgbe_setup_kr_x550em;
2162ac13930bSmikeb 		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
2163ac13930bSmikeb 		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
2164ac13930bSmikeb 		break;
2165d7a8f955Sjmatthew 	case ixgbe_phy_ext_1g_t:
2166d7a8f955Sjmatthew 		/* link is managed by FW */
2167d7a8f955Sjmatthew 		phy->ops.setup_link = NULL;
2168d7a8f955Sjmatthew 		phy->ops.reset = NULL;
2169d7a8f955Sjmatthew 		break;
2170d7a8f955Sjmatthew 	case ixgbe_phy_x550em_xfi:
2171d7a8f955Sjmatthew 		/* link is managed by HW */
2172d7a8f955Sjmatthew 		phy->ops.setup_link = NULL;
2173d7a8f955Sjmatthew 		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
2174d7a8f955Sjmatthew 		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
2175d7a8f955Sjmatthew 		break;
2176ac13930bSmikeb 	case ixgbe_phy_x550em_ext_t:
2177ac13930bSmikeb 		/* If internal link mode is XFI, then setup iXFI internal link,
2178ac13930bSmikeb 		 * else setup KR now.
2179ac13930bSmikeb 		 */
2180ac13930bSmikeb 		phy->ops.setup_internal_link =
2181ac13930bSmikeb 					      ixgbe_setup_internal_phy_t_x550em;
2182d7a8f955Sjmatthew 
2183d7a8f955Sjmatthew 		/* setup SW LPLU only for first revision of X550EM_x */
2184d7a8f955Sjmatthew 		if ((hw->mac.type == ixgbe_mac_X550EM_x) &&
2185d7a8f955Sjmatthew 		    !(IXGBE_FUSES0_REV_MASK &
2186d7a8f955Sjmatthew 		      IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))))
2187d7a8f955Sjmatthew 			phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em;
2188ac13930bSmikeb 
2189ac13930bSmikeb 		phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
2190ac13930bSmikeb 		phy->ops.reset = ixgbe_reset_phy_t_X550em;
2191ac13930bSmikeb 		break;
2192d7a8f955Sjmatthew 	case ixgbe_phy_sgmii:
2193d7a8f955Sjmatthew 		phy->ops.setup_link = NULL;
2194d7a8f955Sjmatthew 		break;
2195d7a8f955Sjmatthew 	case ixgbe_phy_fw:
2196d7a8f955Sjmatthew 		phy->ops.setup_link = ixgbe_setup_fw_link;
2197d7a8f955Sjmatthew 		phy->ops.reset = ixgbe_reset_phy_fw;
2198d7a8f955Sjmatthew 		break;
2199ac13930bSmikeb 	default:
2200ac13930bSmikeb 		break;
2201ac13930bSmikeb 	}
2202ac13930bSmikeb 	return ret_val;
2203ac13930bSmikeb }
2204ac13930bSmikeb 
2205ac13930bSmikeb /**
2206d7a8f955Sjmatthew  * ixgbe_set_mdio_speed - Set MDIO clock speed
2207d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
2208d7a8f955Sjmatthew  */
2209d7a8f955Sjmatthew void ixgbe_set_mdio_speed(struct ixgbe_hw *hw)
2210d7a8f955Sjmatthew {
2211d7a8f955Sjmatthew 	uint32_t hlreg0;
2212d7a8f955Sjmatthew 
2213d7a8f955Sjmatthew 	switch (hw->device_id) {
2214d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_10G_T:
2215d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SGMII:
2216d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
2217d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_10G_T:
2218d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_SFP:
2219d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_QSFP:
2220d7a8f955Sjmatthew 		/* Config MDIO clock speed before the first MDIO PHY access */
2221d7a8f955Sjmatthew 		hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2222d7a8f955Sjmatthew 		hlreg0 &= ~IXGBE_HLREG0_MDCSPD;
2223d7a8f955Sjmatthew 		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
2224d7a8f955Sjmatthew 		break;
2225d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T:
2226d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
2227d7a8f955Sjmatthew 		/* Select fast MDIO clock speed for these devices */
2228d7a8f955Sjmatthew 		hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2229d7a8f955Sjmatthew 		hlreg0 |= IXGBE_HLREG0_MDCSPD;
2230d7a8f955Sjmatthew 		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
2231d7a8f955Sjmatthew 		break;
2232d7a8f955Sjmatthew 	default:
2233d7a8f955Sjmatthew 		break;
2234d7a8f955Sjmatthew 	}
2235d7a8f955Sjmatthew }
2236d7a8f955Sjmatthew 
2237d7a8f955Sjmatthew /**
2238ac13930bSmikeb  *  ixgbe_reset_hw_X550em - Perform hardware reset
2239ac13930bSmikeb  *  @hw: pointer to hardware structure
2240ac13930bSmikeb  *
2241ac13930bSmikeb  *  Resets the hardware by resetting the transmit and receive units, masks
2242ac13930bSmikeb  *  and clears all interrupts, perform a PHY reset, and perform a link (MAC)
2243ac13930bSmikeb  *  reset.
2244ac13930bSmikeb  */
2245ac13930bSmikeb int32_t ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
2246ac13930bSmikeb {
2247ac13930bSmikeb 	ixgbe_link_speed link_speed;
2248ac13930bSmikeb 	int32_t status;
2249ac13930bSmikeb 	uint32_t ctrl = 0;
2250ac13930bSmikeb 	uint32_t i;
2251ac13930bSmikeb 	bool link_up = FALSE;
2252d7a8f955Sjmatthew 	uint32_t swfw_mask = hw->phy.phy_semaphore_mask;
2253ac13930bSmikeb 
2254ac13930bSmikeb 	DEBUGFUNC("ixgbe_reset_hw_X550em");
2255ac13930bSmikeb 
2256ac13930bSmikeb 	/* Call adapter stop to disable Tx/Rx and clear interrupts */
2257ac13930bSmikeb 	status = hw->mac.ops.stop_adapter(hw);
2258d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS) {
2259d7a8f955Sjmatthew 		DEBUGOUT1("Failed to stop adapter, STATUS = %d\n", status);
2260ac13930bSmikeb 		return status;
2261d7a8f955Sjmatthew 	}
2262ac13930bSmikeb 	/* flush pending Tx transactions */
2263ac13930bSmikeb 	ixgbe_clear_tx_pending(hw);
2264ac13930bSmikeb 
2265d7a8f955Sjmatthew 	ixgbe_set_mdio_speed(hw);
2266ac13930bSmikeb 
2267ac13930bSmikeb 	/* PHY ops must be identified and initialized prior to reset */
2268ac13930bSmikeb 	status = hw->phy.ops.init(hw);
2269ac13930bSmikeb 
2270d7a8f955Sjmatthew 	if (status)
2271d7a8f955Sjmatthew 		DEBUGOUT1("Failed to initialize PHY ops, STATUS = %d\n",
2272d7a8f955Sjmatthew 			  status);
2273d7a8f955Sjmatthew 
2274d7a8f955Sjmatthew 	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED ||
2275d7a8f955Sjmatthew 	    status == IXGBE_ERR_PHY_ADDR_INVALID) {
2276d7a8f955Sjmatthew 		DEBUGOUT("Returning from reset HW due to PHY init failure\n");
2277ac13930bSmikeb 		return status;
2278d7a8f955Sjmatthew 	}
2279ac13930bSmikeb 
2280ac13930bSmikeb 	/* start the external PHY */
2281ac13930bSmikeb 	if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
2282ac13930bSmikeb 		status = ixgbe_init_ext_t_x550em(hw);
2283d7a8f955Sjmatthew 		if (status) {
2284d7a8f955Sjmatthew 			DEBUGOUT1("Failed to start the external PHY, STATUS = %d\n",
2285d7a8f955Sjmatthew 				  status);
2286ac13930bSmikeb 			return status;
2287ac13930bSmikeb 		}
2288d7a8f955Sjmatthew 	}
2289ac13930bSmikeb 
2290ac13930bSmikeb 	/* Setup SFP module if there is one present. */
2291ac13930bSmikeb 	if (hw->phy.sfp_setup_needed) {
2292ac13930bSmikeb 		status = hw->mac.ops.setup_sfp(hw);
2293ac13930bSmikeb 		hw->phy.sfp_setup_needed = FALSE;
2294ac13930bSmikeb 	}
2295ac13930bSmikeb 
2296ac13930bSmikeb 	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
2297ac13930bSmikeb 		return status;
2298ac13930bSmikeb 
2299ac13930bSmikeb 	/* Reset PHY */
2300d7a8f955Sjmatthew 	if (!hw->phy.reset_disable && hw->phy.ops.reset) {
2301d7a8f955Sjmatthew 		if (hw->phy.ops.reset(hw) == IXGBE_ERR_OVERTEMP)
2302d7a8f955Sjmatthew 			return IXGBE_ERR_OVERTEMP;
2303d7a8f955Sjmatthew 	}
2304ac13930bSmikeb 
2305ac13930bSmikeb mac_reset_top:
2306ac13930bSmikeb 	/* Issue global reset to the MAC.  Needs to be SW reset if link is up.
2307ac13930bSmikeb 	 * If link reset is used when link is up, it might reset the PHY when
2308ac13930bSmikeb 	 * mng is using it.  If link is down or the flag to force full link
2309ac13930bSmikeb 	 * reset is set, then perform link reset.
2310ac13930bSmikeb 	 */
2311ac13930bSmikeb 	ctrl = IXGBE_CTRL_LNK_RST;
2312ac13930bSmikeb 	if (!hw->force_full_reset) {
2313ac13930bSmikeb 		hw->mac.ops.check_link(hw, &link_speed, &link_up, FALSE);
2314ac13930bSmikeb 		if (link_up)
2315ac13930bSmikeb 			ctrl = IXGBE_CTRL_RST;
2316ac13930bSmikeb 	}
2317ac13930bSmikeb 
2318d7a8f955Sjmatthew 	status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
2319d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS) {
2320d7a8f955Sjmatthew 		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
2321d7a8f955Sjmatthew 			"semaphore failed with %d", status);
2322d7a8f955Sjmatthew 		return IXGBE_ERR_SWFW_SYNC;
2323d7a8f955Sjmatthew 	}
2324ac13930bSmikeb 	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
2325ac13930bSmikeb 	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
2326ac13930bSmikeb 	IXGBE_WRITE_FLUSH(hw);
2327d7a8f955Sjmatthew 	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
2328ac13930bSmikeb 
2329ac13930bSmikeb 	/* Poll for reset bit to self-clear meaning reset is complete */
2330ac13930bSmikeb 	for (i = 0; i < 10; i++) {
2331ac13930bSmikeb 		usec_delay(1);
2332ac13930bSmikeb 		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
2333ac13930bSmikeb 		if (!(ctrl & IXGBE_CTRL_RST_MASK))
2334ac13930bSmikeb 			break;
2335ac13930bSmikeb 	}
2336ac13930bSmikeb 
2337ac13930bSmikeb 	if (ctrl & IXGBE_CTRL_RST_MASK) {
2338ac13930bSmikeb 		status = IXGBE_ERR_RESET_FAILED;
2339ac13930bSmikeb 		DEBUGOUT("Reset polling failed to complete.\n");
2340ac13930bSmikeb 	}
2341ac13930bSmikeb 
2342ac13930bSmikeb 	msec_delay(50);
2343ac13930bSmikeb 
2344ac13930bSmikeb 	/* Double resets are required for recovery from certain error
2345ac13930bSmikeb 	 * conditions.  Between resets, it is necessary to stall to
2346ac13930bSmikeb 	 * allow time for any pending HW events to complete.
2347ac13930bSmikeb 	 */
2348ac13930bSmikeb 	if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
2349ac13930bSmikeb 		hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
2350ac13930bSmikeb 		goto mac_reset_top;
2351ac13930bSmikeb 	}
2352ac13930bSmikeb 
2353ac13930bSmikeb 	/* Store the permanent mac address */
2354ac13930bSmikeb 	hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
2355ac13930bSmikeb 
2356ac13930bSmikeb 	/* Store MAC address from RAR0, clear receive address registers, and
2357ac13930bSmikeb 	 * clear the multicast table.  Also reset num_rar_entries to 128,
2358ac13930bSmikeb 	 * since we modify this value when programming the SAN MAC address.
2359ac13930bSmikeb 	 */
2360ac13930bSmikeb 	hw->mac.num_rar_entries = 128;
2361ac13930bSmikeb 	hw->mac.ops.init_rx_addrs(hw);
2362ac13930bSmikeb 
2363d7a8f955Sjmatthew 	ixgbe_set_mdio_speed(hw);
2364d7a8f955Sjmatthew 
2365ac13930bSmikeb 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
2366ac13930bSmikeb 		ixgbe_setup_mux_ctl(hw);
2367ac13930bSmikeb 
2368d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2369d7a8f955Sjmatthew 		DEBUGOUT1("Reset HW failed, STATUS = %d\n", status);
2370d7a8f955Sjmatthew 
2371ac13930bSmikeb 	return status;
2372ac13930bSmikeb }
2373ac13930bSmikeb 
2374ac13930bSmikeb /**
2375ac13930bSmikeb  * ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY.
2376ac13930bSmikeb  * @hw: pointer to hardware structure
2377ac13930bSmikeb  */
2378ac13930bSmikeb int32_t ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
2379ac13930bSmikeb {
2380ac13930bSmikeb 	uint32_t status;
2381ac13930bSmikeb 	uint16_t reg;
2382ac13930bSmikeb 
2383ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw,
2384ac13930bSmikeb 				      IXGBE_MDIO_TX_VENDOR_ALARMS_3,
2385ac13930bSmikeb 				      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
2386ac13930bSmikeb 				      &reg);
2387ac13930bSmikeb 
2388ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2389ac13930bSmikeb 		return status;
2390ac13930bSmikeb 
2391ac13930bSmikeb 	/* If PHY FW reset completed bit is set then this is the first
2392ac13930bSmikeb 	 * SW instance after a power on so the PHY FW must be un-stalled.
2393ac13930bSmikeb 	 */
2394ac13930bSmikeb 	if (reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
2395ac13930bSmikeb 		status = hw->phy.ops.read_reg(hw,
2396ac13930bSmikeb 					IXGBE_MDIO_GLOBAL_RES_PR_10,
2397ac13930bSmikeb 					IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2398ac13930bSmikeb 					&reg);
2399ac13930bSmikeb 
2400ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
2401ac13930bSmikeb 			return status;
2402ac13930bSmikeb 
2403ac13930bSmikeb 		reg &= ~IXGBE_MDIO_POWER_UP_STALL;
2404ac13930bSmikeb 
2405ac13930bSmikeb 		status = hw->phy.ops.write_reg(hw,
2406ac13930bSmikeb 					IXGBE_MDIO_GLOBAL_RES_PR_10,
2407ac13930bSmikeb 					IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2408ac13930bSmikeb 					reg);
2409ac13930bSmikeb 
2410ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
2411ac13930bSmikeb 			return status;
2412ac13930bSmikeb 	}
2413ac13930bSmikeb 
2414ac13930bSmikeb 	return status;
2415ac13930bSmikeb }
2416ac13930bSmikeb 
2417ac13930bSmikeb /**
2418ac13930bSmikeb  *  ixgbe_setup_kr_x550em - Configure the KR PHY.
2419ac13930bSmikeb  *  @hw: pointer to hardware structure
2420ac13930bSmikeb  **/
2421ac13930bSmikeb int32_t ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
2422ac13930bSmikeb {
2423d7a8f955Sjmatthew 	/* leave link alone for 2.5G */
2424d7a8f955Sjmatthew 	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
2425d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
2426d7a8f955Sjmatthew 
2427d7a8f955Sjmatthew 	if (ixgbe_check_reset_blocked(hw))
2428d7a8f955Sjmatthew 		return 0;
2429d7a8f955Sjmatthew 
2430ac13930bSmikeb 	return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised);
2431ac13930bSmikeb }
2432ac13930bSmikeb 
2433ac13930bSmikeb /**
2434ac13930bSmikeb  *  ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP
2435ac13930bSmikeb  *  @hw: pointer to hardware structure
2436d7a8f955Sjmatthew  *  @speed: new link speed
2437d7a8f955Sjmatthew  *  @autoneg_wait_to_complete: unused
2438ac13930bSmikeb  *
2439ac13930bSmikeb  *  Configure the external PHY and the integrated KR PHY for SFP support.
2440ac13930bSmikeb  **/
2441ac13930bSmikeb int32_t ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
2442ac13930bSmikeb 					ixgbe_link_speed speed,
2443ac13930bSmikeb 					bool autoneg_wait_to_complete)
2444ac13930bSmikeb {
2445ac13930bSmikeb 	int32_t ret_val;
2446ac13930bSmikeb 	uint16_t reg_slice, reg_val;
2447ac13930bSmikeb 	bool setup_linear = FALSE;
2448ac13930bSmikeb 
2449ac13930bSmikeb 	/* Check if SFP module is supported and linear */
2450ac13930bSmikeb 	ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
2451ac13930bSmikeb 
2452ac13930bSmikeb 	/* If no SFP module present, then return success. Return success since
2453ac13930bSmikeb 	 * there is no reason to configure CS4227 and SFP not present error is
2454ac13930bSmikeb 	 * not excepted in the setup MAC link flow.
2455ac13930bSmikeb 	 */
2456ac13930bSmikeb 	if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
2457ac13930bSmikeb 		return IXGBE_SUCCESS;
2458ac13930bSmikeb 
2459ac13930bSmikeb 	if (ret_val != IXGBE_SUCCESS)
2460ac13930bSmikeb 		return ret_val;
2461ac13930bSmikeb 
2462ac13930bSmikeb 	/* Configure internal PHY for KR/KX. */
2463ac13930bSmikeb 	ixgbe_setup_kr_speed_x550em(hw, speed);
2464ac13930bSmikeb 
2465ac13930bSmikeb 	/* Configure CS4227 LINE side to proper mode. */
2466ac13930bSmikeb 	reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB +
2467ac13930bSmikeb 		    (hw->bus.lan_id << 12);
2468ac13930bSmikeb 	if (setup_linear)
2469ac13930bSmikeb 		reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
2470ac13930bSmikeb 	else
2471ac13930bSmikeb 		reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
2472d7a8f955Sjmatthew 	ret_val = hw->link.ops.write_link(hw, hw->link.addr, reg_slice,
2473d7a8f955Sjmatthew 					  reg_val);
2474d7a8f955Sjmatthew 	return ret_val;
2475d7a8f955Sjmatthew }
2476d7a8f955Sjmatthew 
2477d7a8f955Sjmatthew /**
2478d7a8f955Sjmatthew  *  ixgbe_setup_sfi_x550a - Configure the internal PHY for native SFI mode
2479d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
2480d7a8f955Sjmatthew  *  @speed: the link speed to force
2481d7a8f955Sjmatthew  *
2482d7a8f955Sjmatthew  *  Configures the integrated PHY for native SFI mode. Used to connect the
2483d7a8f955Sjmatthew  *  internal PHY directly to an SFP cage, without autonegotiation.
2484d7a8f955Sjmatthew  **/
2485d7a8f955Sjmatthew int32_t ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
2486d7a8f955Sjmatthew {
2487d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
2488d7a8f955Sjmatthew 	int32_t status;
2489d7a8f955Sjmatthew 	uint32_t reg_val;
2490d7a8f955Sjmatthew 
2491d7a8f955Sjmatthew 	/* Disable all AN and force speed to 10G Serial. */
2492d7a8f955Sjmatthew 	status = mac->ops.read_iosf_sb_reg(hw,
2493d7a8f955Sjmatthew 				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2494d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2495d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2496d7a8f955Sjmatthew 		return status;
2497d7a8f955Sjmatthew 
2498d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
2499d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
2500d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
2501d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
2502d7a8f955Sjmatthew 
2503d7a8f955Sjmatthew 	/* Select forced link speed for internal PHY. */
2504d7a8f955Sjmatthew 	switch (*speed) {
2505d7a8f955Sjmatthew 	case IXGBE_LINK_SPEED_10GB_FULL:
2506d7a8f955Sjmatthew 		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_10G;
2507d7a8f955Sjmatthew 		break;
2508d7a8f955Sjmatthew 	case IXGBE_LINK_SPEED_1GB_FULL:
2509d7a8f955Sjmatthew 		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G;
2510d7a8f955Sjmatthew 		break;
2511d7a8f955Sjmatthew 	default:
2512d7a8f955Sjmatthew 		/* Other link speeds are not supported by internal PHY. */
2513d7a8f955Sjmatthew 		return IXGBE_ERR_LINK_SETUP;
2514d7a8f955Sjmatthew 	}
2515d7a8f955Sjmatthew 
2516d7a8f955Sjmatthew 	status = mac->ops.write_iosf_sb_reg(hw,
2517d7a8f955Sjmatthew 				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2518d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2519d7a8f955Sjmatthew 
2520d7a8f955Sjmatthew 	/* Toggle port SW reset by AN reset. */
2521d7a8f955Sjmatthew 	status = ixgbe_restart_an_internal_phy_x550em(hw);
2522d7a8f955Sjmatthew 
2523d7a8f955Sjmatthew 	return status;
2524d7a8f955Sjmatthew }
2525d7a8f955Sjmatthew 
2526d7a8f955Sjmatthew /**
2527d7a8f955Sjmatthew  *  ixgbe_setup_mac_link_sfp_x550a - Setup internal PHY for SFP
2528d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
2529d7a8f955Sjmatthew  *  @speed: new link speed
2530d7a8f955Sjmatthew  *  @autoneg_wait_to_complete: unused
2531d7a8f955Sjmatthew  *
25324b1a56afSjsg  *  Configure the integrated PHY for SFP support.
2533d7a8f955Sjmatthew  **/
2534d7a8f955Sjmatthew int32_t ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw,
2535d7a8f955Sjmatthew 				       ixgbe_link_speed speed,
2536d7a8f955Sjmatthew 				       bool autoneg_wait_to_complete)
2537d7a8f955Sjmatthew {
2538d7a8f955Sjmatthew 	int32_t ret_val;
2539d7a8f955Sjmatthew 	uint16_t reg_phy_ext;
2540d7a8f955Sjmatthew 	bool setup_linear = FALSE;
2541d7a8f955Sjmatthew 	uint32_t reg_slice, reg_phy_int, slice_offset;
2542d7a8f955Sjmatthew 
2543d7a8f955Sjmatthew 	/* Check if SFP module is supported and linear */
2544d7a8f955Sjmatthew 	ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
2545d7a8f955Sjmatthew 
2546d7a8f955Sjmatthew 	/* If no SFP module present, then return success. Return success since
2547d7a8f955Sjmatthew 	 * SFP not present error is not excepted in the setup MAC link flow.
2548d7a8f955Sjmatthew 	 */
2549d7a8f955Sjmatthew 	if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
2550d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
2551d7a8f955Sjmatthew 
2552d7a8f955Sjmatthew 	if (ret_val != IXGBE_SUCCESS)
2553d7a8f955Sjmatthew 		return ret_val;
2554d7a8f955Sjmatthew 
2555d7a8f955Sjmatthew 	if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) {
2556d7a8f955Sjmatthew 		/* Configure internal PHY for native SFI based on module type */
2557d7a8f955Sjmatthew 		ret_val = hw->mac.ops.read_iosf_sb_reg(hw,
2558d7a8f955Sjmatthew 				   IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2559d7a8f955Sjmatthew 				   IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_phy_int);
2560d7a8f955Sjmatthew 
2561d7a8f955Sjmatthew 		if (ret_val != IXGBE_SUCCESS)
2562d7a8f955Sjmatthew 			return ret_val;
2563d7a8f955Sjmatthew 
2564d7a8f955Sjmatthew 		reg_phy_int &= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA;
2565d7a8f955Sjmatthew 		if (!setup_linear)
2566d7a8f955Sjmatthew 			reg_phy_int |= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_SR;
2567d7a8f955Sjmatthew 
2568d7a8f955Sjmatthew 		ret_val = hw->mac.ops.write_iosf_sb_reg(hw,
2569d7a8f955Sjmatthew 				   IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2570d7a8f955Sjmatthew 				   IXGBE_SB_IOSF_TARGET_KR_PHY, reg_phy_int);
2571d7a8f955Sjmatthew 
2572d7a8f955Sjmatthew 		if (ret_val != IXGBE_SUCCESS)
2573d7a8f955Sjmatthew 			return ret_val;
2574d7a8f955Sjmatthew 
2575d7a8f955Sjmatthew 		/* Setup SFI internal link. */
2576d7a8f955Sjmatthew 		ret_val = ixgbe_setup_sfi_x550a(hw, &speed);
2577d7a8f955Sjmatthew 	} else {
2578d7a8f955Sjmatthew 		/* Configure internal PHY for KR/KX. */
2579d7a8f955Sjmatthew 		ixgbe_setup_kr_speed_x550em(hw, speed);
2580d7a8f955Sjmatthew 
2581d7a8f955Sjmatthew 		if (hw->phy.addr == 0x0 || hw->phy.addr == 0xFFFF) {
2582d7a8f955Sjmatthew 			/* Find Address */
2583d7a8f955Sjmatthew 			DEBUGOUT("Invalid NW_MNG_IF_SEL.MDIO_PHY_ADD value\n");
2584d7a8f955Sjmatthew 			return IXGBE_ERR_PHY_ADDR_INVALID;
2585d7a8f955Sjmatthew 		}
2586d7a8f955Sjmatthew 
2587d7a8f955Sjmatthew 		/* Get external PHY SKU id */
2588d7a8f955Sjmatthew 		ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU,
2589d7a8f955Sjmatthew 					IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
2590d7a8f955Sjmatthew 
2591d7a8f955Sjmatthew 		if (ret_val != IXGBE_SUCCESS)
2592d7a8f955Sjmatthew 			return ret_val;
2593d7a8f955Sjmatthew 
2594d7a8f955Sjmatthew 		/* When configuring quad port CS4223, the MAC instance is part
2595d7a8f955Sjmatthew 		 * of the slice offset.
2596d7a8f955Sjmatthew 		 */
2597d7a8f955Sjmatthew 		if (reg_phy_ext == IXGBE_CS4223_SKU_ID)
2598d7a8f955Sjmatthew 			slice_offset = (hw->bus.lan_id +
2599d7a8f955Sjmatthew 					(hw->bus.instance_id << 1)) << 12;
2600d7a8f955Sjmatthew 		else
2601d7a8f955Sjmatthew 			slice_offset = hw->bus.lan_id << 12;
2602d7a8f955Sjmatthew 
2603d7a8f955Sjmatthew 		/* Configure CS4227/CS4223 LINE side to proper mode. */
2604d7a8f955Sjmatthew 		reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset;
2605d7a8f955Sjmatthew 
2606d7a8f955Sjmatthew 		ret_val = hw->phy.ops.read_reg(hw, reg_slice,
2607d7a8f955Sjmatthew 					IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
2608d7a8f955Sjmatthew 
2609d7a8f955Sjmatthew 		if (ret_val != IXGBE_SUCCESS)
2610d7a8f955Sjmatthew 			return ret_val;
2611d7a8f955Sjmatthew 
2612d7a8f955Sjmatthew 		reg_phy_ext &= ~((IXGBE_CS4227_EDC_MODE_CX1 << 1) |
2613d7a8f955Sjmatthew 				 (IXGBE_CS4227_EDC_MODE_SR << 1));
2614d7a8f955Sjmatthew 
2615d7a8f955Sjmatthew 		if (setup_linear)
2616d7a8f955Sjmatthew 			reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
2617d7a8f955Sjmatthew 		else
2618d7a8f955Sjmatthew 			reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
2619d7a8f955Sjmatthew 		ret_val = hw->phy.ops.write_reg(hw, reg_slice,
2620d7a8f955Sjmatthew 					 IXGBE_MDIO_ZERO_DEV_TYPE, reg_phy_ext);
2621d7a8f955Sjmatthew 
2622d7a8f955Sjmatthew 		/* Flush previous write with a read */
2623d7a8f955Sjmatthew 		ret_val = hw->phy.ops.read_reg(hw, reg_slice,
2624d7a8f955Sjmatthew 					IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
2625ac13930bSmikeb 	}
2626ac13930bSmikeb 	return ret_val;
2627ac13930bSmikeb }
2628ac13930bSmikeb 
2629ac13930bSmikeb /**
2630d7a8f955Sjmatthew  *  ixgbe_setup_ixfi_x550em_x - MAC specific iXFI configuration
2631d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
2632d7a8f955Sjmatthew  *
2633d7a8f955Sjmatthew  *  iXfI configuration needed for ixgbe_mac_X550EM_x devices.
2634d7a8f955Sjmatthew  **/
2635d7a8f955Sjmatthew int32_t ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw)
2636d7a8f955Sjmatthew {
2637d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
2638d7a8f955Sjmatthew 	int32_t status;
2639d7a8f955Sjmatthew 	uint32_t reg_val;
2640d7a8f955Sjmatthew 
2641d7a8f955Sjmatthew 	/* Disable training protocol FSM. */
2642d7a8f955Sjmatthew 	status = mac->ops.read_iosf_sb_reg(hw,
2643d7a8f955Sjmatthew 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
2644d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2645d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2646d7a8f955Sjmatthew 		return status;
2647d7a8f955Sjmatthew 	reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
2648d7a8f955Sjmatthew 	status = mac->ops.write_iosf_sb_reg(hw,
2649d7a8f955Sjmatthew 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
2650d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2651d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2652d7a8f955Sjmatthew 		return status;
2653d7a8f955Sjmatthew 
2654d7a8f955Sjmatthew 	/* Disable Flex from training TXFFE. */
2655d7a8f955Sjmatthew 	status = mac->ops.read_iosf_sb_reg(hw,
2656d7a8f955Sjmatthew 				IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
2657d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2658d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2659d7a8f955Sjmatthew 		return status;
2660d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
2661d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
2662d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
2663d7a8f955Sjmatthew 	status = mac->ops.write_iosf_sb_reg(hw,
2664d7a8f955Sjmatthew 				IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
2665d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2666d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2667d7a8f955Sjmatthew 		return status;
2668d7a8f955Sjmatthew 	status = mac->ops.read_iosf_sb_reg(hw,
2669d7a8f955Sjmatthew 				IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
2670d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2671d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2672d7a8f955Sjmatthew 		return status;
2673d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
2674d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
2675d7a8f955Sjmatthew 	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
2676d7a8f955Sjmatthew 	status = mac->ops.write_iosf_sb_reg(hw,
2677d7a8f955Sjmatthew 				IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
2678d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2679d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2680d7a8f955Sjmatthew 		return status;
2681d7a8f955Sjmatthew 
2682d7a8f955Sjmatthew 	/* Enable override for coefficients. */
2683d7a8f955Sjmatthew 	status = mac->ops.read_iosf_sb_reg(hw,
2684d7a8f955Sjmatthew 				IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
2685d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2686d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
2687d7a8f955Sjmatthew 		return status;
2688d7a8f955Sjmatthew 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN;
2689d7a8f955Sjmatthew 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN;
2690d7a8f955Sjmatthew 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
2691d7a8f955Sjmatthew 	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
2692d7a8f955Sjmatthew 	status = mac->ops.write_iosf_sb_reg(hw,
2693d7a8f955Sjmatthew 				IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
2694d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2695d7a8f955Sjmatthew 	return status;
2696d7a8f955Sjmatthew }
2697d7a8f955Sjmatthew 
2698d7a8f955Sjmatthew /**
2699ac13930bSmikeb  *  ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
2700ac13930bSmikeb  *  @hw: pointer to hardware structure
2701ac13930bSmikeb  *  @speed: the link speed to force
2702ac13930bSmikeb  *
2703ac13930bSmikeb  *  Configures the integrated KR PHY to use iXFI mode. Used to connect an
2704ac13930bSmikeb  *  internal and external PHY at a specific speed, without autonegotiation.
2705ac13930bSmikeb  **/
2706ac13930bSmikeb int32_t ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
2707ac13930bSmikeb {
2708d7a8f955Sjmatthew 	struct ixgbe_mac_info *mac = &hw->mac;
2709ac13930bSmikeb 	int32_t status;
2710ac13930bSmikeb 	uint32_t reg_val;
2711ac13930bSmikeb 
2712d7a8f955Sjmatthew 	/* iXFI is only supported with X552 */
2713d7a8f955Sjmatthew 	if (mac->type != ixgbe_mac_X550EM_x)
2714d7a8f955Sjmatthew 		return IXGBE_ERR_LINK_SETUP;
2715d7a8f955Sjmatthew 
2716ac13930bSmikeb 	/* Disable AN and force speed to 10G Serial. */
2717d7a8f955Sjmatthew 	status = mac->ops.read_iosf_sb_reg(hw,
2718ac13930bSmikeb 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2719ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2720ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2721ac13930bSmikeb 		return status;
2722ac13930bSmikeb 
2723ac13930bSmikeb 	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
2724ac13930bSmikeb 	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
2725ac13930bSmikeb 
2726ac13930bSmikeb 	/* Select forced link speed for internal PHY. */
2727ac13930bSmikeb 	switch (*speed) {
2728ac13930bSmikeb 	case IXGBE_LINK_SPEED_10GB_FULL:
2729ac13930bSmikeb 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
2730ac13930bSmikeb 		break;
2731ac13930bSmikeb 	case IXGBE_LINK_SPEED_1GB_FULL:
2732ac13930bSmikeb 		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
2733ac13930bSmikeb 		break;
2734ac13930bSmikeb 	default:
2735ac13930bSmikeb 		/* Other link speeds are not supported by internal KR PHY. */
2736ac13930bSmikeb 		return IXGBE_ERR_LINK_SETUP;
2737ac13930bSmikeb 	}
2738ac13930bSmikeb 
2739d7a8f955Sjmatthew 	status = mac->ops.write_iosf_sb_reg(hw,
2740ac13930bSmikeb 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2741ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2742ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2743ac13930bSmikeb 		return status;
2744ac13930bSmikeb 
2745d7a8f955Sjmatthew 	/* Additional configuration needed for x550em_x */
2746d7a8f955Sjmatthew 	if (hw->mac.type == ixgbe_mac_X550EM_x) {
2747d7a8f955Sjmatthew 		status = ixgbe_setup_ixfi_x550em_x(hw);
2748ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
2749ac13930bSmikeb 			return status;
2750d7a8f955Sjmatthew 	}
2751ac13930bSmikeb 
2752ac13930bSmikeb 	/* Toggle port SW reset by AN reset. */
2753d7a8f955Sjmatthew 	status = ixgbe_restart_an_internal_phy_x550em(hw);
2754ac13930bSmikeb 
2755ac13930bSmikeb 	return status;
2756ac13930bSmikeb }
2757ac13930bSmikeb 
2758ac13930bSmikeb /**
2759ac13930bSmikeb  * ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status
2760ac13930bSmikeb  * @hw: address of hardware structure
2761ac13930bSmikeb  * @link_up: address of boolean to indicate link status
2762ac13930bSmikeb  *
2763ac13930bSmikeb  * Returns error code if unable to get link status.
2764ac13930bSmikeb  */
2765ac13930bSmikeb int32_t ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
2766ac13930bSmikeb {
2767ac13930bSmikeb 	uint32_t ret;
2768ac13930bSmikeb 	uint16_t autoneg_status;
2769ac13930bSmikeb 
2770ac13930bSmikeb 	*link_up = FALSE;
2771ac13930bSmikeb 
2772ac13930bSmikeb 	/* read this twice back to back to indicate current status */
2773ac13930bSmikeb 	ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
2774ac13930bSmikeb 				   IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
2775ac13930bSmikeb 				   &autoneg_status);
2776ac13930bSmikeb 	if (ret != IXGBE_SUCCESS)
2777ac13930bSmikeb 		return ret;
2778ac13930bSmikeb 
2779ac13930bSmikeb 	ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
2780ac13930bSmikeb 				   IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
2781ac13930bSmikeb 				   &autoneg_status);
2782ac13930bSmikeb 	if (ret != IXGBE_SUCCESS)
2783ac13930bSmikeb 		return ret;
2784ac13930bSmikeb 
2785ac13930bSmikeb 	*link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS);
2786ac13930bSmikeb 
2787ac13930bSmikeb 	return IXGBE_SUCCESS;
2788ac13930bSmikeb }
2789ac13930bSmikeb 
2790ac13930bSmikeb /**
2791ac13930bSmikeb  * ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link
2792ac13930bSmikeb  * @hw: point to hardware structure
2793ac13930bSmikeb  *
2794ac13930bSmikeb  * Configures the link between the integrated KR PHY and the external X557 PHY
2795ac13930bSmikeb  * The driver will call this function when it gets a link status change
2796ac13930bSmikeb  * interrupt from the X557 PHY. This function configures the link speed
2797ac13930bSmikeb  * between the PHYs to match the link speed of the BASE-T link.
2798ac13930bSmikeb  *
2799ac13930bSmikeb  * A return of a non-zero value indicates an error, and the base driver should
2800ac13930bSmikeb  * not report link up.
2801ac13930bSmikeb  */
2802ac13930bSmikeb int32_t ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
2803ac13930bSmikeb {
2804ac13930bSmikeb 	ixgbe_link_speed force_speed;
2805ac13930bSmikeb 	bool link_up;
2806ac13930bSmikeb 	uint32_t status;
2807ac13930bSmikeb 	uint16_t speed;
2808ac13930bSmikeb 
2809ac13930bSmikeb 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
2810ac13930bSmikeb 		return IXGBE_ERR_CONFIG;
2811ac13930bSmikeb 
2812d7a8f955Sjmatthew 	if (hw->mac.type == ixgbe_mac_X550EM_x &&
2813d7a8f955Sjmatthew 	    !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
2814d7a8f955Sjmatthew 		/* If link is down, there is no setup necessary so return  */
2815ac13930bSmikeb 		status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
2816ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
2817ac13930bSmikeb 			return status;
2818ac13930bSmikeb 
2819ac13930bSmikeb 		if (!link_up)
2820ac13930bSmikeb 			return IXGBE_SUCCESS;
2821ac13930bSmikeb 
2822d7a8f955Sjmatthew 		status = hw->phy.ops.read_reg(hw,
2823d7a8f955Sjmatthew 					      IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
2824ac13930bSmikeb 					      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
2825ac13930bSmikeb 					      &speed);
2826ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
2827ac13930bSmikeb 			return status;
2828ac13930bSmikeb 
2829d7a8f955Sjmatthew 		/* If link is still down - no setup is required so return */
2830ac13930bSmikeb 		status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
2831ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
2832ac13930bSmikeb 			return status;
2833ac13930bSmikeb 		if (!link_up)
2834ac13930bSmikeb 			return IXGBE_SUCCESS;
2835ac13930bSmikeb 
2836ac13930bSmikeb 		/* clear everything but the speed and duplex bits */
2837ac13930bSmikeb 		speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
2838ac13930bSmikeb 
2839ac13930bSmikeb 		switch (speed) {
2840ac13930bSmikeb 		case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL:
2841ac13930bSmikeb 			force_speed = IXGBE_LINK_SPEED_10GB_FULL;
2842ac13930bSmikeb 			break;
2843ac13930bSmikeb 		case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL:
2844ac13930bSmikeb 			force_speed = IXGBE_LINK_SPEED_1GB_FULL;
2845ac13930bSmikeb 			break;
2846ac13930bSmikeb 		default:
2847ac13930bSmikeb 			/* Internal PHY does not support anything else */
2848ac13930bSmikeb 			return IXGBE_ERR_INVALID_LINK_SETTINGS;
2849ac13930bSmikeb 		}
2850ac13930bSmikeb 
2851ac13930bSmikeb 		return ixgbe_setup_ixfi_x550em(hw, &force_speed);
2852d7a8f955Sjmatthew 	} else {
2853d7a8f955Sjmatthew 		speed = IXGBE_LINK_SPEED_10GB_FULL |
2854d7a8f955Sjmatthew 			IXGBE_LINK_SPEED_1GB_FULL;
2855d7a8f955Sjmatthew 		return ixgbe_setup_kr_speed_x550em(hw, speed);
2856d7a8f955Sjmatthew 	}
2857ac13930bSmikeb }
2858ac13930bSmikeb 
2859ac13930bSmikeb /**
2860ac13930bSmikeb  *  ixgbe_setup_phy_loopback_x550em - Configure the KR PHY for loopback.
2861ac13930bSmikeb  *  @hw: pointer to hardware structure
2862ac13930bSmikeb  *
2863ac13930bSmikeb  *  Configures the integrated KR PHY to use internal loopback mode.
2864ac13930bSmikeb  **/
2865ac13930bSmikeb int32_t ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw)
2866ac13930bSmikeb {
2867ac13930bSmikeb 	int32_t status;
2868ac13930bSmikeb 	uint32_t reg_val;
2869ac13930bSmikeb 
2870ac13930bSmikeb 	/* Disable AN and force speed to 10G Serial. */
2871d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
2872ac13930bSmikeb 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2873ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2874ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2875ac13930bSmikeb 		return status;
2876ac13930bSmikeb 	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
2877ac13930bSmikeb 	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
2878ac13930bSmikeb 	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
2879d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
2880ac13930bSmikeb 					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2881ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2882ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2883ac13930bSmikeb 		return status;
2884ac13930bSmikeb 
2885ac13930bSmikeb 	/* Set near-end loopback clocks. */
2886d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
2887ac13930bSmikeb 				IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
2888ac13930bSmikeb 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2889ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2890ac13930bSmikeb 		return status;
2891ac13930bSmikeb 	reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B;
2892ac13930bSmikeb 	reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS;
2893d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
2894ac13930bSmikeb 				IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
2895ac13930bSmikeb 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2896ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2897ac13930bSmikeb 		return status;
2898ac13930bSmikeb 
2899ac13930bSmikeb 	/* Set loopback enable. */
2900d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
2901ac13930bSmikeb 				IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
2902ac13930bSmikeb 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2903ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2904ac13930bSmikeb 		return status;
2905ac13930bSmikeb 	reg_val |= IXGBE_KRM_PMD_DFX_BURNIN_TX_RX_KR_LB_MASK;
2906d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
2907ac13930bSmikeb 				IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
2908ac13930bSmikeb 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2909ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2910ac13930bSmikeb 		return status;
2911ac13930bSmikeb 
2912ac13930bSmikeb 	/* Training bypass. */
2913d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
2914ac13930bSmikeb 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
2915ac13930bSmikeb 				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2916ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
2917ac13930bSmikeb 		return status;
2918ac13930bSmikeb 	reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_PROTOCOL_BYPASS;
2919d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
2920ac13930bSmikeb 				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
2921ac13930bSmikeb 				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2922ac13930bSmikeb 
2923ac13930bSmikeb 	return status;
2924ac13930bSmikeb }
2925ac13930bSmikeb 
2926ac13930bSmikeb /**
2927ac13930bSmikeb  *  ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command
2928ac13930bSmikeb  *  assuming that the semaphore is already obtained.
2929ac13930bSmikeb  *  @hw: pointer to hardware structure
2930ac13930bSmikeb  *  @offset: offset of  word in the EEPROM to read
2931ac13930bSmikeb  *  @data: word read from the EEPROM
2932ac13930bSmikeb  *
2933ac13930bSmikeb  *  Reads a 16 bit word from the EEPROM using the hostif.
2934ac13930bSmikeb  **/
2935d7a8f955Sjmatthew int32_t ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, uint16_t offset,uint16_t *data)
2936ac13930bSmikeb {
2937d7a8f955Sjmatthew 	const uint32_t mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM;
2938457e2542Sderaadt 	struct ixgbe_hic_read_shadow_ram buffer;
2939d7a8f955Sjmatthew 	int32_t status;
2940ac13930bSmikeb 
2941d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_read_ee_hostif_X550");
2942ac13930bSmikeb 	buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
2943ac13930bSmikeb 	buffer.hdr.req.buf_lenh = 0;
2944ac13930bSmikeb 	buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
2945ac13930bSmikeb 	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
2946ac13930bSmikeb 
2947ac13930bSmikeb 	/* convert offset from words to bytes */
2948ac13930bSmikeb 	buffer.address = htobe32(offset * 2);
2949ac13930bSmikeb 	/* one word */
2950ac13930bSmikeb 	buffer.length = htobe16(sizeof(uint16_t));
2951d7a8f955Sjmatthew 	buffer.pad2 = 0;
2952d7a8f955Sjmatthew 	buffer.pad3 = 0;
2953ac13930bSmikeb 
2954d7a8f955Sjmatthew 	status = hw->mac.ops.acquire_swfw_sync(hw, mask);
2955ac13930bSmikeb 	if (status)
2956ac13930bSmikeb 		return status;
2957ac13930bSmikeb 
2958d7a8f955Sjmatthew 	status = ixgbe_hic_unlocked(hw, (uint32_t *)&buffer, sizeof(buffer),
2959d7a8f955Sjmatthew 				    IXGBE_HI_COMMAND_TIMEOUT);
2960d7a8f955Sjmatthew 	if (!status) {
2961ac13930bSmikeb 		*data = (uint16_t)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG,
2962ac13930bSmikeb 						  FW_NVM_DATA_OFFSET);
2963ac13930bSmikeb 	}
2964ac13930bSmikeb 
2965d7a8f955Sjmatthew 	hw->mac.ops.release_swfw_sync(hw, mask);
2966ac13930bSmikeb 	return status;
2967ac13930bSmikeb }
2968ac13930bSmikeb 
2969ac13930bSmikeb /**
2970ac13930bSmikeb  *  ixgbe_read_ee_hostif_buffer_X550- Read EEPROM word(s) using hostif
2971ac13930bSmikeb  *  @hw: pointer to hardware structure
2972ac13930bSmikeb  *  @offset: offset of  word in the EEPROM to read
2973ac13930bSmikeb  *  @words: number of words
2974ac13930bSmikeb  *  @data: word(s) read from the EEPROM
2975ac13930bSmikeb  *
2976ac13930bSmikeb  *  Reads a 16 bit word(s) from the EEPROM using the hostif.
2977ac13930bSmikeb  **/
2978ac13930bSmikeb int32_t ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
2979ac13930bSmikeb 					 uint16_t offset, uint16_t words,
2980ac13930bSmikeb 					 uint16_t *data)
2981ac13930bSmikeb {
2982d7a8f955Sjmatthew 	const uint32_t mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM;
2983ac13930bSmikeb 	struct ixgbe_hic_read_shadow_ram buffer;
2984ac13930bSmikeb 	uint32_t current_word = 0;
2985ac13930bSmikeb 	uint16_t words_to_read;
2986ac13930bSmikeb 	int32_t status;
2987ac13930bSmikeb 	uint32_t i;
2988ac13930bSmikeb 
2989ac13930bSmikeb 	DEBUGFUNC("ixgbe_read_ee_hostif_buffer_X550");
2990ac13930bSmikeb 
2991ac13930bSmikeb 	/* Take semaphore for the entire operation. */
2992d7a8f955Sjmatthew 	status = hw->mac.ops.acquire_swfw_sync(hw, mask);
2993ac13930bSmikeb 	if (status) {
2994ac13930bSmikeb 		DEBUGOUT("EEPROM read buffer - semaphore failed\n");
2995ac13930bSmikeb 		return status;
2996ac13930bSmikeb 	}
2997d7a8f955Sjmatthew 
2998ac13930bSmikeb 	while (words) {
2999ac13930bSmikeb 		if (words > FW_MAX_READ_BUFFER_SIZE / 2)
3000ac13930bSmikeb 			words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
3001ac13930bSmikeb 		else
3002ac13930bSmikeb 			words_to_read = words;
3003ac13930bSmikeb 
3004ac13930bSmikeb 		buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
3005ac13930bSmikeb 		buffer.hdr.req.buf_lenh = 0;
3006ac13930bSmikeb 		buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
3007ac13930bSmikeb 		buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
3008ac13930bSmikeb 
3009ac13930bSmikeb 		/* convert offset from words to bytes */
3010ac13930bSmikeb 		buffer.address = htobe32((offset + current_word) * 2);
3011ac13930bSmikeb 		buffer.length = htobe16(words_to_read * 2);
3012d7a8f955Sjmatthew 		buffer.pad2 = 0;
3013d7a8f955Sjmatthew 		buffer.pad3 = 0;
3014ac13930bSmikeb 
3015d7a8f955Sjmatthew 		status = ixgbe_hic_unlocked(hw, (uint32_t *)&buffer, sizeof(buffer),
3016d7a8f955Sjmatthew 					    IXGBE_HI_COMMAND_TIMEOUT);
3017ac13930bSmikeb 
3018ac13930bSmikeb 		if (status) {
3019ac13930bSmikeb 			DEBUGOUT("Host interface command failed\n");
3020ac13930bSmikeb 			goto out;
3021ac13930bSmikeb 		}
3022ac13930bSmikeb 
3023ac13930bSmikeb 		for (i = 0; i < words_to_read; i++) {
3024ac13930bSmikeb 			uint32_t reg = IXGBE_FLEX_MNG + (FW_NVM_DATA_OFFSET << 2) +
3025ac13930bSmikeb 				  2 * i;
3026ac13930bSmikeb 			uint32_t value = IXGBE_READ_REG(hw, reg);
3027ac13930bSmikeb 
3028ac13930bSmikeb 			data[current_word] = (uint16_t)(value & 0xffff);
3029ac13930bSmikeb 			current_word++;
3030ac13930bSmikeb 			i++;
3031ac13930bSmikeb 			if (i < words_to_read) {
3032ac13930bSmikeb 				value >>= 16;
3033ac13930bSmikeb 				data[current_word] = (uint16_t)(value & 0xffff);
3034ac13930bSmikeb 				current_word++;
3035ac13930bSmikeb 			}
3036ac13930bSmikeb 		}
3037ac13930bSmikeb 		words -= words_to_read;
3038ac13930bSmikeb 	}
3039ac13930bSmikeb 
3040ac13930bSmikeb out:
3041d7a8f955Sjmatthew 	hw->mac.ops.release_swfw_sync(hw, mask);
3042ac13930bSmikeb 	return status;
3043ac13930bSmikeb }
3044ac13930bSmikeb 
3045ac13930bSmikeb /**
3046ac13930bSmikeb  *  ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
3047ac13930bSmikeb  *  @hw: pointer to hardware structure
3048ac13930bSmikeb  *  @offset: offset of  word in the EEPROM to write
3049ac13930bSmikeb  *  @data: word write to the EEPROM
3050ac13930bSmikeb  *
3051ac13930bSmikeb  *  Write a 16 bit word to the EEPROM using the hostif.
3052ac13930bSmikeb  **/
3053ac13930bSmikeb int32_t ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, uint16_t offset,
3054ac13930bSmikeb 					uint16_t data)
3055ac13930bSmikeb {
3056ac13930bSmikeb 	int32_t status;
3057ac13930bSmikeb 	struct ixgbe_hic_write_shadow_ram buffer;
3058ac13930bSmikeb 
3059ac13930bSmikeb 	DEBUGFUNC("ixgbe_write_ee_hostif_data_X550");
3060ac13930bSmikeb 
3061ac13930bSmikeb 	buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
3062ac13930bSmikeb 	buffer.hdr.req.buf_lenh = 0;
3063ac13930bSmikeb 	buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
3064ac13930bSmikeb 	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
3065ac13930bSmikeb 
3066ac13930bSmikeb 	 /* one word */
3067ac13930bSmikeb 	buffer.length = htobe16(sizeof(uint16_t));
3068ac13930bSmikeb 	buffer.data = data;
3069ac13930bSmikeb 	buffer.address = htobe32(offset * 2);
3070ac13930bSmikeb 
3071ac13930bSmikeb 	status = ixgbe_host_interface_command(hw, (uint32_t *)&buffer,
3072ac13930bSmikeb 					      sizeof(buffer),
3073ac13930bSmikeb 					      IXGBE_HI_COMMAND_TIMEOUT, FALSE);
3074ac13930bSmikeb 
3075ac13930bSmikeb 	return status;
3076ac13930bSmikeb }
3077ac13930bSmikeb 
3078ac13930bSmikeb /**
3079ac13930bSmikeb  *  ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
3080ac13930bSmikeb  *  @hw: pointer to hardware structure
3081ac13930bSmikeb  *  @offset: offset of  word in the EEPROM to write
3082ac13930bSmikeb  *  @data: word write to the EEPROM
3083ac13930bSmikeb  *
3084ac13930bSmikeb  *  Write a 16 bit word to the EEPROM using the hostif.
3085ac13930bSmikeb  **/
3086ac13930bSmikeb int32_t ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, uint16_t offset,
3087ac13930bSmikeb 				   uint16_t data)
3088ac13930bSmikeb {
3089ac13930bSmikeb 	int32_t status = IXGBE_SUCCESS;
3090ac13930bSmikeb 
3091ac13930bSmikeb 	DEBUGFUNC("ixgbe_write_ee_hostif_X550");
3092ac13930bSmikeb 
3093ac13930bSmikeb 	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
3094ac13930bSmikeb 	    IXGBE_SUCCESS) {
3095ac13930bSmikeb 		status = ixgbe_write_ee_hostif_data_X550(hw, offset, data);
3096ac13930bSmikeb 		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
3097ac13930bSmikeb 	} else {
3098d7a8f955Sjmatthew 		DEBUGOUT("write ee hostif failed to get semaphore");
3099ac13930bSmikeb 		status = IXGBE_ERR_SWFW_SYNC;
3100ac13930bSmikeb 	}
3101ac13930bSmikeb 
3102ac13930bSmikeb 	return status;
3103ac13930bSmikeb }
3104ac13930bSmikeb 
3105ac13930bSmikeb /**
3106ac13930bSmikeb  * ixgbe_checksum_ptr_x550 - Checksum one pointer region
3107ac13930bSmikeb  * @hw: pointer to hardware structure
3108ac13930bSmikeb  * @ptr: pointer offset in eeprom
3109ac13930bSmikeb  * @size: size of section pointed by ptr, if 0 first word will be used as size
3110ac13930bSmikeb  * @csum: address of checksum to update
3111d7a8f955Sjmatthew  * @buffer: pointer to buffer containing calculated checksum
3112d7a8f955Sjmatthew  * @buffer_size: size of buffer
3113ac13930bSmikeb  *
3114ac13930bSmikeb  * Returns error status for any failure
3115ac13930bSmikeb  */
3116ac13930bSmikeb int32_t ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, uint16_t ptr,
3117ac13930bSmikeb 				uint16_t size, uint16_t *csum, uint16_t *buffer,
3118ac13930bSmikeb 				uint32_t buffer_size)
3119ac13930bSmikeb {
3120ac13930bSmikeb 	uint16_t buf[256];
3121ac13930bSmikeb 	int32_t status;
3122ac13930bSmikeb 	uint16_t length, bufsz, i, start;
3123ac13930bSmikeb 	uint16_t *local_buffer;
3124ac13930bSmikeb 
3125ac13930bSmikeb 	bufsz = sizeof(buf) / sizeof(buf[0]);
3126ac13930bSmikeb 
3127ac13930bSmikeb 	/* Read a chunk at the pointer location */
3128ac13930bSmikeb 	if (!buffer) {
3129ac13930bSmikeb 		status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf);
3130ac13930bSmikeb 		if (status) {
3131ac13930bSmikeb 			DEBUGOUT("Failed to read EEPROM image\n");
3132ac13930bSmikeb 			return status;
3133ac13930bSmikeb 		}
3134ac13930bSmikeb 		local_buffer = buf;
3135ac13930bSmikeb 	} else {
3136ac13930bSmikeb 		if (buffer_size < ptr)
3137ac13930bSmikeb 			return  IXGBE_ERR_PARAM;
3138ac13930bSmikeb 		local_buffer = &buffer[ptr];
3139ac13930bSmikeb 	}
3140ac13930bSmikeb 
3141ac13930bSmikeb 	if (size) {
3142ac13930bSmikeb 		start = 0;
3143ac13930bSmikeb 		length = size;
3144ac13930bSmikeb 	} else {
3145ac13930bSmikeb 		start = 1;
3146ac13930bSmikeb 		length = local_buffer[0];
3147ac13930bSmikeb 
3148ac13930bSmikeb 		/* Skip pointer section if length is invalid. */
3149ac13930bSmikeb 		if (length == 0xFFFF || length == 0 ||
3150ac13930bSmikeb 		    (ptr + length) >= hw->eeprom.word_size)
3151ac13930bSmikeb 			return IXGBE_SUCCESS;
3152ac13930bSmikeb 	}
3153ac13930bSmikeb 
3154ac13930bSmikeb 	if (buffer && ((uint32_t)start + (uint32_t)length > buffer_size))
3155ac13930bSmikeb 		return IXGBE_ERR_PARAM;
3156ac13930bSmikeb 
3157ac13930bSmikeb 	for (i = start; length; i++, length--) {
3158ac13930bSmikeb 		if (i == bufsz && !buffer) {
3159ac13930bSmikeb 			ptr += bufsz;
3160ac13930bSmikeb 			i = 0;
3161ac13930bSmikeb 			if (length < bufsz)
3162ac13930bSmikeb 				bufsz = length;
3163ac13930bSmikeb 
3164ac13930bSmikeb 			/* Read a chunk at the pointer location */
3165ac13930bSmikeb 			status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr,
3166ac13930bSmikeb 								  bufsz, buf);
3167ac13930bSmikeb 			if (status) {
3168ac13930bSmikeb 				DEBUGOUT("Failed to read EEPROM image\n");
3169ac13930bSmikeb 				return status;
3170ac13930bSmikeb 			}
3171ac13930bSmikeb 		}
3172ac13930bSmikeb 		*csum += local_buffer[i];
3173ac13930bSmikeb 	}
3174ac13930bSmikeb 	return IXGBE_SUCCESS;
3175ac13930bSmikeb }
3176ac13930bSmikeb 
3177ac13930bSmikeb /**
3178ac13930bSmikeb  *  ixgbe_calc_checksum_X550 - Calculates and returns the checksum
3179ac13930bSmikeb  *  @hw: pointer to hardware structure
3180ac13930bSmikeb  *  @buffer: pointer to buffer containing calculated checksum
3181ac13930bSmikeb  *  @buffer_size: size of buffer
3182ac13930bSmikeb  *
3183ac13930bSmikeb  *  Returns a negative error code on error, or the 16-bit checksum
3184ac13930bSmikeb  **/
3185ac13930bSmikeb int32_t ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, uint16_t *buffer,
3186ac13930bSmikeb 				 uint32_t buffer_size)
3187ac13930bSmikeb {
3188ac13930bSmikeb 	uint16_t eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1];
3189ac13930bSmikeb 	uint16_t *local_buffer;
3190ac13930bSmikeb 	int32_t status;
3191ac13930bSmikeb 	uint16_t checksum = 0;
3192ac13930bSmikeb 	uint16_t pointer, i, size;
3193ac13930bSmikeb 
3194ac13930bSmikeb 	DEBUGFUNC("ixgbe_calc_eeprom_checksum_X550");
3195ac13930bSmikeb 
3196ac13930bSmikeb 	hw->eeprom.ops.init_params(hw);
3197ac13930bSmikeb 
3198ac13930bSmikeb 	if (!buffer) {
3199ac13930bSmikeb 		/* Read pointer area */
3200ac13930bSmikeb 		status = ixgbe_read_ee_hostif_buffer_X550(hw, 0,
3201ac13930bSmikeb 						     IXGBE_EEPROM_LAST_WORD + 1,
3202ac13930bSmikeb 						     eeprom_ptrs);
3203ac13930bSmikeb 		if (status) {
3204ac13930bSmikeb 			DEBUGOUT("Failed to read EEPROM image\n");
3205ac13930bSmikeb 			return status;
3206ac13930bSmikeb 		}
3207ac13930bSmikeb 		local_buffer = eeprom_ptrs;
3208ac13930bSmikeb 	} else {
3209ac13930bSmikeb 		if (buffer_size < IXGBE_EEPROM_LAST_WORD)
3210ac13930bSmikeb 			return IXGBE_ERR_PARAM;
3211ac13930bSmikeb 		local_buffer = buffer;
3212ac13930bSmikeb 	}
3213ac13930bSmikeb 
3214ac13930bSmikeb 	/*
3215ac13930bSmikeb 	 * For X550 hardware include 0x0-0x41 in the checksum, skip the
3216ac13930bSmikeb 	 * checksum word itself
3217ac13930bSmikeb 	 */
3218ac13930bSmikeb 	for (i = 0; i <= IXGBE_EEPROM_LAST_WORD; i++)
3219ac13930bSmikeb 		if (i != IXGBE_EEPROM_CHECKSUM)
3220ac13930bSmikeb 			checksum += local_buffer[i];
3221ac13930bSmikeb 
3222ac13930bSmikeb 	/*
3223ac13930bSmikeb 	 * Include all data from pointers 0x3, 0x6-0xE.  This excludes the
3224ac13930bSmikeb 	 * FW, PHY module, and PCIe Expansion/Option ROM pointers.
3225ac13930bSmikeb 	 */
3226ac13930bSmikeb 	for (i = IXGBE_PCIE_ANALOG_PTR_X550; i < IXGBE_FW_PTR; i++) {
3227ac13930bSmikeb 		if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
3228ac13930bSmikeb 			continue;
3229ac13930bSmikeb 
3230ac13930bSmikeb 		pointer = local_buffer[i];
3231ac13930bSmikeb 
3232ac13930bSmikeb 		/* Skip pointer section if the pointer is invalid. */
3233ac13930bSmikeb 		if (pointer == 0xFFFF || pointer == 0 ||
3234ac13930bSmikeb 		    pointer >= hw->eeprom.word_size)
3235ac13930bSmikeb 			continue;
3236ac13930bSmikeb 
3237ac13930bSmikeb 		switch (i) {
3238ac13930bSmikeb 		case IXGBE_PCIE_GENERAL_PTR:
3239ac13930bSmikeb 			size = IXGBE_IXGBE_PCIE_GENERAL_SIZE;
3240ac13930bSmikeb 			break;
3241ac13930bSmikeb 		case IXGBE_PCIE_CONFIG0_PTR:
3242ac13930bSmikeb 		case IXGBE_PCIE_CONFIG1_PTR:
3243ac13930bSmikeb 			size = IXGBE_PCIE_CONFIG_SIZE;
3244ac13930bSmikeb 			break;
3245ac13930bSmikeb 		default:
3246ac13930bSmikeb 			size = 0;
3247ac13930bSmikeb 			break;
3248ac13930bSmikeb 		}
3249ac13930bSmikeb 
3250ac13930bSmikeb 		status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum,
3251ac13930bSmikeb 						buffer, buffer_size);
3252ac13930bSmikeb 		if (status)
3253ac13930bSmikeb 			return status;
3254ac13930bSmikeb 	}
3255ac13930bSmikeb 
3256ac13930bSmikeb 	checksum = (uint16_t)IXGBE_EEPROM_SUM - checksum;
3257ac13930bSmikeb 
3258ac13930bSmikeb 	return (int32_t)checksum;
3259ac13930bSmikeb }
3260ac13930bSmikeb 
3261ac13930bSmikeb /**
3262ac13930bSmikeb  *  ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum
3263ac13930bSmikeb  *  @hw: pointer to hardware structure
3264ac13930bSmikeb  *
3265ac13930bSmikeb  *  Returns a negative error code on error, or the 16-bit checksum
3266ac13930bSmikeb  **/
3267ac13930bSmikeb int32_t ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
3268ac13930bSmikeb {
3269ac13930bSmikeb 	return ixgbe_calc_checksum_X550(hw, NULL, 0);
3270ac13930bSmikeb }
3271ac13930bSmikeb 
3272ac13930bSmikeb /**
3273ac13930bSmikeb  *  ixgbe_validate_eeprom_checksum_X550 - Validate EEPROM checksum
3274ac13930bSmikeb  *  @hw: pointer to hardware structure
3275ac13930bSmikeb  *  @checksum_val: calculated checksum
3276ac13930bSmikeb  *
3277ac13930bSmikeb  *  Performs checksum calculation and validates the EEPROM checksum.  If the
3278ac13930bSmikeb  *  caller does not need checksum_val, the value can be NULL.
3279ac13930bSmikeb  **/
3280ac13930bSmikeb int32_t ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, uint16_t *checksum_val)
3281ac13930bSmikeb {
3282ac13930bSmikeb 	int32_t status;
3283ac13930bSmikeb 	uint16_t checksum;
3284ac13930bSmikeb 	uint16_t read_checksum = 0;
3285ac13930bSmikeb 
3286ac13930bSmikeb 	DEBUGFUNC("ixgbe_validate_eeprom_checksum_X550");
3287ac13930bSmikeb 
3288ac13930bSmikeb 	/* Read the first word from the EEPROM. If this times out or fails, do
3289ac13930bSmikeb 	 * not continue or we could be in for a very long wait while every
3290ac13930bSmikeb 	 * EEPROM read fails
3291ac13930bSmikeb 	 */
3292ac13930bSmikeb 	status = hw->eeprom.ops.read(hw, 0, &checksum);
3293ac13930bSmikeb 	if (status) {
3294ac13930bSmikeb 		DEBUGOUT("EEPROM read failed\n");
3295ac13930bSmikeb 		return status;
3296ac13930bSmikeb 	}
3297ac13930bSmikeb 
3298ac13930bSmikeb 	status = hw->eeprom.ops.calc_checksum(hw);
3299ac13930bSmikeb 	if (status < 0)
3300ac13930bSmikeb 		return status;
3301ac13930bSmikeb 
3302ac13930bSmikeb 	checksum = (uint16_t)(status & 0xffff);
3303ac13930bSmikeb 
3304ac13930bSmikeb 	status = ixgbe_read_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
3305ac13930bSmikeb 					   &read_checksum);
3306ac13930bSmikeb 	if (status)
3307ac13930bSmikeb 		return status;
3308ac13930bSmikeb 
3309ac13930bSmikeb 	/* Verify read checksum from EEPROM is the same as
3310ac13930bSmikeb 	 * calculated checksum
3311ac13930bSmikeb 	 */
3312ac13930bSmikeb 	if (read_checksum != checksum) {
3313ac13930bSmikeb 		status = IXGBE_ERR_EEPROM_CHECKSUM;
3314d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
3315d7a8f955Sjmatthew 			     "Invalid EEPROM checksum");
3316ac13930bSmikeb 	}
3317ac13930bSmikeb 
3318ac13930bSmikeb 	/* If the user cares, return the calculated checksum */
3319ac13930bSmikeb 	if (checksum_val)
3320ac13930bSmikeb 		*checksum_val = checksum;
3321ac13930bSmikeb 
3322ac13930bSmikeb 	return status;
3323ac13930bSmikeb }
3324ac13930bSmikeb 
3325ac13930bSmikeb /**
3326ac13930bSmikeb  * ixgbe_update_eeprom_checksum_X550 - Updates the EEPROM checksum and flash
3327ac13930bSmikeb  * @hw: pointer to hardware structure
3328ac13930bSmikeb  *
3329ac13930bSmikeb  * After writing EEPROM to shadow RAM using EEWR register, software calculates
3330ac13930bSmikeb  * checksum and updates the EEPROM and instructs the hardware to update
3331ac13930bSmikeb  * the flash.
3332ac13930bSmikeb  **/
3333ac13930bSmikeb int32_t ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
3334ac13930bSmikeb {
3335ac13930bSmikeb 	int32_t status;
3336ac13930bSmikeb 	uint16_t checksum = 0;
3337ac13930bSmikeb 
3338ac13930bSmikeb 	DEBUGFUNC("ixgbe_update_eeprom_checksum_X550");
3339ac13930bSmikeb 
3340ac13930bSmikeb 	/* Read the first word from the EEPROM. If this times out or fails, do
3341ac13930bSmikeb 	 * not continue or we could be in for a very long wait while every
3342ac13930bSmikeb 	 * EEPROM read fails
3343ac13930bSmikeb 	 */
3344ac13930bSmikeb 	status = ixgbe_read_ee_hostif_X550(hw, 0, &checksum);
3345ac13930bSmikeb 	if (status) {
3346ac13930bSmikeb 		DEBUGOUT("EEPROM read failed\n");
3347ac13930bSmikeb 		return status;
3348ac13930bSmikeb 	}
3349ac13930bSmikeb 
3350ac13930bSmikeb 	status = ixgbe_calc_eeprom_checksum_X550(hw);
3351ac13930bSmikeb 	if (status < 0)
3352ac13930bSmikeb 		return status;
3353ac13930bSmikeb 
3354ac13930bSmikeb 	checksum = (uint16_t)(status & 0xffff);
3355ac13930bSmikeb 
3356ac13930bSmikeb 	status = ixgbe_write_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
3357ac13930bSmikeb 					    checksum);
3358ac13930bSmikeb 	if (status)
3359ac13930bSmikeb 		return status;
3360ac13930bSmikeb 
3361ac13930bSmikeb 	status = ixgbe_update_flash_X550(hw);
3362ac13930bSmikeb 
3363ac13930bSmikeb 	return status;
3364ac13930bSmikeb }
3365ac13930bSmikeb 
3366ac13930bSmikeb /**
3367ac13930bSmikeb  *  ixgbe_update_flash_X550 - Instruct HW to copy EEPROM to Flash device
3368ac13930bSmikeb  *  @hw: pointer to hardware structure
3369ac13930bSmikeb  *
3370ac13930bSmikeb  *  Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash.
3371ac13930bSmikeb  **/
3372ac13930bSmikeb int32_t ixgbe_update_flash_X550(struct ixgbe_hw *hw)
3373ac13930bSmikeb {
3374ac13930bSmikeb 	int32_t status = IXGBE_SUCCESS;
3375ac13930bSmikeb 	union ixgbe_hic_hdr2 buffer;
3376ac13930bSmikeb 
3377ac13930bSmikeb 	DEBUGFUNC("ixgbe_update_flash_X550");
3378ac13930bSmikeb 
3379ac13930bSmikeb 	buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD;
3380ac13930bSmikeb 	buffer.req.buf_lenh = 0;
3381ac13930bSmikeb 	buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
3382ac13930bSmikeb 	buffer.req.checksum = FW_DEFAULT_CHECKSUM;
3383ac13930bSmikeb 
3384ac13930bSmikeb 	status = ixgbe_host_interface_command(hw, (uint32_t *)&buffer,
3385ac13930bSmikeb 					      sizeof(buffer),
3386ac13930bSmikeb 					      IXGBE_HI_COMMAND_TIMEOUT, FALSE);
3387ac13930bSmikeb 
3388ac13930bSmikeb 	return status;
3389ac13930bSmikeb }
3390ac13930bSmikeb 
3391ac13930bSmikeb /**
3392ac13930bSmikeb  *  ixgbe_get_supported_physical_layer_X550em - Returns physical layer type
3393ac13930bSmikeb  *  @hw: pointer to hardware structure
3394ac13930bSmikeb  *
3395ac13930bSmikeb  *  Determines physical layer capabilities of the current configuration.
3396ac13930bSmikeb  **/
3397d7a8f955Sjmatthew uint64_t ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw)
3398ac13930bSmikeb {
3399d7a8f955Sjmatthew 	uint64_t physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
3400ac13930bSmikeb 	uint16_t ext_ability = 0;
3401ac13930bSmikeb 
3402ac13930bSmikeb 	DEBUGFUNC("ixgbe_get_supported_physical_layer_X550em");
3403ac13930bSmikeb 
3404ac13930bSmikeb 	hw->phy.ops.identify(hw);
3405ac13930bSmikeb 
3406ac13930bSmikeb 	switch (hw->phy.type) {
3407ac13930bSmikeb 	case ixgbe_phy_x550em_kr:
3408d7a8f955Sjmatthew 		if (hw->mac.type == ixgbe_mac_X550EM_a) {
3409d7a8f955Sjmatthew 			if (hw->phy.nw_mng_if_sel &
3410d7a8f955Sjmatthew 			    IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G) {
3411d7a8f955Sjmatthew 				physical_layer =
3412d7a8f955Sjmatthew 					IXGBE_PHYSICAL_LAYER_2500BASE_KX;
3413d7a8f955Sjmatthew 				break;
3414d7a8f955Sjmatthew 			} else if (hw->device_id ==
3415d7a8f955Sjmatthew 				   IXGBE_DEV_ID_X550EM_A_KR_L) {
3416d7a8f955Sjmatthew 				physical_layer =
3417d7a8f955Sjmatthew 					IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3418d7a8f955Sjmatthew 				break;
3419d7a8f955Sjmatthew 			}
3420d7a8f955Sjmatthew 		}
3421d7a8f955Sjmatthew 		/* fall through */
3422d7a8f955Sjmatthew 	case ixgbe_phy_x550em_xfi:
3423ac13930bSmikeb 		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR |
3424ac13930bSmikeb 				 IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3425ac13930bSmikeb 		break;
3426ac13930bSmikeb 	case ixgbe_phy_x550em_kx4:
3427ac13930bSmikeb 		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
3428ac13930bSmikeb 				 IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3429ac13930bSmikeb 		break;
3430ac13930bSmikeb 	case ixgbe_phy_x550em_ext_t:
3431ac13930bSmikeb 		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY,
3432ac13930bSmikeb 				     IXGBE_MDIO_PMA_PMD_DEV_TYPE,
3433ac13930bSmikeb 				     &ext_ability);
3434ac13930bSmikeb 		if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY)
3435ac13930bSmikeb 			physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T;
3436ac13930bSmikeb 		if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY)
3437ac13930bSmikeb 			physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
3438ac13930bSmikeb 		break;
3439d7a8f955Sjmatthew 	case ixgbe_phy_fw:
3440d7a8f955Sjmatthew 		if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_1GB_FULL)
3441d7a8f955Sjmatthew 			physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
3442d7a8f955Sjmatthew 		if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_100_FULL)
3443d7a8f955Sjmatthew 			physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX;
3444d7a8f955Sjmatthew 		if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_10_FULL)
3445d7a8f955Sjmatthew 			physical_layer |= IXGBE_PHYSICAL_LAYER_10BASE_T;
3446d7a8f955Sjmatthew 		break;
3447d7a8f955Sjmatthew 	case ixgbe_phy_sgmii:
3448d7a8f955Sjmatthew 		physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3449d7a8f955Sjmatthew 		break;
3450d7a8f955Sjmatthew 	case ixgbe_phy_ext_1g_t:
3451d7a8f955Sjmatthew 		physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
3452d7a8f955Sjmatthew 		break;
3453ac13930bSmikeb 	default:
3454ac13930bSmikeb 		break;
3455ac13930bSmikeb 	}
3456ac13930bSmikeb 
3457ac13930bSmikeb 	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber)
3458ac13930bSmikeb 		physical_layer = ixgbe_get_supported_phy_sfp_layer_generic(hw);
3459ac13930bSmikeb 
3460ac13930bSmikeb 	return physical_layer;
3461ac13930bSmikeb }
3462ac13930bSmikeb 
3463ac13930bSmikeb /**
3464ac13930bSmikeb  * ixgbe_get_bus_info_x550em - Set PCI bus info
3465ac13930bSmikeb  * @hw: pointer to hardware structure
3466ac13930bSmikeb  *
3467ac13930bSmikeb  * Sets bus link width and speed to unknown because X550em is
3468ac13930bSmikeb  * not a PCI device.
3469ac13930bSmikeb  **/
3470ac13930bSmikeb int32_t ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw)
3471ac13930bSmikeb {
3472ac13930bSmikeb 
3473ac13930bSmikeb 	DEBUGFUNC("ixgbe_get_bus_info_x550em");
3474ac13930bSmikeb 
3475ac13930bSmikeb 	hw->bus.width = ixgbe_bus_width_unknown;
3476ac13930bSmikeb 	hw->bus.speed = ixgbe_bus_speed_unknown;
3477ac13930bSmikeb 
3478ac13930bSmikeb 	hw->mac.ops.set_lan_id(hw);
3479ac13930bSmikeb 
3480ac13930bSmikeb 	return IXGBE_SUCCESS;
3481ac13930bSmikeb }
3482ac13930bSmikeb 
3483ac13930bSmikeb /**
3484ac13930bSmikeb  * ixgbe_disable_rx_x550 - Disable RX unit
3485d7a8f955Sjmatthew  * @hw: pointer to hardware structure
3486ac13930bSmikeb  *
3487ac13930bSmikeb  * Enables the Rx DMA unit for x550
3488ac13930bSmikeb  **/
3489ac13930bSmikeb void ixgbe_disable_rx_x550(struct ixgbe_hw *hw)
3490ac13930bSmikeb {
3491d7a8f955Sjmatthew 	uint32_t rxctrl, pfdtxgswc;
3492ac13930bSmikeb 	int32_t status;
3493ac13930bSmikeb 	struct ixgbe_hic_disable_rxen fw_cmd;
3494ac13930bSmikeb 
3495d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_enable_rx_dma_x550");
3496ac13930bSmikeb 
3497ac13930bSmikeb 	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
3498ac13930bSmikeb 	if (rxctrl & IXGBE_RXCTRL_RXEN) {
3499d7a8f955Sjmatthew 		pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
3500d7a8f955Sjmatthew 		if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
3501d7a8f955Sjmatthew 			pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
3502d7a8f955Sjmatthew 			IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
3503d7a8f955Sjmatthew 			hw->mac.set_lben = TRUE;
3504d7a8f955Sjmatthew 		} else {
3505d7a8f955Sjmatthew 			hw->mac.set_lben = FALSE;
3506d7a8f955Sjmatthew 		}
3507d7a8f955Sjmatthew 
3508ac13930bSmikeb 		fw_cmd.hdr.cmd = FW_DISABLE_RXEN_CMD;
3509ac13930bSmikeb 		fw_cmd.hdr.buf_len = FW_DISABLE_RXEN_LEN;
3510ac13930bSmikeb 		fw_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
3511ac13930bSmikeb 		fw_cmd.port_number = (uint8_t)hw->bus.lan_id;
3512ac13930bSmikeb 
3513ac13930bSmikeb 		status = ixgbe_host_interface_command(hw, (uint32_t *)&fw_cmd,
3514ac13930bSmikeb 					sizeof(struct ixgbe_hic_disable_rxen),
3515ac13930bSmikeb 					IXGBE_HI_COMMAND_TIMEOUT, TRUE);
3516ac13930bSmikeb 
3517ac13930bSmikeb 		/* If we fail - disable RX using register write */
3518ac13930bSmikeb 		if (status) {
3519ac13930bSmikeb 			rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
3520ac13930bSmikeb 			if (rxctrl & IXGBE_RXCTRL_RXEN) {
3521ac13930bSmikeb 				rxctrl &= ~IXGBE_RXCTRL_RXEN;
3522ac13930bSmikeb 				IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
3523ac13930bSmikeb 			}
3524ac13930bSmikeb 		}
3525ac13930bSmikeb 	}
3526ac13930bSmikeb }
3527ac13930bSmikeb 
3528ac13930bSmikeb /**
3529d7a8f955Sjmatthew  * ixgbe_enter_lplu_x550em - Transition to low power states
3530d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
3531d7a8f955Sjmatthew  *
3532d7a8f955Sjmatthew  * Configures Low Power Link Up on transition to low power states
3533d7a8f955Sjmatthew  * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
3534d7a8f955Sjmatthew  * X557 PHY immediately prior to entering LPLU.
3535d7a8f955Sjmatthew  **/
3536d7a8f955Sjmatthew int32_t ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw)
3537d7a8f955Sjmatthew {
3538d7a8f955Sjmatthew 	uint16_t an_10g_cntl_reg, autoneg_reg, speed;
3539d7a8f955Sjmatthew 	int32_t status;
3540d7a8f955Sjmatthew 	ixgbe_link_speed lcd_speed;
3541d7a8f955Sjmatthew 	uint32_t save_autoneg;
3542d7a8f955Sjmatthew 	bool link_up;
3543d7a8f955Sjmatthew 
3544d7a8f955Sjmatthew 	/* SW LPLU not required on later HW revisions. */
3545d7a8f955Sjmatthew 	if ((hw->mac.type == ixgbe_mac_X550EM_x) &&
3546d7a8f955Sjmatthew 	    (IXGBE_FUSES0_REV_MASK &
3547d7a8f955Sjmatthew 	     IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))))
3548d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
3549d7a8f955Sjmatthew 
3550d7a8f955Sjmatthew 	/* If blocked by MNG FW, then don't restart AN */
3551d7a8f955Sjmatthew 	if (ixgbe_check_reset_blocked(hw))
3552d7a8f955Sjmatthew 		return IXGBE_SUCCESS;
3553d7a8f955Sjmatthew 
3554d7a8f955Sjmatthew 	status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
3555d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3556d7a8f955Sjmatthew 		return status;
3557d7a8f955Sjmatthew 
3558d7a8f955Sjmatthew 	status = hw->eeprom.ops.read(hw, NVM_INIT_CTRL_3, &hw->eeprom.ctrl_word_3);
3559d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3560d7a8f955Sjmatthew 		return status;
3561d7a8f955Sjmatthew 
3562d7a8f955Sjmatthew 	/* If link is down, LPLU disabled in NVM, WoL disabled, or manageability
3563d7a8f955Sjmatthew 	 * disabled, then force link down by entering low power mode.
3564d7a8f955Sjmatthew 	 */
3565d7a8f955Sjmatthew 	if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) ||
3566d7a8f955Sjmatthew 	    !(hw->wol_enabled || ixgbe_mng_present(hw)))
3567d7a8f955Sjmatthew 		return ixgbe_set_copper_phy_power(hw, FALSE);
3568d7a8f955Sjmatthew 
3569d7a8f955Sjmatthew 	/* Determine LCD */
3570d7a8f955Sjmatthew 	status = ixgbe_get_lcd_t_x550em(hw, &lcd_speed);
3571d7a8f955Sjmatthew 
3572d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3573d7a8f955Sjmatthew 		return status;
3574d7a8f955Sjmatthew 
3575d7a8f955Sjmatthew 	/* If no valid LCD link speed, then force link down and exit. */
3576d7a8f955Sjmatthew 	if (lcd_speed == IXGBE_LINK_SPEED_UNKNOWN)
3577d7a8f955Sjmatthew 		return ixgbe_set_copper_phy_power(hw, FALSE);
3578d7a8f955Sjmatthew 
3579d7a8f955Sjmatthew 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
3580d7a8f955Sjmatthew 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3581d7a8f955Sjmatthew 				      &speed);
3582d7a8f955Sjmatthew 
3583d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3584d7a8f955Sjmatthew 		return status;
3585d7a8f955Sjmatthew 
3586d7a8f955Sjmatthew 	/* If no link now, speed is invalid so take link down */
3587d7a8f955Sjmatthew 	status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
3588d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3589d7a8f955Sjmatthew 		return ixgbe_set_copper_phy_power(hw, FALSE);
3590d7a8f955Sjmatthew 
3591d7a8f955Sjmatthew 	/* clear everything but the speed bits */
3592d7a8f955Sjmatthew 	speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK;
3593d7a8f955Sjmatthew 
3594d7a8f955Sjmatthew 	/* If current speed is already LCD, then exit. */
3595d7a8f955Sjmatthew 	if (((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB) &&
3596d7a8f955Sjmatthew 	     (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) ||
3597d7a8f955Sjmatthew 	    ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) &&
3598d7a8f955Sjmatthew 	     (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL)))
3599d7a8f955Sjmatthew 		return status;
3600d7a8f955Sjmatthew 
3601d7a8f955Sjmatthew 	/* Clear AN completed indication */
3602d7a8f955Sjmatthew 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM,
3603d7a8f955Sjmatthew 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3604d7a8f955Sjmatthew 				      &autoneg_reg);
3605d7a8f955Sjmatthew 
3606d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3607d7a8f955Sjmatthew 		return status;
3608d7a8f955Sjmatthew 
3609d7a8f955Sjmatthew 	status = hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
3610d7a8f955Sjmatthew 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3611d7a8f955Sjmatthew 			     &an_10g_cntl_reg);
3612d7a8f955Sjmatthew 
3613d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3614d7a8f955Sjmatthew 		return status;
3615d7a8f955Sjmatthew 
3616d7a8f955Sjmatthew 	status = hw->phy.ops.read_reg(hw,
3617d7a8f955Sjmatthew 			     IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
3618d7a8f955Sjmatthew 			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3619d7a8f955Sjmatthew 			     &autoneg_reg);
3620d7a8f955Sjmatthew 
3621d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS)
3622d7a8f955Sjmatthew 		return status;
3623d7a8f955Sjmatthew 
3624d7a8f955Sjmatthew 	save_autoneg = hw->phy.autoneg_advertised;
3625d7a8f955Sjmatthew 
3626d7a8f955Sjmatthew 	/* Setup link at least common link speed */
3627d7a8f955Sjmatthew 	status = hw->mac.ops.setup_link(hw, lcd_speed, FALSE);
3628d7a8f955Sjmatthew 
3629d7a8f955Sjmatthew 	/* restore autoneg from before setting lplu speed */
3630d7a8f955Sjmatthew 	hw->phy.autoneg_advertised = save_autoneg;
3631d7a8f955Sjmatthew 
3632d7a8f955Sjmatthew 	return status;
3633d7a8f955Sjmatthew }
3634d7a8f955Sjmatthew 
3635d7a8f955Sjmatthew /**
3636ac13930bSmikeb  * ixgbe_get_lcd_x550em - Determine lowest common denominator
3637ac13930bSmikeb  *  @hw: pointer to hardware structure
3638ac13930bSmikeb  *  @lcd_speed: pointer to lowest common link speed
3639ac13930bSmikeb  *
3640ac13930bSmikeb  * Determine lowest common link speed with link partner.
3641ac13930bSmikeb  **/
3642ac13930bSmikeb int32_t ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed)
3643ac13930bSmikeb {
3644ac13930bSmikeb 	uint16_t an_lp_status;
3645ac13930bSmikeb 	int32_t status;
3646ac13930bSmikeb 	uint16_t word = hw->eeprom.ctrl_word_3;
3647ac13930bSmikeb 
3648ac13930bSmikeb 	*lcd_speed = IXGBE_LINK_SPEED_UNKNOWN;
3649ac13930bSmikeb 
3650ac13930bSmikeb 	status = hw->phy.ops.read_reg(hw, IXGBE_AUTO_NEG_LP_STATUS,
3651ac13930bSmikeb 				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3652ac13930bSmikeb 				      &an_lp_status);
3653ac13930bSmikeb 
3654ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
3655ac13930bSmikeb 		return status;
3656ac13930bSmikeb 
3657ac13930bSmikeb 	/* If link partner advertised 1G, return 1G */
3658ac13930bSmikeb 	if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) {
3659ac13930bSmikeb 		*lcd_speed = IXGBE_LINK_SPEED_1GB_FULL;
3660ac13930bSmikeb 		return status;
3661ac13930bSmikeb 	}
3662ac13930bSmikeb 
3663ac13930bSmikeb 	/* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */
3664ac13930bSmikeb 	if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) ||
3665ac13930bSmikeb 	    (word & NVM_INIT_CTRL_3_D10GMP_PORT0))
3666ac13930bSmikeb 		return status;
3667ac13930bSmikeb 
3668ac13930bSmikeb 	/* Link partner not capable of lower speeds, return 10G */
3669ac13930bSmikeb 	*lcd_speed = IXGBE_LINK_SPEED_10GB_FULL;
3670ac13930bSmikeb 	return status;
3671ac13930bSmikeb }
3672ac13930bSmikeb 
3673ac13930bSmikeb /**
3674ac13930bSmikeb  *  ixgbe_setup_fc_X550em - Set up flow control
3675ac13930bSmikeb  *  @hw: pointer to hardware structure
3676ac13930bSmikeb  *
3677ac13930bSmikeb  *  Called at init time to set up flow control.
3678ac13930bSmikeb  **/
3679ac13930bSmikeb int32_t ixgbe_setup_fc_X550em(struct ixgbe_hw *hw)
3680ac13930bSmikeb {
3681ac13930bSmikeb 	int32_t ret_val = IXGBE_SUCCESS;
3682ac13930bSmikeb 	uint32_t pause, asm_dir, reg_val;
3683ac13930bSmikeb 
3684ac13930bSmikeb 	DEBUGFUNC("ixgbe_setup_fc_X550em");
3685ac13930bSmikeb 
3686ac13930bSmikeb 	/* Validate the requested mode */
3687ac13930bSmikeb 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
3688d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
3689d7a8f955Sjmatthew 			"ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
3690ac13930bSmikeb 		ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
3691ac13930bSmikeb 		goto out;
3692ac13930bSmikeb 	}
3693ac13930bSmikeb 
3694ac13930bSmikeb 	/* 10gig parts do not have a word in the EEPROM to determine the
3695ac13930bSmikeb 	 * default flow control setting, so we explicitly set it to full.
3696ac13930bSmikeb 	 */
3697ac13930bSmikeb 	if (hw->fc.requested_mode == ixgbe_fc_default)
3698ac13930bSmikeb 		hw->fc.requested_mode = ixgbe_fc_full;
3699ac13930bSmikeb 
3700ac13930bSmikeb 	/* Determine PAUSE and ASM_DIR bits. */
3701ac13930bSmikeb 	switch (hw->fc.requested_mode) {
3702ac13930bSmikeb 	case ixgbe_fc_none:
3703ac13930bSmikeb 		pause = 0;
3704ac13930bSmikeb 		asm_dir = 0;
3705ac13930bSmikeb 		break;
3706ac13930bSmikeb 	case ixgbe_fc_tx_pause:
3707ac13930bSmikeb 		pause = 0;
3708ac13930bSmikeb 		asm_dir = 1;
3709ac13930bSmikeb 		break;
3710ac13930bSmikeb 	case ixgbe_fc_rx_pause:
3711ac13930bSmikeb 		/* Rx Flow control is enabled and Tx Flow control is
3712ac13930bSmikeb 		 * disabled by software override. Since there really
3713ac13930bSmikeb 		 * isn't a way to advertise that we are capable of RX
3714ac13930bSmikeb 		 * Pause ONLY, we will advertise that we support both
3715ac13930bSmikeb 		 * symmetric and asymmetric Rx PAUSE, as such we fall
3716ac13930bSmikeb 		 * through to the fc_full statement.  Later, we will
3717ac13930bSmikeb 		 * disable the adapter's ability to send PAUSE frames.
3718ac13930bSmikeb 		 */
3719ac13930bSmikeb 	case ixgbe_fc_full:
3720ac13930bSmikeb 		pause = 1;
3721ac13930bSmikeb 		asm_dir = 1;
3722ac13930bSmikeb 		break;
3723ac13930bSmikeb 	default:
3724d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_ARGUMENT,
3725d7a8f955Sjmatthew 			"Flow control param set incorrectly\n");
3726ac13930bSmikeb 		ret_val = IXGBE_ERR_CONFIG;
3727ac13930bSmikeb 		goto out;
3728ac13930bSmikeb 	}
3729ac13930bSmikeb 
3730d7a8f955Sjmatthew 	switch (hw->device_id) {
3731d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_KR:
3732d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_KR:
3733d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_A_KR_L:
3734d7a8f955Sjmatthew 		ret_val = hw->mac.ops.read_iosf_sb_reg(hw,
3735ac13930bSmikeb 					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3736ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
3737ac13930bSmikeb 		if (ret_val != IXGBE_SUCCESS)
3738ac13930bSmikeb 			goto out;
3739ac13930bSmikeb 		reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
3740ac13930bSmikeb 			IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
3741ac13930bSmikeb 		if (pause)
3742ac13930bSmikeb 			reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
3743ac13930bSmikeb 		if (asm_dir)
3744ac13930bSmikeb 			reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
3745d7a8f955Sjmatthew 		ret_val = hw->mac.ops.write_iosf_sb_reg(hw,
3746ac13930bSmikeb 					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3747ac13930bSmikeb 					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
3748ac13930bSmikeb 
3749ac13930bSmikeb 		/* This device does not fully support AN. */
3750ac13930bSmikeb 		hw->fc.disable_fc_autoneg = TRUE;
3751d7a8f955Sjmatthew 		break;
3752d7a8f955Sjmatthew 	case IXGBE_DEV_ID_X550EM_X_XFI:
3753d7a8f955Sjmatthew 		hw->fc.disable_fc_autoneg = TRUE;
3754d7a8f955Sjmatthew 		break;
3755d7a8f955Sjmatthew 	default:
3756d7a8f955Sjmatthew 		break;
3757ac13930bSmikeb 	}
3758ac13930bSmikeb 
3759ac13930bSmikeb out:
3760ac13930bSmikeb 	return ret_val;
3761ac13930bSmikeb }
3762ac13930bSmikeb 
3763ac13930bSmikeb /**
3764d7a8f955Sjmatthew  *  ixgbe_fc_autoneg_backplane_x550em_a - Enable flow control IEEE clause 37
3765d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
3766d7a8f955Sjmatthew  *
3767d7a8f955Sjmatthew  *  Enable flow control according to IEEE clause 37.
3768d7a8f955Sjmatthew  **/
3769d7a8f955Sjmatthew void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw)
3770d7a8f955Sjmatthew {
3771d7a8f955Sjmatthew 	uint32_t link_s1, lp_an_page_low, an_cntl_1;
3772d7a8f955Sjmatthew 	int32_t status = IXGBE_ERR_FC_NOT_NEGOTIATED;
3773d7a8f955Sjmatthew 	ixgbe_link_speed speed;
3774d7a8f955Sjmatthew 	bool link_up;
3775d7a8f955Sjmatthew 
3776d7a8f955Sjmatthew 	/* AN should have completed when the cable was plugged in.
3777d7a8f955Sjmatthew 	 * Look for reasons to bail out.  Bail out if:
3778d7a8f955Sjmatthew 	 * - FC autoneg is disabled, or if
3779d7a8f955Sjmatthew 	 * - link is not up.
3780d7a8f955Sjmatthew 	 */
3781d7a8f955Sjmatthew 	if (hw->fc.disable_fc_autoneg) {
3782d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
3783d7a8f955Sjmatthew 			     "Flow control autoneg is disabled");
3784d7a8f955Sjmatthew 		goto out;
3785d7a8f955Sjmatthew 	}
3786d7a8f955Sjmatthew 
3787d7a8f955Sjmatthew 	hw->mac.ops.check_link(hw, &speed, &link_up, FALSE);
3788d7a8f955Sjmatthew 	if (!link_up) {
3789d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down");
3790d7a8f955Sjmatthew 		goto out;
3791d7a8f955Sjmatthew 	}
3792d7a8f955Sjmatthew 
3793d7a8f955Sjmatthew 	/* Check at auto-negotiation has completed */
3794d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
3795d7a8f955Sjmatthew 					IXGBE_KRM_LINK_S1(hw->bus.lan_id),
3796d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, &link_s1);
3797d7a8f955Sjmatthew 
3798d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS ||
3799d7a8f955Sjmatthew 	    (link_s1 & IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE) == 0) {
3800d7a8f955Sjmatthew 		DEBUGOUT("Auto-Negotiation did not complete\n");
3801d7a8f955Sjmatthew 		status = IXGBE_ERR_FC_NOT_NEGOTIATED;
3802d7a8f955Sjmatthew 		goto out;
3803d7a8f955Sjmatthew 	}
3804d7a8f955Sjmatthew 
3805d7a8f955Sjmatthew 	/* Read the 10g AN autoc and LP ability registers and resolve
3806d7a8f955Sjmatthew 	 * local flow control settings accordingly
3807d7a8f955Sjmatthew 	 */
3808d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
3809d7a8f955Sjmatthew 				IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3810d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl_1);
3811d7a8f955Sjmatthew 
3812d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS) {
3813d7a8f955Sjmatthew 		DEBUGOUT("Auto-Negotiation did not complete\n");
3814d7a8f955Sjmatthew 		goto out;
3815d7a8f955Sjmatthew 	}
3816d7a8f955Sjmatthew 
3817d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
3818d7a8f955Sjmatthew 				IXGBE_KRM_LP_BASE_PAGE_HIGH(hw->bus.lan_id),
3819d7a8f955Sjmatthew 				IXGBE_SB_IOSF_TARGET_KR_PHY, &lp_an_page_low);
3820d7a8f955Sjmatthew 
3821d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS) {
3822d7a8f955Sjmatthew 		DEBUGOUT("Auto-Negotiation did not complete\n");
3823d7a8f955Sjmatthew 		goto out;
3824d7a8f955Sjmatthew 	}
3825d7a8f955Sjmatthew 
3826d7a8f955Sjmatthew 	status = ixgbe_negotiate_fc(hw, an_cntl_1, lp_an_page_low,
3827d7a8f955Sjmatthew 				    IXGBE_KRM_AN_CNTL_1_SYM_PAUSE,
3828d7a8f955Sjmatthew 				    IXGBE_KRM_AN_CNTL_1_ASM_PAUSE,
3829d7a8f955Sjmatthew 				    IXGBE_KRM_LP_BASE_PAGE_HIGH_SYM_PAUSE,
3830d7a8f955Sjmatthew 				    IXGBE_KRM_LP_BASE_PAGE_HIGH_ASM_PAUSE);
3831d7a8f955Sjmatthew 
3832d7a8f955Sjmatthew out:
3833d7a8f955Sjmatthew 	if (status == IXGBE_SUCCESS) {
3834d7a8f955Sjmatthew 		hw->fc.fc_was_autonegged = TRUE;
3835d7a8f955Sjmatthew 	} else {
3836d7a8f955Sjmatthew 		hw->fc.fc_was_autonegged = FALSE;
3837d7a8f955Sjmatthew 		hw->fc.current_mode = hw->fc.requested_mode;
3838d7a8f955Sjmatthew 	}
3839d7a8f955Sjmatthew }
3840d7a8f955Sjmatthew 
3841d7a8f955Sjmatthew /**
3842d7a8f955Sjmatthew  *  ixgbe_fc_autoneg_fiber_x550em_a - passthrough FC settings
3843d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
3844d7a8f955Sjmatthew  *
3845d7a8f955Sjmatthew  **/
3846d7a8f955Sjmatthew void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw)
3847d7a8f955Sjmatthew {
3848d7a8f955Sjmatthew 	hw->fc.fc_was_autonegged = FALSE;
3849d7a8f955Sjmatthew 	hw->fc.current_mode = hw->fc.requested_mode;
3850d7a8f955Sjmatthew }
3851d7a8f955Sjmatthew 
3852d7a8f955Sjmatthew /**
3853d7a8f955Sjmatthew  *  ixgbe_fc_autoneg_sgmii_x550em_a - Enable flow control IEEE clause 37
3854d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
3855d7a8f955Sjmatthew  *
3856d7a8f955Sjmatthew  *  Enable flow control according to IEEE clause 37.
3857d7a8f955Sjmatthew  **/
3858d7a8f955Sjmatthew void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw)
3859d7a8f955Sjmatthew {
3860d7a8f955Sjmatthew 	int32_t status = IXGBE_ERR_FC_NOT_NEGOTIATED;
3861d7a8f955Sjmatthew 	uint32_t info[FW_PHY_ACT_DATA_COUNT] = { 0 };
3862d7a8f955Sjmatthew 	ixgbe_link_speed speed;
3863d7a8f955Sjmatthew 	bool link_up;
3864d7a8f955Sjmatthew 
3865d7a8f955Sjmatthew 	/* AN should have completed when the cable was plugged in.
3866d7a8f955Sjmatthew 	 * Look for reasons to bail out.  Bail out if:
3867d7a8f955Sjmatthew 	 * - FC autoneg is disabled, or if
3868d7a8f955Sjmatthew 	 * - link is not up.
3869d7a8f955Sjmatthew 	 */
3870d7a8f955Sjmatthew 	if (hw->fc.disable_fc_autoneg) {
3871d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
3872d7a8f955Sjmatthew 			     "Flow control autoneg is disabled");
3873d7a8f955Sjmatthew 		goto out;
3874d7a8f955Sjmatthew 	}
3875d7a8f955Sjmatthew 
3876d7a8f955Sjmatthew 	hw->mac.ops.check_link(hw, &speed, &link_up, FALSE);
3877d7a8f955Sjmatthew 	if (!link_up) {
3878d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down");
3879d7a8f955Sjmatthew 		goto out;
3880d7a8f955Sjmatthew 	}
3881d7a8f955Sjmatthew 
3882d7a8f955Sjmatthew 	/* Check if auto-negotiation has completed */
3883d7a8f955Sjmatthew 	status = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &info);
3884d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS ||
3885d7a8f955Sjmatthew 	    !(info[0] & FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE)) {
3886d7a8f955Sjmatthew 		DEBUGOUT("Auto-Negotiation did not complete\n");
3887d7a8f955Sjmatthew 		status = IXGBE_ERR_FC_NOT_NEGOTIATED;
3888d7a8f955Sjmatthew 		goto out;
3889d7a8f955Sjmatthew 	}
3890d7a8f955Sjmatthew 
3891d7a8f955Sjmatthew 	/* Negotiate the flow control */
3892d7a8f955Sjmatthew 	status = ixgbe_negotiate_fc(hw, info[0], info[0],
3893d7a8f955Sjmatthew 				    FW_PHY_ACT_GET_LINK_INFO_FC_RX,
3894d7a8f955Sjmatthew 				    FW_PHY_ACT_GET_LINK_INFO_FC_TX,
3895d7a8f955Sjmatthew 				    FW_PHY_ACT_GET_LINK_INFO_LP_FC_RX,
3896d7a8f955Sjmatthew 				    FW_PHY_ACT_GET_LINK_INFO_LP_FC_TX);
3897d7a8f955Sjmatthew 
3898d7a8f955Sjmatthew out:
3899d7a8f955Sjmatthew 	if (status == IXGBE_SUCCESS) {
3900d7a8f955Sjmatthew 		hw->fc.fc_was_autonegged = TRUE;
3901d7a8f955Sjmatthew 	} else {
3902d7a8f955Sjmatthew 		hw->fc.fc_was_autonegged = FALSE;
3903d7a8f955Sjmatthew 		hw->fc.current_mode = hw->fc.requested_mode;
3904d7a8f955Sjmatthew 	}
3905d7a8f955Sjmatthew }
3906d7a8f955Sjmatthew 
3907d7a8f955Sjmatthew /**
3908d7a8f955Sjmatthew  *  ixgbe_setup_fc_backplane_x550em_a - Set up flow control
3909d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
3910d7a8f955Sjmatthew  *
3911d7a8f955Sjmatthew  *  Called at init time to set up flow control.
3912d7a8f955Sjmatthew  **/
3913d7a8f955Sjmatthew int32_t ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw)
3914d7a8f955Sjmatthew {
3915d7a8f955Sjmatthew 	int32_t status = IXGBE_SUCCESS;
3916d7a8f955Sjmatthew 	uint32_t an_cntl = 0;
3917d7a8f955Sjmatthew 
3918d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_setup_fc_backplane_x550em_a");
3919d7a8f955Sjmatthew 
3920d7a8f955Sjmatthew 	/* Validate the requested mode */
3921d7a8f955Sjmatthew 	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
3922d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
3923d7a8f955Sjmatthew 			      "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
3924d7a8f955Sjmatthew 		return IXGBE_ERR_INVALID_LINK_SETTINGS;
3925d7a8f955Sjmatthew 	}
3926d7a8f955Sjmatthew 
3927d7a8f955Sjmatthew 	if (hw->fc.requested_mode == ixgbe_fc_default)
3928d7a8f955Sjmatthew 		hw->fc.requested_mode = ixgbe_fc_full;
3929d7a8f955Sjmatthew 
3930d7a8f955Sjmatthew 	/* Set up the 1G and 10G flow control advertisement registers so the
3931d7a8f955Sjmatthew 	 * HW will be able to do FC autoneg once the cable is plugged in.  If
3932d7a8f955Sjmatthew 	 * we link at 10G, the 1G advertisement is harmless and vice versa.
3933d7a8f955Sjmatthew 	 */
3934d7a8f955Sjmatthew 	status = hw->mac.ops.read_iosf_sb_reg(hw,
3935d7a8f955Sjmatthew 					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3936d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl);
3937d7a8f955Sjmatthew 
3938d7a8f955Sjmatthew 	if (status != IXGBE_SUCCESS) {
3939d7a8f955Sjmatthew 		DEBUGOUT("Auto-Negotiation did not complete\n");
3940d7a8f955Sjmatthew 		return status;
3941d7a8f955Sjmatthew 	}
3942d7a8f955Sjmatthew 
3943d7a8f955Sjmatthew 	/* The possible values of fc.requested_mode are:
3944d7a8f955Sjmatthew 	 * 0: Flow control is completely disabled
3945d7a8f955Sjmatthew 	 * 1: Rx flow control is enabled (we can receive pause frames,
3946d7a8f955Sjmatthew 	 *    but not send pause frames).
3947d7a8f955Sjmatthew 	 * 2: Tx flow control is enabled (we can send pause frames but
3948d7a8f955Sjmatthew 	 *    we do not support receiving pause frames).
3949d7a8f955Sjmatthew 	 * 3: Both Rx and Tx flow control (symmetric) are enabled.
3950d7a8f955Sjmatthew 	 * other: Invalid.
3951d7a8f955Sjmatthew 	 */
3952d7a8f955Sjmatthew 	switch (hw->fc.requested_mode) {
3953d7a8f955Sjmatthew 	case ixgbe_fc_none:
3954d7a8f955Sjmatthew 		/* Flow control completely disabled by software override. */
3955d7a8f955Sjmatthew 		an_cntl &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
3956d7a8f955Sjmatthew 			     IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
3957d7a8f955Sjmatthew 		break;
3958d7a8f955Sjmatthew 	case ixgbe_fc_tx_pause:
3959d7a8f955Sjmatthew 		/* Tx Flow control is enabled, and Rx Flow control is
3960d7a8f955Sjmatthew 		 * disabled by software override.
3961d7a8f955Sjmatthew 		 */
3962d7a8f955Sjmatthew 		an_cntl |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
3963d7a8f955Sjmatthew 		an_cntl &= ~IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
3964d7a8f955Sjmatthew 		break;
3965d7a8f955Sjmatthew 	case ixgbe_fc_rx_pause:
3966d7a8f955Sjmatthew 		/* Rx Flow control is enabled and Tx Flow control is
3967d7a8f955Sjmatthew 		 * disabled by software override. Since there really
3968d7a8f955Sjmatthew 		 * isn't a way to advertise that we are capable of RX
3969d7a8f955Sjmatthew 		 * Pause ONLY, we will advertise that we support both
3970d7a8f955Sjmatthew 		 * symmetric and asymmetric Rx PAUSE, as such we fall
3971d7a8f955Sjmatthew 		 * through to the fc_full statement.  Later, we will
3972d7a8f955Sjmatthew 		 * disable the adapter's ability to send PAUSE frames.
3973d7a8f955Sjmatthew 		 */
3974d7a8f955Sjmatthew 	case ixgbe_fc_full:
3975d7a8f955Sjmatthew 		/* Flow control (both Rx and Tx) is enabled by SW override. */
3976d7a8f955Sjmatthew 		an_cntl |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
3977d7a8f955Sjmatthew 			   IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
3978d7a8f955Sjmatthew 		break;
3979d7a8f955Sjmatthew 	default:
3980d7a8f955Sjmatthew 		ERROR_REPORT1(IXGBE_ERROR_ARGUMENT,
3981d7a8f955Sjmatthew 			      "Flow control param set incorrectly\n");
3982d7a8f955Sjmatthew 		return IXGBE_ERR_CONFIG;
3983d7a8f955Sjmatthew 	}
3984d7a8f955Sjmatthew 
3985d7a8f955Sjmatthew 	status = hw->mac.ops.write_iosf_sb_reg(hw,
3986d7a8f955Sjmatthew 					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3987d7a8f955Sjmatthew 					IXGBE_SB_IOSF_TARGET_KR_PHY, an_cntl);
3988d7a8f955Sjmatthew 
3989d7a8f955Sjmatthew 	/* Restart auto-negotiation. */
3990d7a8f955Sjmatthew 	status = ixgbe_restart_an_internal_phy_x550em(hw);
3991d7a8f955Sjmatthew 
3992d7a8f955Sjmatthew 	return status;
3993d7a8f955Sjmatthew }
3994d7a8f955Sjmatthew 
3995d7a8f955Sjmatthew /**
3996ac13930bSmikeb  * ixgbe_set_mux - Set mux for port 1 access with CS4227
3997ac13930bSmikeb  * @hw: pointer to hardware structure
3998ac13930bSmikeb  * @state: set mux if 1, clear if 0
3999ac13930bSmikeb  */
4000ac13930bSmikeb void ixgbe_set_mux(struct ixgbe_hw *hw, uint8_t state)
4001ac13930bSmikeb {
4002ac13930bSmikeb 	uint32_t esdp;
4003ac13930bSmikeb 
4004ac13930bSmikeb 	if (!hw->bus.lan_id)
4005ac13930bSmikeb 		return;
4006ac13930bSmikeb 	esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
4007ac13930bSmikeb 	if (state)
4008ac13930bSmikeb 		esdp |= IXGBE_ESDP_SDP1;
4009ac13930bSmikeb 	else
4010ac13930bSmikeb 		esdp &= ~IXGBE_ESDP_SDP1;
4011ac13930bSmikeb 	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
4012ac13930bSmikeb 	IXGBE_WRITE_FLUSH(hw);
4013ac13930bSmikeb }
4014ac13930bSmikeb 
4015ac13930bSmikeb /**
4016ac13930bSmikeb  *  ixgbe_acquire_swfw_sync_X550em - Acquire SWFW semaphore
4017ac13930bSmikeb  *  @hw: pointer to hardware structure
4018ac13930bSmikeb  *  @mask: Mask to specify which semaphore to acquire
4019ac13930bSmikeb  *
4020ac13930bSmikeb  *  Acquires the SWFW semaphore and sets the I2C MUX
4021ac13930bSmikeb  **/
4022ac13930bSmikeb int32_t ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, uint32_t mask)
4023ac13930bSmikeb {
4024ac13930bSmikeb 	int32_t status;
4025ac13930bSmikeb 
4026ac13930bSmikeb 	DEBUGFUNC("ixgbe_acquire_swfw_sync_X550em");
4027ac13930bSmikeb 
4028ac13930bSmikeb 	status = ixgbe_acquire_swfw_sync_X540(hw, mask);
4029ac13930bSmikeb 	if (status)
4030ac13930bSmikeb 		return status;
4031ac13930bSmikeb 
4032ac13930bSmikeb 	if (mask & IXGBE_GSSR_I2C_MASK)
4033ac13930bSmikeb 		ixgbe_set_mux(hw, 1);
4034ac13930bSmikeb 
4035ac13930bSmikeb 	return IXGBE_SUCCESS;
4036ac13930bSmikeb }
4037ac13930bSmikeb 
4038ac13930bSmikeb /**
4039ac13930bSmikeb  *  ixgbe_release_swfw_sync_X550em - Release SWFW semaphore
4040ac13930bSmikeb  *  @hw: pointer to hardware structure
4041ac13930bSmikeb  *  @mask: Mask to specify which semaphore to release
4042ac13930bSmikeb  *
4043ac13930bSmikeb  *  Releases the SWFW semaphore and sets the I2C MUX
4044ac13930bSmikeb  **/
4045ac13930bSmikeb void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, uint32_t mask)
4046ac13930bSmikeb {
4047ac13930bSmikeb 	DEBUGFUNC("ixgbe_release_swfw_sync_X550em");
4048ac13930bSmikeb 
4049ac13930bSmikeb 	if (mask & IXGBE_GSSR_I2C_MASK)
4050ac13930bSmikeb 		ixgbe_set_mux(hw, 0);
4051ac13930bSmikeb 
4052ac13930bSmikeb 	ixgbe_release_swfw_sync_X540(hw, mask);
4053ac13930bSmikeb }
4054ac13930bSmikeb 
4055ac13930bSmikeb /**
4056d7a8f955Sjmatthew  *  ixgbe_acquire_swfw_sync_X550a - Acquire SWFW semaphore
4057d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
4058d7a8f955Sjmatthew  *  @mask: Mask to specify which semaphore to acquire
4059d7a8f955Sjmatthew  *
4060d7a8f955Sjmatthew  *  Acquires the SWFW semaphore and get the shared phy token as needed
4061d7a8f955Sjmatthew  */
4062d7a8f955Sjmatthew int32_t ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, uint32_t mask)
4063d7a8f955Sjmatthew {
4064d7a8f955Sjmatthew 	uint32_t hmask = mask & ~IXGBE_GSSR_TOKEN_SM;
4065d7a8f955Sjmatthew 	int retries = FW_PHY_TOKEN_RETRIES;
4066d7a8f955Sjmatthew 	int32_t status = IXGBE_SUCCESS;
4067d7a8f955Sjmatthew 
4068d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_acquire_swfw_sync_X550a");
4069d7a8f955Sjmatthew 
4070d7a8f955Sjmatthew 	while (--retries) {
4071d7a8f955Sjmatthew 		status = IXGBE_SUCCESS;
4072d7a8f955Sjmatthew 		if (hmask)
4073d7a8f955Sjmatthew 			status = ixgbe_acquire_swfw_sync_X540(hw, hmask);
4074d7a8f955Sjmatthew 		if (status) {
4075d7a8f955Sjmatthew 			DEBUGOUT1("Could not acquire SWFW semaphore, Status = %d\n",
4076d7a8f955Sjmatthew 				  status);
4077d7a8f955Sjmatthew 			return status;
4078d7a8f955Sjmatthew 		}
4079d7a8f955Sjmatthew 		if (!(mask & IXGBE_GSSR_TOKEN_SM))
4080d7a8f955Sjmatthew 			return IXGBE_SUCCESS;
4081d7a8f955Sjmatthew 
4082d7a8f955Sjmatthew 		status = ixgbe_get_phy_token(hw);
4083d7a8f955Sjmatthew 		if (status == IXGBE_ERR_TOKEN_RETRY)
4084d7a8f955Sjmatthew 			DEBUGOUT1("Could not acquire PHY token, Status = %d\n",
4085d7a8f955Sjmatthew 				  status);
4086d7a8f955Sjmatthew 
4087d7a8f955Sjmatthew 		if (status == IXGBE_SUCCESS)
4088d7a8f955Sjmatthew 			return IXGBE_SUCCESS;
4089d7a8f955Sjmatthew 
4090d7a8f955Sjmatthew 		if (hmask)
4091d7a8f955Sjmatthew 			ixgbe_release_swfw_sync_X540(hw, hmask);
4092d7a8f955Sjmatthew 
4093d7a8f955Sjmatthew 		if (status != IXGBE_ERR_TOKEN_RETRY) {
4094d7a8f955Sjmatthew 			DEBUGOUT1("Unable to retry acquiring the PHY token, Status = %d\n",
4095d7a8f955Sjmatthew 				  status);
4096d7a8f955Sjmatthew 			return status;
4097d7a8f955Sjmatthew 		}
4098d7a8f955Sjmatthew 	}
4099d7a8f955Sjmatthew 
4100d7a8f955Sjmatthew 	DEBUGOUT1("Semaphore acquisition retries failed!: PHY ID = 0x%08X\n",
4101d7a8f955Sjmatthew 		  hw->phy.id);
4102d7a8f955Sjmatthew 	return status;
4103d7a8f955Sjmatthew }
4104d7a8f955Sjmatthew 
4105d7a8f955Sjmatthew /**
4106d7a8f955Sjmatthew  *  ixgbe_release_swfw_sync_X550a - Release SWFW semaphore
4107d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
4108d7a8f955Sjmatthew  *  @mask: Mask to specify which semaphore to release
4109d7a8f955Sjmatthew  *
4110d7a8f955Sjmatthew  *  Releases the SWFW semaphore and puts the shared phy token as needed
4111d7a8f955Sjmatthew  */
4112d7a8f955Sjmatthew void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *hw, uint32_t mask)
4113d7a8f955Sjmatthew {
4114d7a8f955Sjmatthew 	uint32_t hmask = mask & ~IXGBE_GSSR_TOKEN_SM;
4115d7a8f955Sjmatthew 
4116d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_release_swfw_sync_X550a");
4117d7a8f955Sjmatthew 
4118d7a8f955Sjmatthew 	if (mask & IXGBE_GSSR_TOKEN_SM)
4119d7a8f955Sjmatthew 		ixgbe_put_phy_token(hw);
4120d7a8f955Sjmatthew 
4121d7a8f955Sjmatthew 	if (hmask)
4122d7a8f955Sjmatthew 		ixgbe_release_swfw_sync_X540(hw, hmask);
4123d7a8f955Sjmatthew }
4124d7a8f955Sjmatthew 
4125d7a8f955Sjmatthew /**
4126d7a8f955Sjmatthew  *  ixgbe_read_phy_reg_x550a  - Reads specified PHY register
4127d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
4128d7a8f955Sjmatthew  *  @reg_addr: 32 bit address of PHY register to read
4129d7a8f955Sjmatthew  *  @device_type: 5 bit device type
4130d7a8f955Sjmatthew  *  @phy_data: Pointer to read data from PHY register
4131d7a8f955Sjmatthew  *
4132d7a8f955Sjmatthew  *  Reads a value from a specified PHY register using the SWFW lock and PHY
4133d7a8f955Sjmatthew  *  Token. The PHY Token is needed since the MDIO is shared between to MAC
4134d7a8f955Sjmatthew  *  instances.
4135d7a8f955Sjmatthew  **/
4136d7a8f955Sjmatthew int32_t ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
4137d7a8f955Sjmatthew 			       uint32_t device_type, uint16_t *phy_data)
4138d7a8f955Sjmatthew {
4139d7a8f955Sjmatthew 	int32_t status;
4140d7a8f955Sjmatthew 	uint32_t mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM;
4141d7a8f955Sjmatthew 
4142d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_read_phy_reg_x550a");
4143d7a8f955Sjmatthew 
4144d7a8f955Sjmatthew 	if (hw->mac.ops.acquire_swfw_sync(hw, mask))
4145d7a8f955Sjmatthew 		return IXGBE_ERR_SWFW_SYNC;
4146d7a8f955Sjmatthew 
4147d7a8f955Sjmatthew 	status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data);
4148d7a8f955Sjmatthew 
4149d7a8f955Sjmatthew 	hw->mac.ops.release_swfw_sync(hw, mask);
4150d7a8f955Sjmatthew 
4151d7a8f955Sjmatthew 	return status;
4152d7a8f955Sjmatthew }
4153d7a8f955Sjmatthew 
4154d7a8f955Sjmatthew /**
4155d7a8f955Sjmatthew  *  ixgbe_write_phy_reg_x550a - Writes specified PHY register
4156d7a8f955Sjmatthew  *  @hw: pointer to hardware structure
4157d7a8f955Sjmatthew  *  @reg_addr: 32 bit PHY register to write
4158d7a8f955Sjmatthew  *  @device_type: 5 bit device type
4159d7a8f955Sjmatthew  *  @phy_data: Data to write to the PHY register
4160d7a8f955Sjmatthew  *
4161d7a8f955Sjmatthew  *  Writes a value to specified PHY register using the SWFW lock and PHY Token.
4162d7a8f955Sjmatthew  *  The PHY Token is needed since the MDIO is shared between to MAC instances.
4163d7a8f955Sjmatthew  **/
4164d7a8f955Sjmatthew int32_t ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, uint32_t reg_addr,
4165d7a8f955Sjmatthew 				uint32_t device_type, uint16_t phy_data)
4166d7a8f955Sjmatthew {
4167d7a8f955Sjmatthew 	int32_t status;
4168d7a8f955Sjmatthew 	uint32_t mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM;
4169d7a8f955Sjmatthew 
4170d7a8f955Sjmatthew 	DEBUGFUNC("ixgbe_write_phy_reg_x550a");
4171d7a8f955Sjmatthew 
4172d7a8f955Sjmatthew 	if (hw->mac.ops.acquire_swfw_sync(hw, mask) == IXGBE_SUCCESS) {
4173d7a8f955Sjmatthew 		status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type,
4174d7a8f955Sjmatthew 						 phy_data);
4175d7a8f955Sjmatthew 		hw->mac.ops.release_swfw_sync(hw, mask);
4176d7a8f955Sjmatthew 	} else {
4177d7a8f955Sjmatthew 		status = IXGBE_ERR_SWFW_SYNC;
4178d7a8f955Sjmatthew 	}
4179d7a8f955Sjmatthew 
4180d7a8f955Sjmatthew 	return status;
4181d7a8f955Sjmatthew }
4182d7a8f955Sjmatthew 
4183d7a8f955Sjmatthew /**
4184ac13930bSmikeb  * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
4185ac13930bSmikeb  * @hw: pointer to hardware structure
4186ac13930bSmikeb  *
4187ac13930bSmikeb  * Handle external Base T PHY interrupt. If high temperature
4188ac13930bSmikeb  * failure alarm then return error, else if link status change
4189ac13930bSmikeb  * then setup internal/external PHY link
4190ac13930bSmikeb  *
4191ac13930bSmikeb  * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
4192ac13930bSmikeb  * failure alarm, else return PHY access status.
4193ac13930bSmikeb  */
4194ac13930bSmikeb int32_t ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
4195ac13930bSmikeb {
4196ac13930bSmikeb 	bool lsc;
4197ac13930bSmikeb 	uint32_t status;
4198ac13930bSmikeb 
4199ac13930bSmikeb 	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
4200ac13930bSmikeb 
4201ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
4202ac13930bSmikeb 		return status;
4203ac13930bSmikeb 
4204d7a8f955Sjmatthew 	if (lsc)
4205ac13930bSmikeb 		return hw->phy.ops.setup_internal_link(hw);
4206ac13930bSmikeb 
4207ac13930bSmikeb 	return IXGBE_SUCCESS;
4208ac13930bSmikeb }
4209ac13930bSmikeb 
4210ac13930bSmikeb /**
4211ac13930bSmikeb  * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
4212ac13930bSmikeb  * @hw: pointer to hardware structure
4213ac13930bSmikeb  * @speed: new link speed
4214ac13930bSmikeb  * @autoneg_wait_to_complete: TRUE when waiting for completion is needed
4215ac13930bSmikeb  *
4216ac13930bSmikeb  * Setup internal/external PHY link speed based on link speed, then set
4217ac13930bSmikeb  * external PHY auto advertised link speed.
4218ac13930bSmikeb  *
4219ac13930bSmikeb  * Returns error status for any failure
4220ac13930bSmikeb  **/
4221ac13930bSmikeb int32_t ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
4222ac13930bSmikeb 				      ixgbe_link_speed speed,
4223ac13930bSmikeb 				      bool autoneg_wait_to_complete)
4224ac13930bSmikeb {
4225ac13930bSmikeb 	int32_t status;
4226ac13930bSmikeb 	ixgbe_link_speed force_speed;
4227ac13930bSmikeb 
4228ac13930bSmikeb 	DEBUGFUNC("ixgbe_setup_mac_link_t_X550em");
4229ac13930bSmikeb 
4230ac13930bSmikeb 	/* Setup internal/external PHY link speed to iXFI (10G), unless
4231ac13930bSmikeb 	 * only 1G is auto advertised then setup KX link.
4232ac13930bSmikeb 	 */
4233ac13930bSmikeb 	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
4234ac13930bSmikeb 		force_speed = IXGBE_LINK_SPEED_10GB_FULL;
4235ac13930bSmikeb 	else
4236ac13930bSmikeb 		force_speed = IXGBE_LINK_SPEED_1GB_FULL;
4237ac13930bSmikeb 
4238d7a8f955Sjmatthew 	/* If X552 and internal link mode is XFI, then setup XFI internal link.
4239d7a8f955Sjmatthew 	 */
4240d7a8f955Sjmatthew 	if (hw->mac.type == ixgbe_mac_X550EM_x &&
4241d7a8f955Sjmatthew 	    !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
4242ac13930bSmikeb 		status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
4243ac13930bSmikeb 
4244ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
4245ac13930bSmikeb 			return status;
4246ac13930bSmikeb 	}
4247ac13930bSmikeb 
4248ac13930bSmikeb 	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete);
4249ac13930bSmikeb }
4250ac13930bSmikeb 
4251ac13930bSmikeb /**
4252ac13930bSmikeb  * ixgbe_check_link_t_X550em - Determine link and speed status
4253ac13930bSmikeb  * @hw: pointer to hardware structure
4254ac13930bSmikeb  * @speed: pointer to link speed
4255ac13930bSmikeb  * @link_up: TRUE when link is up
4256ac13930bSmikeb  * @link_up_wait_to_complete: bool used to wait for link up or not
4257ac13930bSmikeb  *
4258ac13930bSmikeb  * Check that both the MAC and X557 external PHY have link.
4259ac13930bSmikeb  **/
4260ac13930bSmikeb int32_t ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
4261ac13930bSmikeb 				  bool *link_up, bool link_up_wait_to_complete)
4262ac13930bSmikeb {
4263ac13930bSmikeb 	uint32_t status;
4264d7a8f955Sjmatthew 	uint16_t i, autoneg_status = 0;
4265ac13930bSmikeb 
4266ac13930bSmikeb 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
4267ac13930bSmikeb 		return IXGBE_ERR_CONFIG;
4268ac13930bSmikeb 
4269ac13930bSmikeb 	status = ixgbe_check_mac_link_generic(hw, speed, link_up,
4270ac13930bSmikeb 					      link_up_wait_to_complete);
4271ac13930bSmikeb 
4272ac13930bSmikeb 	/* If check link fails or MAC link is not up, then return */
4273ac13930bSmikeb 	if (status != IXGBE_SUCCESS || !(*link_up))
4274ac13930bSmikeb 		return status;
4275ac13930bSmikeb 
4276ac13930bSmikeb 	/* MAC link is up, so check external PHY link.
4277d7a8f955Sjmatthew 	 * X557 PHY. Link status is latching low, and can only be used to detect
4278d7a8f955Sjmatthew 	 * link drop, and not the current status of the link without performing
4279d7a8f955Sjmatthew 	 * back-to-back reads.
4280ac13930bSmikeb 	 */
4281d7a8f955Sjmatthew 	for (i = 0; i < 2; i++) {
4282ac13930bSmikeb 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
4283ac13930bSmikeb 					      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
4284ac13930bSmikeb 					      &autoneg_status);
4285ac13930bSmikeb 
4286ac13930bSmikeb 		if (status != IXGBE_SUCCESS)
4287ac13930bSmikeb 			return status;
4288d7a8f955Sjmatthew 	}
4289ac13930bSmikeb 
4290ac13930bSmikeb 	/* If external PHY link is not up, then indicate link not up */
4291ac13930bSmikeb 	if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
4292ac13930bSmikeb 		*link_up = FALSE;
4293ac13930bSmikeb 
4294ac13930bSmikeb 	return IXGBE_SUCCESS;
4295ac13930bSmikeb }
4296ac13930bSmikeb 
4297ac13930bSmikeb /**
4298ac13930bSmikeb  *  ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI
4299ac13930bSmikeb  *  @hw: pointer to hardware structure
4300ac13930bSmikeb  **/
4301ac13930bSmikeb int32_t ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw)
4302ac13930bSmikeb {
4303ac13930bSmikeb 	int32_t status;
4304ac13930bSmikeb 
4305ac13930bSmikeb 	status = ixgbe_reset_phy_generic(hw);
4306ac13930bSmikeb 
4307ac13930bSmikeb 	if (status != IXGBE_SUCCESS)
4308ac13930bSmikeb 		return status;
4309ac13930bSmikeb 
4310ac13930bSmikeb 	/* Configure Link Status Alarm and Temperature Threshold interrupts */
4311ac13930bSmikeb 	return ixgbe_enable_lasi_ext_t_x550em(hw);
4312ac13930bSmikeb }
4313ac13930bSmikeb 
4314ac13930bSmikeb /**
4315ac13930bSmikeb  *  ixgbe_led_on_t_X550em - Turns on the software controllable LEDs.
4316ac13930bSmikeb  *  @hw: pointer to hardware structure
4317ac13930bSmikeb  *  @led_idx: led number to turn on
4318ac13930bSmikeb  **/
4319ac13930bSmikeb int32_t ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, uint32_t led_idx)
4320ac13930bSmikeb {
4321ac13930bSmikeb 	uint16_t phy_data;
4322ac13930bSmikeb 
4323ac13930bSmikeb 	DEBUGFUNC("ixgbe_led_on_t_X550em");
4324ac13930bSmikeb 
4325ac13930bSmikeb 	if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
4326ac13930bSmikeb 		return IXGBE_ERR_PARAM;
4327ac13930bSmikeb 
4328d7a8f955Sjmatthew 	if (hw->phy.id == 0)
4329d7a8f955Sjmatthew 		ixgbe_identify_phy(hw);
4330d7a8f955Sjmatthew 
4331ac13930bSmikeb 	/* To turn on the LED, set mode to ON. */
4332ac13930bSmikeb 	hw->phy.ops.read_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4333ac13930bSmikeb 			   IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data);
4334ac13930bSmikeb 	phy_data |= IXGBE_X557_LED_MANUAL_SET_MASK;
4335ac13930bSmikeb 	hw->phy.ops.write_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4336ac13930bSmikeb 			    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data);
4337ac13930bSmikeb 
4338d7a8f955Sjmatthew 	/* Some designs have the LEDs wired to the MAC */
4339d7a8f955Sjmatthew 	return ixgbe_led_on_generic(hw, led_idx);
4340ac13930bSmikeb }
4341ac13930bSmikeb 
4342ac13930bSmikeb /**
4343ac13930bSmikeb  *  ixgbe_led_off_t_X550em - Turns off the software controllable LEDs.
4344ac13930bSmikeb  *  @hw: pointer to hardware structure
4345ac13930bSmikeb  *  @led_idx: led number to turn off
4346ac13930bSmikeb  **/
4347ac13930bSmikeb int32_t ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, uint32_t led_idx)
4348ac13930bSmikeb {
4349ac13930bSmikeb 	uint16_t phy_data;
4350ac13930bSmikeb 
4351ac13930bSmikeb 	DEBUGFUNC("ixgbe_led_off_t_X550em");
4352ac13930bSmikeb 
4353ac13930bSmikeb 	if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
4354ac13930bSmikeb 		return IXGBE_ERR_PARAM;
4355ac13930bSmikeb 
4356d7a8f955Sjmatthew 	if (hw->phy.id == 0)
4357d7a8f955Sjmatthew 		ixgbe_identify_phy(hw);
4358d7a8f955Sjmatthew 
4359ac13930bSmikeb 	/* To turn on the LED, set mode to ON. */
4360ac13930bSmikeb 	hw->phy.ops.read_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4361ac13930bSmikeb 			   IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data);
4362ac13930bSmikeb 	phy_data &= ~IXGBE_X557_LED_MANUAL_SET_MASK;
4363ac13930bSmikeb 	hw->phy.ops.write_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4364ac13930bSmikeb 			    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data);
4365ac13930bSmikeb 
4366d7a8f955Sjmatthew 	/* Some designs have the LEDs wired to the MAC */
4367d7a8f955Sjmatthew 	return ixgbe_led_off_generic(hw, led_idx);
4368ac13930bSmikeb }
4369