1282289Serj/******************************************************************************
2282289Serj
3315333Serj  Copyright (c) 2001-2017, Intel Corporation
4282289Serj  All rights reserved.
5315333Serj
6315333Serj  Redistribution and use in source and binary forms, with or without
7282289Serj  modification, are permitted provided that the following conditions are met:
8315333Serj
9315333Serj   1. Redistributions of source code must retain the above copyright notice,
10282289Serj      this list of conditions and the following disclaimer.
11315333Serj
12315333Serj   2. Redistributions in binary form must reproduce the above copyright
13315333Serj      notice, this list of conditions and the following disclaimer in the
14282289Serj      documentation and/or other materials provided with the distribution.
15315333Serj
16315333Serj   3. Neither the name of the Intel Corporation nor the names of its
17315333Serj      contributors may be used to endorse or promote products derived from
18282289Serj      this software without specific prior written permission.
19315333Serj
20282289Serj  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21315333Serj  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22315333Serj  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23315333Serj  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24315333Serj  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25315333Serj  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26315333Serj  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27315333Serj  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28315333Serj  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29282289Serj  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30282289Serj  POSSIBILITY OF SUCH DAMAGE.
31282289Serj
32282289Serj******************************************************************************/
33282289Serj/*$FreeBSD: stable/10/sys/dev/ixgbe/ixgbe_x550.c 315333 2017-03-15 21:20:17Z erj $*/
34282289Serj
35282289Serj#include "ixgbe_x550.h"
36282289Serj#include "ixgbe_x540.h"
37282289Serj#include "ixgbe_type.h"
38282289Serj#include "ixgbe_api.h"
39282289Serj#include "ixgbe_common.h"
40282289Serj#include "ixgbe_phy.h"
41282289Serj
42282289Serjstatic s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed);
43315333Serjstatic s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, u32 mask);
44315333Serjstatic void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *, u32 mask);
45315333Serjstatic s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw);
46282289Serj
47282289Serj/**
48282289Serj *  ixgbe_init_ops_X550 - Inits func ptrs and MAC type
49282289Serj *  @hw: pointer to hardware structure
50282289Serj *
51282289Serj *  Initialize the function pointers and assign the MAC type for X550.
52282289Serj *  Does not touch the hardware.
53282289Serj **/
54282289Serjs32 ixgbe_init_ops_X550(struct ixgbe_hw *hw)
55282289Serj{
56282289Serj	struct ixgbe_mac_info *mac = &hw->mac;
57282289Serj	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
58282289Serj	s32 ret_val;
59282289Serj
60282289Serj	DEBUGFUNC("ixgbe_init_ops_X550");
61282289Serj
62282289Serj	ret_val = ixgbe_init_ops_X540(hw);
63282289Serj	mac->ops.dmac_config = ixgbe_dmac_config_X550;
64282289Serj	mac->ops.dmac_config_tcs = ixgbe_dmac_config_tcs_X550;
65282289Serj	mac->ops.dmac_update_tcs = ixgbe_dmac_update_tcs_X550;
66315333Serj	mac->ops.setup_eee = NULL;
67282289Serj	mac->ops.set_source_address_pruning =
68282289Serj			ixgbe_set_source_address_pruning_X550;
69282289Serj	mac->ops.set_ethertype_anti_spoofing =
70282289Serj			ixgbe_set_ethertype_anti_spoofing_X550;
71282289Serj
72282289Serj	mac->ops.get_rtrup2tc = ixgbe_dcb_get_rtrup2tc_generic;
73282289Serj	eeprom->ops.init_params = ixgbe_init_eeprom_params_X550;
74282289Serj	eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550;
75282289Serj	eeprom->ops.read = ixgbe_read_ee_hostif_X550;
76282289Serj	eeprom->ops.read_buffer = ixgbe_read_ee_hostif_buffer_X550;
77282289Serj	eeprom->ops.write = ixgbe_write_ee_hostif_X550;
78282289Serj	eeprom->ops.write_buffer = ixgbe_write_ee_hostif_buffer_X550;
79282289Serj	eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550;
80282289Serj	eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550;
81282289Serj
82282289Serj	mac->ops.disable_mdd = ixgbe_disable_mdd_X550;
83282289Serj	mac->ops.enable_mdd = ixgbe_enable_mdd_X550;
84282289Serj	mac->ops.mdd_event = ixgbe_mdd_event_X550;
85282289Serj	mac->ops.restore_mdd_vf = ixgbe_restore_mdd_vf_X550;
86282289Serj	mac->ops.disable_rx = ixgbe_disable_rx_x550;
87315333Serj	/* Manageability interface */
88315333Serj	mac->ops.set_fw_drv_ver = ixgbe_set_fw_drv_ver_x550;
89315333Serj	switch (hw->device_id) {
90315333Serj	case IXGBE_DEV_ID_X550EM_X_10G_T:
91315333Serj	case IXGBE_DEV_ID_X550EM_A_10G_T:
92282289Serj		hw->mac.ops.led_on = ixgbe_led_on_t_X550em;
93282289Serj		hw->mac.ops.led_off = ixgbe_led_off_t_X550em;
94315333Serj		break;
95315333Serj	default:
96315333Serj		break;
97282289Serj	}
98282289Serj	return ret_val;
99282289Serj}
100282289Serj
101282289Serj/**
102282289Serj * ixgbe_read_cs4227 - Read CS4227 register
103282289Serj * @hw: pointer to hardware structure
104282289Serj * @reg: register number to write
105282289Serj * @value: pointer to receive value read
106282289Serj *
107282289Serj * Returns status code
108282289Serj **/
109282289Serjstatic s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value)
110282289Serj{
111315333Serj	return hw->link.ops.read_link_unlocked(hw, hw->link.addr, reg, value);
112282289Serj}
113282289Serj
114282289Serj/**
115282289Serj * ixgbe_write_cs4227 - Write CS4227 register
116282289Serj * @hw: pointer to hardware structure
117282289Serj * @reg: register number to write
118282289Serj * @value: value to write to register
119282289Serj *
120282289Serj * Returns status code
121282289Serj **/
122282289Serjstatic s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value)
123282289Serj{
124315333Serj	return hw->link.ops.write_link_unlocked(hw, hw->link.addr, reg, value);
125282289Serj}
126282289Serj
127282289Serj/**
128282289Serj * ixgbe_read_pe - Read register from port expander
129282289Serj * @hw: pointer to hardware structure
130282289Serj * @reg: register number to read
131282289Serj * @value: pointer to receive read value
132282289Serj *
133282289Serj * Returns status code
134282289Serj **/
135282289Serjstatic s32 ixgbe_read_pe(struct ixgbe_hw *hw, u8 reg, u8 *value)
136282289Serj{
137282289Serj	s32 status;
138282289Serj
139282289Serj	status = ixgbe_read_i2c_byte_unlocked(hw, reg, IXGBE_PE, value);
140282289Serj	if (status != IXGBE_SUCCESS)
141282289Serj		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
142282289Serj			      "port expander access failed with %d\n", status);
143282289Serj	return status;
144282289Serj}
145282289Serj
146282289Serj/**
147282289Serj * ixgbe_write_pe - Write register to port expander
148282289Serj * @hw: pointer to hardware structure
149282289Serj * @reg: register number to write
150282289Serj * @value: value to write
151282289Serj *
152282289Serj * Returns status code
153282289Serj **/
154282289Serjstatic s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value)
155282289Serj{
156282289Serj	s32 status;
157282289Serj
158282289Serj	status = ixgbe_write_i2c_byte_unlocked(hw, reg, IXGBE_PE, value);
159282289Serj	if (status != IXGBE_SUCCESS)
160282289Serj		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
161282289Serj			      "port expander access failed with %d\n", status);
162282289Serj	return status;
163282289Serj}
164282289Serj
165282289Serj/**
166282289Serj * ixgbe_reset_cs4227 - Reset CS4227 using port expander
167282289Serj * @hw: pointer to hardware structure
168282289Serj *
169295524Ssbruno * This function assumes that the caller has acquired the proper semaphore.
170282289Serj * Returns error code
171282289Serj **/
172282289Serjstatic s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw)
173282289Serj{
174282289Serj	s32 status;
175295524Ssbruno	u32 retry;
176295524Ssbruno	u16 value;
177282289Serj	u8 reg;
178282289Serj
179295524Ssbruno	/* Trigger hard reset. */
180282289Serj	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
181282289Serj	if (status != IXGBE_SUCCESS)
182282289Serj		return status;
183282289Serj	reg |= IXGBE_PE_BIT1;
184282289Serj	status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
185282289Serj	if (status != IXGBE_SUCCESS)
186282289Serj		return status;
187282289Serj
188282289Serj	status = ixgbe_read_pe(hw, IXGBE_PE_CONFIG, &reg);
189282289Serj	if (status != IXGBE_SUCCESS)
190282289Serj		return status;
191282289Serj	reg &= ~IXGBE_PE_BIT1;
192282289Serj	status = ixgbe_write_pe(hw, IXGBE_PE_CONFIG, reg);
193282289Serj	if (status != IXGBE_SUCCESS)
194282289Serj		return status;
195282289Serj
196282289Serj	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
197282289Serj	if (status != IXGBE_SUCCESS)
198282289Serj		return status;
199282289Serj	reg &= ~IXGBE_PE_BIT1;
200282289Serj	status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
201282289Serj	if (status != IXGBE_SUCCESS)
202282289Serj		return status;
203282289Serj
204282289Serj	usec_delay(IXGBE_CS4227_RESET_HOLD);
205282289Serj
206282289Serj	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
207282289Serj	if (status != IXGBE_SUCCESS)
208282289Serj		return status;
209282289Serj	reg |= IXGBE_PE_BIT1;
210282289Serj	status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
211282289Serj	if (status != IXGBE_SUCCESS)
212282289Serj		return status;
213282289Serj
214295524Ssbruno	/* Wait for the reset to complete. */
215282289Serj	msec_delay(IXGBE_CS4227_RESET_DELAY);
216295524Ssbruno	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
217295524Ssbruno		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EFUSE_STATUS,
218295524Ssbruno					   &value);
219295524Ssbruno		if (status == IXGBE_SUCCESS &&
220295524Ssbruno		    value == IXGBE_CS4227_EEPROM_LOAD_OK)
221295524Ssbruno			break;
222295524Ssbruno		msec_delay(IXGBE_CS4227_CHECK_DELAY);
223295524Ssbruno	}
224295524Ssbruno	if (retry == IXGBE_CS4227_RETRIES) {
225295524Ssbruno		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
226295524Ssbruno			"CS4227 reset did not complete.");
227295524Ssbruno		return IXGBE_ERR_PHY;
228295524Ssbruno	}
229282289Serj
230295524Ssbruno	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value);
231295524Ssbruno	if (status != IXGBE_SUCCESS ||
232295524Ssbruno	    !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) {
233295524Ssbruno		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
234295524Ssbruno			"CS4227 EEPROM did not load successfully.");
235295524Ssbruno		return IXGBE_ERR_PHY;
236295524Ssbruno	}
237295524Ssbruno
238282289Serj	return IXGBE_SUCCESS;
239282289Serj}
240282289Serj
241282289Serj/**
242282289Serj * ixgbe_check_cs4227 - Check CS4227 and reset as needed
243282289Serj * @hw: pointer to hardware structure
244282289Serj **/
245282289Serjstatic void ixgbe_check_cs4227(struct ixgbe_hw *hw)
246282289Serj{
247295524Ssbruno	s32 status = IXGBE_SUCCESS;
248282289Serj	u32 swfw_mask = hw->phy.phy_semaphore_mask;
249295524Ssbruno	u16 value = 0;
250282289Serj	u8 retry;
251282289Serj
252282289Serj	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
253282289Serj		status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
254282289Serj		if (status != IXGBE_SUCCESS) {
255282289Serj			ERROR_REPORT2(IXGBE_ERROR_CAUTION,
256295524Ssbruno				"semaphore failed with %d", status);
257295524Ssbruno			msec_delay(IXGBE_CS4227_CHECK_DELAY);
258295524Ssbruno			continue;
259282289Serj		}
260295524Ssbruno
261295524Ssbruno		/* Get status of reset flow. */
262295524Ssbruno		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
263295524Ssbruno
264295524Ssbruno		if (status == IXGBE_SUCCESS &&
265295524Ssbruno		    value == IXGBE_CS4227_RESET_COMPLETE)
266295524Ssbruno			goto out;
267295524Ssbruno
268295524Ssbruno		if (status != IXGBE_SUCCESS ||
269295524Ssbruno		    value != IXGBE_CS4227_RESET_PENDING)
270295524Ssbruno			break;
271295524Ssbruno
272295524Ssbruno		/* Reset is pending. Wait and check again. */
273295524Ssbruno		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
274295524Ssbruno		msec_delay(IXGBE_CS4227_CHECK_DELAY);
275295524Ssbruno	}
276295524Ssbruno
277295524Ssbruno	/* If still pending, assume other instance failed. */
278295524Ssbruno	if (retry == IXGBE_CS4227_RETRIES) {
279295524Ssbruno		status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
280295524Ssbruno		if (status != IXGBE_SUCCESS) {
281295524Ssbruno			ERROR_REPORT2(IXGBE_ERROR_CAUTION,
282295524Ssbruno				      "semaphore failed with %d", status);
283282289Serj			return;
284282289Serj		}
285282289Serj	}
286295524Ssbruno
287295524Ssbruno	/* Reset the CS4227. */
288295524Ssbruno	status = ixgbe_reset_cs4227(hw);
289295524Ssbruno	if (status != IXGBE_SUCCESS) {
290295524Ssbruno		ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
291295524Ssbruno			"CS4227 reset failed: %d", status);
292295524Ssbruno		goto out;
293295524Ssbruno	}
294295524Ssbruno
295295524Ssbruno	/* Reset takes so long, temporarily release semaphore in case the
296295524Ssbruno	 * other driver instance is waiting for the reset indication.
297295524Ssbruno	 */
298295524Ssbruno	ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
299295524Ssbruno			   IXGBE_CS4227_RESET_PENDING);
300295524Ssbruno	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
301295524Ssbruno	msec_delay(10);
302295524Ssbruno	status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
303295524Ssbruno	if (status != IXGBE_SUCCESS) {
304295524Ssbruno		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
305295524Ssbruno			"semaphore failed with %d", status);
306295524Ssbruno		return;
307295524Ssbruno	}
308295524Ssbruno
309295524Ssbruno	/* Record completion for next time. */
310295524Ssbruno	status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
311295524Ssbruno		IXGBE_CS4227_RESET_COMPLETE);
312295524Ssbruno
313295524Ssbrunoout:
314295524Ssbruno	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
315295524Ssbruno	msec_delay(hw->eeprom.semaphore_delay);
316282289Serj}
317282289Serj
318282289Serj/**
319282289Serj * ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control
320282289Serj * @hw: pointer to hardware structure
321282289Serj **/
322282289Serjstatic void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw)
323282289Serj{
324282289Serj	u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
325282289Serj
326282289Serj	if (hw->bus.lan_id) {
327282289Serj		esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
328282289Serj		esdp |= IXGBE_ESDP_SDP1_DIR;
329282289Serj	}
330282289Serj	esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
331282289Serj	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
332282289Serj	IXGBE_WRITE_FLUSH(hw);
333282289Serj}
334282289Serj
335282289Serj/**
336315333Serj * ixgbe_read_phy_reg_mdi_22 - Read from a clause 22 PHY register without lock
337315333Serj * @hw: pointer to hardware structure
338315333Serj * @reg_addr: 32 bit address of PHY register to read
339315333Serj * @dev_type: always unused
340315333Serj * @phy_data: Pointer to read data from PHY register
341315333Serj */
342315333Serjstatic s32 ixgbe_read_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr,
343315333Serj				     u32 dev_type, u16 *phy_data)
344315333Serj{
345315333Serj	u32 i, data, command;
346315333Serj	UNREFERENCED_1PARAMETER(dev_type);
347315333Serj
348315333Serj	/* Setup and write the read command */
349315333Serj	command = (reg_addr << IXGBE_MSCA_DEV_TYPE_SHIFT) |
350315333Serj		  (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
351315333Serj		  IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_READ_AUTOINC |
352315333Serj		  IXGBE_MSCA_MDI_COMMAND;
353315333Serj
354315333Serj	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
355315333Serj
356315333Serj	/* Check every 10 usec to see if the access completed.
357315333Serj	 * The MDI Command bit will clear when the operation is
358315333Serj	 * complete
359315333Serj	 */
360315333Serj	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
361315333Serj		usec_delay(10);
362315333Serj
363315333Serj		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
364315333Serj		if (!(command & IXGBE_MSCA_MDI_COMMAND))
365315333Serj			break;
366315333Serj	}
367315333Serj
368315333Serj	if (command & IXGBE_MSCA_MDI_COMMAND) {
369315333Serj		ERROR_REPORT1(IXGBE_ERROR_POLLING,
370315333Serj			      "PHY read command did not complete.\n");
371315333Serj		return IXGBE_ERR_PHY;
372315333Serj	}
373315333Serj
374315333Serj	/* Read operation is complete.  Get the data from MSRWD */
375315333Serj	data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
376315333Serj	data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
377315333Serj	*phy_data = (u16)data;
378315333Serj
379315333Serj	return IXGBE_SUCCESS;
380315333Serj}
381315333Serj
382315333Serj/**
383315333Serj * ixgbe_write_phy_reg_mdi_22 - Write to a clause 22 PHY register without lock
384315333Serj * @hw: pointer to hardware structure
385315333Serj * @reg_addr: 32 bit PHY register to write
386315333Serj * @dev_type: always unused
387315333Serj * @phy_data: Data to write to the PHY register
388315333Serj */
389315333Serjstatic s32 ixgbe_write_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr,
390315333Serj				      u32 dev_type, u16 phy_data)
391315333Serj{
392315333Serj	u32 i, command;
393315333Serj	UNREFERENCED_1PARAMETER(dev_type);
394315333Serj
395315333Serj	/* Put the data in the MDI single read and write data register*/
396315333Serj	IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
397315333Serj
398315333Serj	/* Setup and write the write command */
399315333Serj	command = (reg_addr << IXGBE_MSCA_DEV_TYPE_SHIFT) |
400315333Serj		  (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
401315333Serj		  IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE |
402315333Serj		  IXGBE_MSCA_MDI_COMMAND;
403315333Serj
404315333Serj	IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
405315333Serj
406315333Serj	/* Check every 10 usec to see if the access completed.
407315333Serj	 * The MDI Command bit will clear when the operation is
408315333Serj	 * complete
409315333Serj	 */
410315333Serj	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
411315333Serj		usec_delay(10);
412315333Serj
413315333Serj		command = IXGBE_READ_REG(hw, IXGBE_MSCA);
414315333Serj		if (!(command & IXGBE_MSCA_MDI_COMMAND))
415315333Serj			break;
416315333Serj	}
417315333Serj
418315333Serj	if (command & IXGBE_MSCA_MDI_COMMAND) {
419315333Serj		ERROR_REPORT1(IXGBE_ERROR_POLLING,
420315333Serj			      "PHY write cmd didn't complete\n");
421315333Serj		return IXGBE_ERR_PHY;
422315333Serj	}
423315333Serj
424315333Serj	return IXGBE_SUCCESS;
425315333Serj}
426315333Serj
427315333Serj/**
428282289Serj * ixgbe_identify_phy_x550em - Get PHY type based on device id
429282289Serj * @hw: pointer to hardware structure
430282289Serj *
431282289Serj * Returns error code
432282289Serj */
433282289Serjstatic s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
434282289Serj{
435315333Serj	hw->mac.ops.set_lan_id(hw);
436315333Serj
437315333Serj	ixgbe_read_mng_if_sel_x550em(hw);
438315333Serj
439282289Serj	switch (hw->device_id) {
440315333Serj	case IXGBE_DEV_ID_X550EM_A_SFP:
441315333Serj		return ixgbe_identify_module_generic(hw);
442282289Serj	case IXGBE_DEV_ID_X550EM_X_SFP:
443282289Serj		/* set up for CS4227 usage */
444282289Serj		ixgbe_setup_mux_ctl(hw);
445282289Serj		ixgbe_check_cs4227(hw);
446315333Serj		/* Fallthrough */
447282289Serj
448315333Serj	case IXGBE_DEV_ID_X550EM_A_SFP_N:
449282289Serj		return ixgbe_identify_module_generic(hw);
450282289Serj		break;
451282289Serj	case IXGBE_DEV_ID_X550EM_X_KX4:
452282289Serj		hw->phy.type = ixgbe_phy_x550em_kx4;
453282289Serj		break;
454315333Serj	case IXGBE_DEV_ID_X550EM_X_XFI:
455315333Serj		hw->phy.type = ixgbe_phy_x550em_xfi;
456315333Serj		break;
457282289Serj	case IXGBE_DEV_ID_X550EM_X_KR:
458315333Serj	case IXGBE_DEV_ID_X550EM_A_KR:
459315333Serj	case IXGBE_DEV_ID_X550EM_A_KR_L:
460282289Serj		hw->phy.type = ixgbe_phy_x550em_kr;
461282289Serj		break;
462315333Serj	case IXGBE_DEV_ID_X550EM_A_10G_T:
463282289Serj	case IXGBE_DEV_ID_X550EM_X_1G_T:
464282289Serj	case IXGBE_DEV_ID_X550EM_X_10G_T:
465282289Serj		return ixgbe_identify_phy_generic(hw);
466315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T:
467315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
468315333Serj		hw->phy.type = ixgbe_phy_fw;
469315333Serj		hw->phy.ops.read_reg = NULL;
470315333Serj		hw->phy.ops.write_reg = NULL;
471315333Serj		if (hw->bus.lan_id)
472315333Serj			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
473315333Serj		else
474315333Serj			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
475315333Serj		break;
476282289Serj	default:
477282289Serj		break;
478282289Serj	}
479282289Serj	return IXGBE_SUCCESS;
480282289Serj}
481282289Serj
482315333Serj/**
483315333Serj * ixgbe_fw_phy_activity - Perform an activity on a PHY
484315333Serj * @hw: pointer to hardware structure
485315333Serj * @activity: activity to perform
486315333Serj * @data: Pointer to 4 32-bit words of data
487315333Serj */
488315333Serjs32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity,
489315333Serj			  u32 (*data)[FW_PHY_ACT_DATA_COUNT])
490315333Serj{
491315333Serj	union {
492315333Serj		struct ixgbe_hic_phy_activity_req cmd;
493315333Serj		struct ixgbe_hic_phy_activity_resp rsp;
494315333Serj	} hic;
495315333Serj	u16 retries = FW_PHY_ACT_RETRIES;
496315333Serj	s32 rc;
497315333Serj	u16 i;
498315333Serj
499315333Serj	do {
500315333Serj		memset(&hic, 0, sizeof(hic));
501315333Serj		hic.cmd.hdr.cmd = FW_PHY_ACT_REQ_CMD;
502315333Serj		hic.cmd.hdr.buf_len = FW_PHY_ACT_REQ_LEN;
503315333Serj		hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
504315333Serj		hic.cmd.port_number = hw->bus.lan_id;
505315333Serj		hic.cmd.activity_id = IXGBE_CPU_TO_LE16(activity);
506315333Serj		for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i)
507315333Serj			hic.cmd.data[i] = IXGBE_CPU_TO_BE32((*data)[i]);
508315333Serj
509315333Serj		rc = ixgbe_host_interface_command(hw, (u32 *)&hic.cmd,
510315333Serj						  sizeof(hic.cmd),
511315333Serj						  IXGBE_HI_COMMAND_TIMEOUT,
512315333Serj						  TRUE);
513315333Serj		if (rc != IXGBE_SUCCESS)
514315333Serj			return rc;
515315333Serj		if (hic.rsp.hdr.cmd_or_resp.ret_status ==
516315333Serj		    FW_CEM_RESP_STATUS_SUCCESS) {
517315333Serj			for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i)
518315333Serj				(*data)[i] = IXGBE_BE32_TO_CPU(hic.rsp.data[i]);
519315333Serj			return IXGBE_SUCCESS;
520315333Serj		}
521315333Serj		usec_delay(20);
522315333Serj		--retries;
523315333Serj	} while (retries > 0);
524315333Serj
525315333Serj	return IXGBE_ERR_HOST_INTERFACE_COMMAND;
526315333Serj}
527315333Serj
528315333Serjstatic const struct {
529315333Serj	u16 fw_speed;
530315333Serj	ixgbe_link_speed phy_speed;
531315333Serj} ixgbe_fw_map[] = {
532315333Serj	{ FW_PHY_ACT_LINK_SPEED_10, IXGBE_LINK_SPEED_10_FULL },
533315333Serj	{ FW_PHY_ACT_LINK_SPEED_100, IXGBE_LINK_SPEED_100_FULL },
534315333Serj	{ FW_PHY_ACT_LINK_SPEED_1G, IXGBE_LINK_SPEED_1GB_FULL },
535315333Serj	{ FW_PHY_ACT_LINK_SPEED_2_5G, IXGBE_LINK_SPEED_2_5GB_FULL },
536315333Serj	{ FW_PHY_ACT_LINK_SPEED_5G, IXGBE_LINK_SPEED_5GB_FULL },
537315333Serj	{ FW_PHY_ACT_LINK_SPEED_10G, IXGBE_LINK_SPEED_10GB_FULL },
538315333Serj};
539315333Serj
540315333Serj/**
541315333Serj * ixgbe_get_phy_id_fw - Get the phy ID via firmware command
542315333Serj * @hw: pointer to hardware structure
543315333Serj *
544315333Serj * Returns error code
545315333Serj */
546315333Serjstatic s32 ixgbe_get_phy_id_fw(struct ixgbe_hw *hw)
547315333Serj{
548315333Serj	u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 };
549315333Serj	u16 phy_speeds;
550315333Serj	u16 phy_id_lo;
551315333Serj	s32 rc;
552315333Serj	u16 i;
553315333Serj
554315333Serj	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_PHY_INFO, &info);
555315333Serj	if (rc)
556315333Serj		return rc;
557315333Serj
558315333Serj	hw->phy.speeds_supported = 0;
559315333Serj	phy_speeds = info[0] & FW_PHY_INFO_SPEED_MASK;
560315333Serj	for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) {
561315333Serj		if (phy_speeds & ixgbe_fw_map[i].fw_speed)
562315333Serj			hw->phy.speeds_supported |= ixgbe_fw_map[i].phy_speed;
563315333Serj	}
564315333Serj	if (!hw->phy.autoneg_advertised)
565315333Serj		hw->phy.autoneg_advertised = hw->phy.speeds_supported;
566315333Serj
567315333Serj	hw->phy.id = info[0] & FW_PHY_INFO_ID_HI_MASK;
568315333Serj	phy_id_lo = info[1] & FW_PHY_INFO_ID_LO_MASK;
569315333Serj	hw->phy.id |= phy_id_lo & IXGBE_PHY_REVISION_MASK;
570315333Serj	hw->phy.revision = phy_id_lo & ~IXGBE_PHY_REVISION_MASK;
571315333Serj	if (!hw->phy.id || hw->phy.id == IXGBE_PHY_REVISION_MASK)
572315333Serj		return IXGBE_ERR_PHY_ADDR_INVALID;
573315333Serj	return IXGBE_SUCCESS;
574315333Serj}
575315333Serj
576315333Serj/**
577315333Serj * ixgbe_identify_phy_fw - Get PHY type based on firmware command
578315333Serj * @hw: pointer to hardware structure
579315333Serj *
580315333Serj * Returns error code
581315333Serj */
582315333Serjstatic s32 ixgbe_identify_phy_fw(struct ixgbe_hw *hw)
583315333Serj{
584315333Serj	if (hw->bus.lan_id)
585315333Serj		hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM;
586315333Serj	else
587315333Serj		hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM;
588315333Serj
589315333Serj	hw->phy.type = ixgbe_phy_fw;
590315333Serj	hw->phy.ops.read_reg = NULL;
591315333Serj	hw->phy.ops.write_reg = NULL;
592315333Serj	return ixgbe_get_phy_id_fw(hw);
593315333Serj}
594315333Serj
595315333Serj/**
596315333Serj * ixgbe_shutdown_fw_phy - Shutdown a firmware-controlled PHY
597315333Serj * @hw: pointer to hardware structure
598315333Serj *
599315333Serj * Returns error code
600315333Serj */
601315333Serjs32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw)
602315333Serj{
603315333Serj	u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 };
604315333Serj
605315333Serj	setup[0] = FW_PHY_ACT_FORCE_LINK_DOWN_OFF;
606315333Serj	return ixgbe_fw_phy_activity(hw, FW_PHY_ACT_FORCE_LINK_DOWN, &setup);
607315333Serj}
608315333Serj
609282289Serjstatic s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
610282289Serj				     u32 device_type, u16 *phy_data)
611282289Serj{
612282289Serj	UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, *phy_data);
613282289Serj	return IXGBE_NOT_IMPLEMENTED;
614282289Serj}
615282289Serj
616282289Serjstatic s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
617282289Serj				      u32 device_type, u16 phy_data)
618282289Serj{
619282289Serj	UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, phy_data);
620282289Serj	return IXGBE_NOT_IMPLEMENTED;
621282289Serj}
622282289Serj
623282289Serj/**
624315333Serj * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
625315333Serj * @hw: pointer to the hardware structure
626315333Serj * @addr: I2C bus address to read from
627315333Serj * @reg: I2C device register to read from
628315333Serj * @val: pointer to location to receive read value
629315333Serj *
630315333Serj * Returns an error code on error.
631315333Serj **/
632315333Serjstatic s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
633315333Serj					   u16 reg, u16 *val)
634315333Serj{
635315333Serj	return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, TRUE);
636315333Serj}
637315333Serj
638315333Serj/**
639315333Serj * ixgbe_read_i2c_combined_generic_unlocked - Do I2C read combined operation
640315333Serj * @hw: pointer to the hardware structure
641315333Serj * @addr: I2C bus address to read from
642315333Serj * @reg: I2C device register to read from
643315333Serj * @val: pointer to location to receive read value
644315333Serj *
645315333Serj * Returns an error code on error.
646315333Serj **/
647315333Serjstatic s32
648315333Serjixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr,
649315333Serj					 u16 reg, u16 *val)
650315333Serj{
651315333Serj	return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, FALSE);
652315333Serj}
653315333Serj
654315333Serj/**
655315333Serj * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
656315333Serj * @hw: pointer to the hardware structure
657315333Serj * @addr: I2C bus address to write to
658315333Serj * @reg: I2C device register to write to
659315333Serj * @val: value to write
660315333Serj *
661315333Serj * Returns an error code on error.
662315333Serj **/
663315333Serjstatic s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
664315333Serj					    u8 addr, u16 reg, u16 val)
665315333Serj{
666315333Serj	return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, TRUE);
667315333Serj}
668315333Serj
669315333Serj/**
670315333Serj * ixgbe_write_i2c_combined_generic_unlocked - Do I2C write combined operation
671315333Serj * @hw: pointer to the hardware structure
672315333Serj * @addr: I2C bus address to write to
673315333Serj * @reg: I2C device register to write to
674315333Serj * @val: value to write
675315333Serj *
676315333Serj * Returns an error code on error.
677315333Serj **/
678315333Serjstatic s32
679315333Serjixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw,
680315333Serj					  u8 addr, u16 reg, u16 val)
681315333Serj{
682315333Serj	return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, FALSE);
683315333Serj}
684315333Serj
685315333Serj/**
686282289Serj*  ixgbe_init_ops_X550EM - Inits func ptrs and MAC type
687282289Serj*  @hw: pointer to hardware structure
688282289Serj*
689282289Serj*  Initialize the function pointers and for MAC type X550EM.
690282289Serj*  Does not touch the hardware.
691282289Serj**/
692282289Serjs32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw)
693282289Serj{
694282289Serj	struct ixgbe_mac_info *mac = &hw->mac;
695282289Serj	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
696282289Serj	struct ixgbe_phy_info *phy = &hw->phy;
697282289Serj	s32 ret_val;
698282289Serj
699282289Serj	DEBUGFUNC("ixgbe_init_ops_X550EM");
700282289Serj
701282289Serj	/* Similar to X550 so start there. */
702282289Serj	ret_val = ixgbe_init_ops_X550(hw);
703282289Serj
704282289Serj	/* Since this function eventually calls
705282289Serj	 * ixgbe_init_ops_540 by design, we are setting
706282289Serj	 * the pointers to NULL explicitly here to overwrite
707282289Serj	 * the values being set in the x540 function.
708282289Serj	 */
709282289Serj
710315333Serj	/* Bypass not supported in x550EM */
711315333Serj	mac->ops.bypass_rw = NULL;
712315333Serj	mac->ops.bypass_valid_rd = NULL;
713315333Serj	mac->ops.bypass_set = NULL;
714315333Serj	mac->ops.bypass_rd_eep = NULL;
715315333Serj
716282289Serj	/* FCOE not supported in x550EM */
717282289Serj	mac->ops.get_san_mac_addr = NULL;
718282289Serj	mac->ops.set_san_mac_addr = NULL;
719282289Serj	mac->ops.get_wwn_prefix = NULL;
720282289Serj	mac->ops.get_fcoe_boot_status = NULL;
721282289Serj
722282289Serj	/* IPsec not supported in x550EM */
723282289Serj	mac->ops.disable_sec_rx_path = NULL;
724282289Serj	mac->ops.enable_sec_rx_path = NULL;
725282289Serj
726282289Serj	/* AUTOC register is not present in x550EM. */
727282289Serj	mac->ops.prot_autoc_read = NULL;
728282289Serj	mac->ops.prot_autoc_write = NULL;
729282289Serj
730282289Serj	/* X550EM bus type is internal*/
731282289Serj	hw->bus.type = ixgbe_bus_type_internal;
732282289Serj	mac->ops.get_bus_info = ixgbe_get_bus_info_X550em;
733282289Serj
734295524Ssbruno
735282289Serj	mac->ops.get_media_type = ixgbe_get_media_type_X550em;
736282289Serj	mac->ops.setup_sfp = ixgbe_setup_sfp_modules_X550em;
737282289Serj	mac->ops.get_link_capabilities = ixgbe_get_link_capabilities_X550em;
738282289Serj	mac->ops.reset_hw = ixgbe_reset_hw_X550em;
739282289Serj	mac->ops.get_supported_physical_layer =
740282289Serj				    ixgbe_get_supported_physical_layer_X550em;
741282289Serj
742282289Serj	if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
743282289Serj		mac->ops.setup_fc = ixgbe_setup_fc_generic;
744282289Serj	else
745282289Serj		mac->ops.setup_fc = ixgbe_setup_fc_X550em;
746282289Serj
747282289Serj	/* PHY */
748282289Serj	phy->ops.init = ixgbe_init_phy_ops_X550em;
749315333Serj	switch (hw->device_id) {
750315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T:
751315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
752315333Serj		mac->ops.setup_fc = NULL;
753315333Serj		phy->ops.identify = ixgbe_identify_phy_fw;
754315333Serj		phy->ops.set_phy_power = NULL;
755315333Serj		phy->ops.get_firmware_version = NULL;
756315333Serj		break;
757315333Serj	default:
758315333Serj		phy->ops.identify = ixgbe_identify_phy_x550em;
759315333Serj	}
760315333Serj
761282289Serj	if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper)
762282289Serj		phy->ops.set_phy_power = NULL;
763282289Serj
764282289Serj
765282289Serj	/* EEPROM */
766282289Serj	eeprom->ops.init_params = ixgbe_init_eeprom_params_X540;
767282289Serj	eeprom->ops.read = ixgbe_read_ee_hostif_X550;
768282289Serj	eeprom->ops.read_buffer = ixgbe_read_ee_hostif_buffer_X550;
769282289Serj	eeprom->ops.write = ixgbe_write_ee_hostif_X550;
770282289Serj	eeprom->ops.write_buffer = ixgbe_write_ee_hostif_buffer_X550;
771282289Serj	eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550;
772282289Serj	eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550;
773282289Serj	eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550;
774282289Serj
775282289Serj	return ret_val;
776282289Serj}
777282289Serj
778282289Serj/**
779315333Serj * ixgbe_setup_fw_link - Setup firmware-controlled PHYs
780315333Serj * @hw: pointer to hardware structure
781315333Serj */
782315333Serjstatic s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw)
783315333Serj{
784315333Serj	u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 };
785315333Serj	s32 rc;
786315333Serj	u16 i;
787315333Serj
788315333Serj	if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw))
789315333Serj		return 0;
790315333Serj
791315333Serj	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
792315333Serj		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
793315333Serj			      "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
794315333Serj		return IXGBE_ERR_INVALID_LINK_SETTINGS;
795315333Serj	}
796315333Serj
797315333Serj	switch (hw->fc.requested_mode) {
798315333Serj	case ixgbe_fc_full:
799315333Serj		setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RXTX <<
800315333Serj			    FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT;
801315333Serj		break;
802315333Serj	case ixgbe_fc_rx_pause:
803315333Serj		setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RX <<
804315333Serj			    FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT;
805315333Serj		break;
806315333Serj	case ixgbe_fc_tx_pause:
807315333Serj		setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_TX <<
808315333Serj			    FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT;
809315333Serj		break;
810315333Serj	default:
811315333Serj		break;
812315333Serj	}
813315333Serj
814315333Serj	for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) {
815315333Serj		if (hw->phy.autoneg_advertised & ixgbe_fw_map[i].phy_speed)
816315333Serj			setup[0] |= ixgbe_fw_map[i].fw_speed;
817315333Serj	}
818315333Serj	setup[0] |= FW_PHY_ACT_SETUP_LINK_HP | FW_PHY_ACT_SETUP_LINK_AN;
819315333Serj
820315333Serj	if (hw->phy.eee_speeds_advertised)
821315333Serj		setup[0] |= FW_PHY_ACT_SETUP_LINK_EEE;
822315333Serj
823315333Serj	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup);
824315333Serj	if (rc)
825315333Serj		return rc;
826315333Serj	if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN)
827315333Serj		return IXGBE_ERR_OVERTEMP;
828315333Serj	return IXGBE_SUCCESS;
829315333Serj}
830315333Serj
831315333Serj/**
832315333Serj * ixgbe_fc_autoneg_fw _ Set up flow control for FW-controlled PHYs
833315333Serj * @hw: pointer to hardware structure
834315333Serj *
835315333Serj *  Called at init time to set up flow control.
836315333Serj */
837315333Serjstatic s32 ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw)
838315333Serj{
839315333Serj	if (hw->fc.requested_mode == ixgbe_fc_default)
840315333Serj		hw->fc.requested_mode = ixgbe_fc_full;
841315333Serj
842315333Serj	return ixgbe_setup_fw_link(hw);
843315333Serj}
844315333Serj
845315333Serj/**
846315333Serj * ixgbe_setup_eee_fw - Enable/disable EEE support
847315333Serj * @hw: pointer to the HW structure
848315333Serj * @enable_eee: boolean flag to enable EEE
849315333Serj *
850315333Serj * Enable/disable EEE based on enable_eee flag.
851315333Serj * This function controls EEE for firmware-based PHY implementations.
852315333Serj */
853315333Serjstatic s32 ixgbe_setup_eee_fw(struct ixgbe_hw *hw, bool enable_eee)
854315333Serj{
855315333Serj	if (!!hw->phy.eee_speeds_advertised == enable_eee)
856315333Serj		return IXGBE_SUCCESS;
857315333Serj	if (enable_eee)
858315333Serj		hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
859315333Serj	else
860315333Serj		hw->phy.eee_speeds_advertised = 0;
861315333Serj	return hw->phy.ops.setup_link(hw);
862315333Serj}
863315333Serj
864315333Serj/**
865315333Serj*  ixgbe_init_ops_X550EM_a - Inits func ptrs and MAC type
866315333Serj*  @hw: pointer to hardware structure
867315333Serj*
868315333Serj*  Initialize the function pointers and for MAC type X550EM_a.
869315333Serj*  Does not touch the hardware.
870315333Serj**/
871315333Serjs32 ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw)
872315333Serj{
873315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
874315333Serj	s32 ret_val;
875315333Serj
876315333Serj	DEBUGFUNC("ixgbe_init_ops_X550EM_a");
877315333Serj
878315333Serj	/* Start with generic X550EM init */
879315333Serj	ret_val = ixgbe_init_ops_X550EM(hw);
880315333Serj
881315333Serj	if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII ||
882315333Serj	    hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L) {
883315333Serj		mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550;
884315333Serj		mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550;
885315333Serj	} else {
886315333Serj		mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550a;
887315333Serj		mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550a;
888315333Serj	}
889315333Serj	mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550a;
890315333Serj	mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550a;
891315333Serj
892315333Serj	switch (mac->ops.get_media_type(hw)) {
893315333Serj	case ixgbe_media_type_fiber:
894315333Serj		mac->ops.setup_fc = NULL;
895315333Serj		mac->ops.fc_autoneg = ixgbe_fc_autoneg_fiber_x550em_a;
896315333Serj		break;
897315333Serj	case ixgbe_media_type_backplane:
898315333Serj		mac->ops.fc_autoneg = ixgbe_fc_autoneg_backplane_x550em_a;
899315333Serj		mac->ops.setup_fc = ixgbe_setup_fc_backplane_x550em_a;
900315333Serj		break;
901315333Serj	default:
902315333Serj		break;
903315333Serj	}
904315333Serj
905315333Serj	switch (hw->device_id) {
906315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T:
907315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
908315333Serj		mac->ops.fc_autoneg = ixgbe_fc_autoneg_sgmii_x550em_a;
909315333Serj		mac->ops.setup_fc = ixgbe_fc_autoneg_fw;
910315333Serj		mac->ops.setup_eee = ixgbe_setup_eee_fw;
911315333Serj		hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_100_FULL |
912315333Serj					       IXGBE_LINK_SPEED_1GB_FULL;
913315333Serj		hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
914315333Serj		break;
915315333Serj	default:
916315333Serj		break;
917315333Serj	}
918315333Serj
919315333Serj	return ret_val;
920315333Serj}
921315333Serj
922315333Serj/**
923315333Serj*  ixgbe_init_ops_X550EM_x - Inits func ptrs and MAC type
924315333Serj*  @hw: pointer to hardware structure
925315333Serj*
926315333Serj*  Initialize the function pointers and for MAC type X550EM_x.
927315333Serj*  Does not touch the hardware.
928315333Serj**/
929315333Serjs32 ixgbe_init_ops_X550EM_x(struct ixgbe_hw *hw)
930315333Serj{
931315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
932315333Serj	struct ixgbe_link_info *link = &hw->link;
933315333Serj	s32 ret_val;
934315333Serj
935315333Serj	DEBUGFUNC("ixgbe_init_ops_X550EM_x");
936315333Serj
937315333Serj	/* Start with generic X550EM init */
938315333Serj	ret_val = ixgbe_init_ops_X550EM(hw);
939315333Serj
940315333Serj	mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550;
941315333Serj	mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550;
942315333Serj	mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em;
943315333Serj	mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em;
944315333Serj	link->ops.read_link = ixgbe_read_i2c_combined_generic;
945315333Serj	link->ops.read_link_unlocked = ixgbe_read_i2c_combined_generic_unlocked;
946315333Serj	link->ops.write_link = ixgbe_write_i2c_combined_generic;
947315333Serj	link->ops.write_link_unlocked =
948315333Serj				      ixgbe_write_i2c_combined_generic_unlocked;
949315333Serj	link->addr = IXGBE_CS4227;
950315333Serj
951315333Serj
952315333Serj	return ret_val;
953315333Serj}
954315333Serj
955315333Serj/**
956282289Serj *  ixgbe_dmac_config_X550
957282289Serj *  @hw: pointer to hardware structure
958282289Serj *
959282289Serj *  Configure DMA coalescing. If enabling dmac, dmac is activated.
960282289Serj *  When disabling dmac, dmac enable dmac bit is cleared.
961282289Serj **/
962282289Serjs32 ixgbe_dmac_config_X550(struct ixgbe_hw *hw)
963282289Serj{
964282289Serj	u32 reg, high_pri_tc;
965282289Serj
966282289Serj	DEBUGFUNC("ixgbe_dmac_config_X550");
967282289Serj
968282289Serj	/* Disable DMA coalescing before configuring */
969282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
970282289Serj	reg &= ~IXGBE_DMACR_DMAC_EN;
971282289Serj	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
972282289Serj
973282289Serj	/* Disable DMA Coalescing if the watchdog timer is 0 */
974282289Serj	if (!hw->mac.dmac_config.watchdog_timer)
975282289Serj		goto out;
976282289Serj
977282289Serj	ixgbe_dmac_config_tcs_X550(hw);
978282289Serj
979282289Serj	/* Configure DMA Coalescing Control Register */
980282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
981282289Serj
982282289Serj	/* Set the watchdog timer in units of 40.96 usec */
983282289Serj	reg &= ~IXGBE_DMACR_DMACWT_MASK;
984282289Serj	reg |= (hw->mac.dmac_config.watchdog_timer * 100) / 4096;
985282289Serj
986282289Serj	reg &= ~IXGBE_DMACR_HIGH_PRI_TC_MASK;
987282289Serj	/* If fcoe is enabled, set high priority traffic class */
988282289Serj	if (hw->mac.dmac_config.fcoe_en) {
989282289Serj		high_pri_tc = 1 << hw->mac.dmac_config.fcoe_tc;
990282289Serj		reg |= ((high_pri_tc << IXGBE_DMACR_HIGH_PRI_TC_SHIFT) &
991282289Serj			IXGBE_DMACR_HIGH_PRI_TC_MASK);
992282289Serj	}
993282289Serj	reg |= IXGBE_DMACR_EN_MNG_IND;
994282289Serj
995282289Serj	/* Enable DMA coalescing after configuration */
996282289Serj	reg |= IXGBE_DMACR_DMAC_EN;
997282289Serj	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
998282289Serj
999282289Serjout:
1000282289Serj	return IXGBE_SUCCESS;
1001282289Serj}
1002282289Serj
1003282289Serj/**
1004282289Serj *  ixgbe_dmac_config_tcs_X550
1005282289Serj *  @hw: pointer to hardware structure
1006282289Serj *
1007282289Serj *  Configure DMA coalescing threshold per TC. The dmac enable bit must
1008282289Serj *  be cleared before configuring.
1009282289Serj **/
1010282289Serjs32 ixgbe_dmac_config_tcs_X550(struct ixgbe_hw *hw)
1011282289Serj{
1012282289Serj	u32 tc, reg, pb_headroom, rx_pb_size, maxframe_size_kb;
1013282289Serj
1014282289Serj	DEBUGFUNC("ixgbe_dmac_config_tcs_X550");
1015282289Serj
1016282289Serj	/* Configure DMA coalescing enabled */
1017282289Serj	switch (hw->mac.dmac_config.link_speed) {
1018315333Serj	case IXGBE_LINK_SPEED_10_FULL:
1019282289Serj	case IXGBE_LINK_SPEED_100_FULL:
1020282289Serj		pb_headroom = IXGBE_DMACRXT_100M;
1021282289Serj		break;
1022282289Serj	case IXGBE_LINK_SPEED_1GB_FULL:
1023282289Serj		pb_headroom = IXGBE_DMACRXT_1G;
1024282289Serj		break;
1025282289Serj	default:
1026282289Serj		pb_headroom = IXGBE_DMACRXT_10G;
1027282289Serj		break;
1028282289Serj	}
1029282289Serj
1030282289Serj	maxframe_size_kb = ((IXGBE_READ_REG(hw, IXGBE_MAXFRS) >>
1031282289Serj			     IXGBE_MHADD_MFS_SHIFT) / 1024);
1032282289Serj
1033282289Serj	/* Set the per Rx packet buffer receive threshold */
1034282289Serj	for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) {
1035282289Serj		reg = IXGBE_READ_REG(hw, IXGBE_DMCTH(tc));
1036282289Serj		reg &= ~IXGBE_DMCTH_DMACRXT_MASK;
1037282289Serj
1038282289Serj		if (tc < hw->mac.dmac_config.num_tcs) {
1039282289Serj			/* Get Rx PB size */
1040282289Serj			rx_pb_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(tc));
1041282289Serj			rx_pb_size = (rx_pb_size & IXGBE_RXPBSIZE_MASK) >>
1042282289Serj				IXGBE_RXPBSIZE_SHIFT;
1043282289Serj
1044282289Serj			/* Calculate receive buffer threshold in kilobytes */
1045282289Serj			if (rx_pb_size > pb_headroom)
1046282289Serj				rx_pb_size = rx_pb_size - pb_headroom;
1047282289Serj			else
1048282289Serj				rx_pb_size = 0;
1049282289Serj
1050282289Serj			/* Minimum of MFS shall be set for DMCTH */
1051282289Serj			reg |= (rx_pb_size > maxframe_size_kb) ?
1052282289Serj				rx_pb_size : maxframe_size_kb;
1053282289Serj		}
1054282289Serj		IXGBE_WRITE_REG(hw, IXGBE_DMCTH(tc), reg);
1055282289Serj	}
1056282289Serj	return IXGBE_SUCCESS;
1057282289Serj}
1058282289Serj
1059282289Serj/**
1060282289Serj *  ixgbe_dmac_update_tcs_X550
1061282289Serj *  @hw: pointer to hardware structure
1062282289Serj *
1063282289Serj *  Disables dmac, updates per TC settings, and then enables dmac.
1064282289Serj **/
1065282289Serjs32 ixgbe_dmac_update_tcs_X550(struct ixgbe_hw *hw)
1066282289Serj{
1067282289Serj	u32 reg;
1068282289Serj
1069282289Serj	DEBUGFUNC("ixgbe_dmac_update_tcs_X550");
1070282289Serj
1071282289Serj	/* Disable DMA coalescing before configuring */
1072282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
1073282289Serj	reg &= ~IXGBE_DMACR_DMAC_EN;
1074282289Serj	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
1075282289Serj
1076282289Serj	ixgbe_dmac_config_tcs_X550(hw);
1077282289Serj
1078282289Serj	/* Enable DMA coalescing after configuration */
1079282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
1080282289Serj	reg |= IXGBE_DMACR_DMAC_EN;
1081282289Serj	IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
1082282289Serj
1083282289Serj	return IXGBE_SUCCESS;
1084282289Serj}
1085282289Serj
1086282289Serj/**
1087282289Serj *  ixgbe_init_eeprom_params_X550 - Initialize EEPROM params
1088282289Serj *  @hw: pointer to hardware structure
1089282289Serj *
1090282289Serj *  Initializes the EEPROM parameters ixgbe_eeprom_info within the
1091282289Serj *  ixgbe_hw struct in order to set up EEPROM access.
1092282289Serj **/
1093282289Serjs32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
1094282289Serj{
1095282289Serj	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
1096282289Serj	u32 eec;
1097282289Serj	u16 eeprom_size;
1098282289Serj
1099282289Serj	DEBUGFUNC("ixgbe_init_eeprom_params_X550");
1100282289Serj
1101282289Serj	if (eeprom->type == ixgbe_eeprom_uninitialized) {
1102282289Serj		eeprom->semaphore_delay = 10;
1103282289Serj		eeprom->type = ixgbe_flash;
1104282289Serj
1105282289Serj		eec = IXGBE_READ_REG(hw, IXGBE_EEC);
1106282289Serj		eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
1107282289Serj				    IXGBE_EEC_SIZE_SHIFT);
1108282289Serj		eeprom->word_size = 1 << (eeprom_size +
1109282289Serj					  IXGBE_EEPROM_WORD_SIZE_SHIFT);
1110282289Serj
1111282289Serj		DEBUGOUT2("Eeprom params: type = %d, size = %d\n",
1112282289Serj			  eeprom->type, eeprom->word_size);
1113282289Serj	}
1114282289Serj
1115282289Serj	return IXGBE_SUCCESS;
1116282289Serj}
1117282289Serj
1118282289Serj/**
1119282289Serj * ixgbe_set_source_address_pruning_X550 - Enable/Disbale source address pruning
1120282289Serj * @hw: pointer to hardware structure
1121282289Serj * @enable: enable or disable source address pruning
1122282289Serj * @pool: Rx pool to set source address pruning for
1123282289Serj **/
1124282289Serjvoid ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable,
1125282289Serj					   unsigned int pool)
1126282289Serj{
1127282289Serj	u64 pfflp;
1128282289Serj
1129282289Serj	/* max rx pool is 63 */
1130282289Serj	if (pool > 63)
1131282289Serj		return;
1132282289Serj
1133282289Serj	pfflp = (u64)IXGBE_READ_REG(hw, IXGBE_PFFLPL);
1134282289Serj	pfflp |= (u64)IXGBE_READ_REG(hw, IXGBE_PFFLPH) << 32;
1135282289Serj
1136282289Serj	if (enable)
1137282289Serj		pfflp |= (1ULL << pool);
1138282289Serj	else
1139282289Serj		pfflp &= ~(1ULL << pool);
1140282289Serj
1141282289Serj	IXGBE_WRITE_REG(hw, IXGBE_PFFLPL, (u32)pfflp);
1142282289Serj	IXGBE_WRITE_REG(hw, IXGBE_PFFLPH, (u32)(pfflp >> 32));
1143282289Serj}
1144282289Serj
1145282289Serj/**
1146282289Serj *  ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype anti-spoofing
1147282289Serj *  @hw: pointer to hardware structure
1148282289Serj *  @enable: enable or disable switch for Ethertype anti-spoofing
1149282289Serj *  @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing
1150282289Serj *
1151282289Serj **/
1152282289Serjvoid ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw,
1153282289Serj		bool enable, int vf)
1154282289Serj{
1155282289Serj	int vf_target_reg = vf >> 3;
1156282289Serj	int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT;
1157282289Serj	u32 pfvfspoof;
1158282289Serj
1159282289Serj	DEBUGFUNC("ixgbe_set_ethertype_anti_spoofing_X550");
1160282289Serj
1161282289Serj	pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg));
1162282289Serj	if (enable)
1163282289Serj		pfvfspoof |= (1 << vf_target_shift);
1164282289Serj	else
1165282289Serj		pfvfspoof &= ~(1 << vf_target_shift);
1166282289Serj
1167282289Serj	IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
1168282289Serj}
1169282289Serj
1170282289Serj/**
1171282289Serj * ixgbe_iosf_wait - Wait for IOSF command completion
1172282289Serj * @hw: pointer to hardware structure
1173282289Serj * @ctrl: pointer to location to receive final IOSF control value
1174282289Serj *
1175282289Serj * Returns failing status on timeout
1176282289Serj *
1177282289Serj * Note: ctrl can be NULL if the IOSF control register value is not needed
1178282289Serj **/
1179282289Serjstatic s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl)
1180282289Serj{
1181295524Ssbruno	u32 i, command = 0;
1182282289Serj
1183282289Serj	/* Check every 10 usec to see if the address cycle completed.
1184282289Serj	 * The SB IOSF BUSY bit will clear when the operation is
1185282289Serj	 * complete
1186282289Serj	 */
1187282289Serj	for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
1188282289Serj		command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
1189282289Serj		if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
1190282289Serj			break;
1191282289Serj		usec_delay(10);
1192282289Serj	}
1193282289Serj	if (ctrl)
1194282289Serj		*ctrl = command;
1195282289Serj	if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
1196282289Serj		ERROR_REPORT1(IXGBE_ERROR_POLLING, "Wait timed out\n");
1197282289Serj		return IXGBE_ERR_PHY;
1198282289Serj	}
1199282289Serj
1200282289Serj	return IXGBE_SUCCESS;
1201282289Serj}
1202282289Serj
1203282289Serj/**
1204315333Serj *  ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register
1205315333Serj *  of the IOSF device
1206282289Serj *  @hw: pointer to hardware structure
1207282289Serj *  @reg_addr: 32 bit PHY register to write
1208282289Serj *  @device_type: 3 bit device type
1209282289Serj *  @data: Data to write to the register
1210282289Serj **/
1211282289Serjs32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
1212282289Serj			    u32 device_type, u32 data)
1213282289Serj{
1214282289Serj	u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
1215282289Serj	u32 command, error;
1216282289Serj	s32 ret;
1217282289Serj
1218282289Serj	ret = ixgbe_acquire_swfw_semaphore(hw, gssr);
1219282289Serj	if (ret != IXGBE_SUCCESS)
1220282289Serj		return ret;
1221282289Serj
1222282289Serj	ret = ixgbe_iosf_wait(hw, NULL);
1223282289Serj	if (ret != IXGBE_SUCCESS)
1224282289Serj		goto out;
1225282289Serj
1226282289Serj	command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
1227282289Serj		   (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
1228282289Serj
1229282289Serj	/* Write IOSF control register */
1230282289Serj	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
1231282289Serj
1232282289Serj	/* Write IOSF data register */
1233282289Serj	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data);
1234282289Serj
1235282289Serj	ret = ixgbe_iosf_wait(hw, &command);
1236282289Serj
1237282289Serj	if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
1238282289Serj		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
1239282289Serj			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
1240282289Serj		ERROR_REPORT2(IXGBE_ERROR_POLLING,
1241282289Serj			      "Failed to write, error %x\n", error);
1242282289Serj		ret = IXGBE_ERR_PHY;
1243282289Serj	}
1244282289Serj
1245282289Serjout:
1246282289Serj	ixgbe_release_swfw_semaphore(hw, gssr);
1247282289Serj	return ret;
1248282289Serj}
1249282289Serj
1250282289Serj/**
1251315333Serj *  ixgbe_read_iosf_sb_reg_x550 - Reads specified register of the IOSF device
1252282289Serj *  @hw: pointer to hardware structure
1253282289Serj *  @reg_addr: 32 bit PHY register to write
1254282289Serj *  @device_type: 3 bit device type
1255315333Serj *  @data: Pointer to read data from the register
1256282289Serj **/
1257282289Serjs32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
1258282289Serj			   u32 device_type, u32 *data)
1259282289Serj{
1260282289Serj	u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
1261282289Serj	u32 command, error;
1262282289Serj	s32 ret;
1263282289Serj
1264282289Serj	ret = ixgbe_acquire_swfw_semaphore(hw, gssr);
1265282289Serj	if (ret != IXGBE_SUCCESS)
1266282289Serj		return ret;
1267282289Serj
1268282289Serj	ret = ixgbe_iosf_wait(hw, NULL);
1269282289Serj	if (ret != IXGBE_SUCCESS)
1270282289Serj		goto out;
1271282289Serj
1272282289Serj	command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
1273282289Serj		   (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
1274282289Serj
1275282289Serj	/* Write IOSF control register */
1276282289Serj	IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
1277282289Serj
1278282289Serj	ret = ixgbe_iosf_wait(hw, &command);
1279282289Serj
1280282289Serj	if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
1281282289Serj		error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
1282282289Serj			 IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
1283282289Serj		ERROR_REPORT2(IXGBE_ERROR_POLLING,
1284282289Serj				"Failed to read, error %x\n", error);
1285282289Serj		ret = IXGBE_ERR_PHY;
1286282289Serj	}
1287282289Serj
1288282289Serj	if (ret == IXGBE_SUCCESS)
1289282289Serj		*data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA);
1290282289Serj
1291282289Serjout:
1292282289Serj	ixgbe_release_swfw_semaphore(hw, gssr);
1293282289Serj	return ret;
1294282289Serj}
1295282289Serj
1296282289Serj/**
1297315333Serj * ixgbe_get_phy_token - Get the token for shared phy access
1298315333Serj * @hw: Pointer to hardware structure
1299315333Serj */
1300315333Serj
1301315333Serjs32 ixgbe_get_phy_token(struct ixgbe_hw *hw)
1302315333Serj{
1303315333Serj	struct ixgbe_hic_phy_token_req token_cmd;
1304315333Serj	s32 status;
1305315333Serj
1306315333Serj	token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD;
1307315333Serj	token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN;
1308315333Serj	token_cmd.hdr.cmd_or_resp.cmd_resv = 0;
1309315333Serj	token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1310315333Serj	token_cmd.port_number = hw->bus.lan_id;
1311315333Serj	token_cmd.command_type = FW_PHY_TOKEN_REQ;
1312315333Serj	token_cmd.pad = 0;
1313315333Serj	status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd,
1314315333Serj					      sizeof(token_cmd),
1315315333Serj					      IXGBE_HI_COMMAND_TIMEOUT,
1316315333Serj					      TRUE);
1317315333Serj	if (status) {
1318315333Serj		DEBUGOUT1("Issuing host interface command failed with Status = %d\n",
1319315333Serj			  status);
1320315333Serj		return status;
1321315333Serj	}
1322315333Serj	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
1323315333Serj		return IXGBE_SUCCESS;
1324315333Serj	if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY) {
1325315333Serj		DEBUGOUT1("Host interface command returned 0x%08x , returning IXGBE_ERR_FW_RESP_INVALID\n",
1326315333Serj			  token_cmd.hdr.cmd_or_resp.ret_status);
1327315333Serj		return IXGBE_ERR_FW_RESP_INVALID;
1328315333Serj	}
1329315333Serj
1330315333Serj	DEBUGOUT("Returning  IXGBE_ERR_TOKEN_RETRY\n");
1331315333Serj	return IXGBE_ERR_TOKEN_RETRY;
1332315333Serj}
1333315333Serj
1334315333Serj/**
1335315333Serj * ixgbe_put_phy_token - Put the token for shared phy access
1336315333Serj * @hw: Pointer to hardware structure
1337315333Serj */
1338315333Serj
1339315333Serjs32 ixgbe_put_phy_token(struct ixgbe_hw *hw)
1340315333Serj{
1341315333Serj	struct ixgbe_hic_phy_token_req token_cmd;
1342315333Serj	s32 status;
1343315333Serj
1344315333Serj	token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD;
1345315333Serj	token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN;
1346315333Serj	token_cmd.hdr.cmd_or_resp.cmd_resv = 0;
1347315333Serj	token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1348315333Serj	token_cmd.port_number = hw->bus.lan_id;
1349315333Serj	token_cmd.command_type = FW_PHY_TOKEN_REL;
1350315333Serj	token_cmd.pad = 0;
1351315333Serj	status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd,
1352315333Serj					      sizeof(token_cmd),
1353315333Serj					      IXGBE_HI_COMMAND_TIMEOUT,
1354315333Serj					      TRUE);
1355315333Serj	if (status)
1356315333Serj		return status;
1357315333Serj	if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
1358315333Serj		return IXGBE_SUCCESS;
1359315333Serj
1360315333Serj	DEBUGOUT("Put PHY Token host interface command failed");
1361315333Serj	return IXGBE_ERR_FW_RESP_INVALID;
1362315333Serj}
1363315333Serj
1364315333Serj/**
1365315333Serj *  ixgbe_write_iosf_sb_reg_x550a - Writes a value to specified register
1366315333Serj *  of the IOSF device
1367315333Serj *  @hw: pointer to hardware structure
1368315333Serj *  @reg_addr: 32 bit PHY register to write
1369315333Serj *  @device_type: 3 bit device type
1370315333Serj *  @data: Data to write to the register
1371315333Serj **/
1372315333Serjs32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
1373315333Serj				  u32 device_type, u32 data)
1374315333Serj{
1375315333Serj	struct ixgbe_hic_internal_phy_req write_cmd;
1376315333Serj	s32 status;
1377315333Serj	UNREFERENCED_1PARAMETER(device_type);
1378315333Serj
1379315333Serj	memset(&write_cmd, 0, sizeof(write_cmd));
1380315333Serj	write_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD;
1381315333Serj	write_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN;
1382315333Serj	write_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1383315333Serj	write_cmd.port_number = hw->bus.lan_id;
1384315333Serj	write_cmd.command_type = FW_INT_PHY_REQ_WRITE;
1385315333Serj	write_cmd.address = IXGBE_CPU_TO_BE16(reg_addr);
1386315333Serj	write_cmd.write_data = IXGBE_CPU_TO_BE32(data);
1387315333Serj
1388315333Serj	status = ixgbe_host_interface_command(hw, (u32 *)&write_cmd,
1389315333Serj					      sizeof(write_cmd),
1390315333Serj					      IXGBE_HI_COMMAND_TIMEOUT, FALSE);
1391315333Serj
1392315333Serj	return status;
1393315333Serj}
1394315333Serj
1395315333Serj/**
1396315333Serj *  ixgbe_read_iosf_sb_reg_x550a - Reads specified register of the IOSF device
1397315333Serj *  @hw: pointer to hardware structure
1398315333Serj *  @reg_addr: 32 bit PHY register to write
1399315333Serj *  @device_type: 3 bit device type
1400315333Serj *  @data: Pointer to read data from the register
1401315333Serj **/
1402315333Serjs32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
1403315333Serj				 u32 device_type, u32 *data)
1404315333Serj{
1405315333Serj	union {
1406315333Serj		struct ixgbe_hic_internal_phy_req cmd;
1407315333Serj		struct ixgbe_hic_internal_phy_resp rsp;
1408315333Serj	} hic;
1409315333Serj	s32 status;
1410315333Serj	UNREFERENCED_1PARAMETER(device_type);
1411315333Serj
1412315333Serj	memset(&hic, 0, sizeof(hic));
1413315333Serj	hic.cmd.hdr.cmd = FW_INT_PHY_REQ_CMD;
1414315333Serj	hic.cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN;
1415315333Serj	hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
1416315333Serj	hic.cmd.port_number = hw->bus.lan_id;
1417315333Serj	hic.cmd.command_type = FW_INT_PHY_REQ_READ;
1418315333Serj	hic.cmd.address = IXGBE_CPU_TO_BE16(reg_addr);
1419315333Serj
1420315333Serj	status = ixgbe_host_interface_command(hw, (u32 *)&hic.cmd,
1421315333Serj					      sizeof(hic.cmd),
1422315333Serj					      IXGBE_HI_COMMAND_TIMEOUT, TRUE);
1423315333Serj
1424315333Serj	/* Extract the register value from the response. */
1425315333Serj	*data = IXGBE_BE32_TO_CPU(hic.rsp.read_data);
1426315333Serj
1427315333Serj	return status;
1428315333Serj}
1429315333Serj
1430315333Serj/**
1431282289Serj *  ixgbe_disable_mdd_X550
1432282289Serj *  @hw: pointer to hardware structure
1433282289Serj *
1434282289Serj *  Disable malicious driver detection
1435282289Serj **/
1436282289Serjvoid ixgbe_disable_mdd_X550(struct ixgbe_hw *hw)
1437282289Serj{
1438282289Serj	u32 reg;
1439282289Serj
1440282289Serj	DEBUGFUNC("ixgbe_disable_mdd_X550");
1441282289Serj
1442282289Serj	/* Disable MDD for TX DMA and interrupt */
1443282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
1444282289Serj	reg &= ~(IXGBE_DMATXCTL_MDP_EN | IXGBE_DMATXCTL_MBINTEN);
1445282289Serj	IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg);
1446282289Serj
1447282289Serj	/* Disable MDD for RX and interrupt */
1448282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
1449282289Serj	reg &= ~(IXGBE_RDRXCTL_MDP_EN | IXGBE_RDRXCTL_MBINTEN);
1450282289Serj	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg);
1451282289Serj}
1452282289Serj
1453282289Serj/**
1454282289Serj *  ixgbe_enable_mdd_X550
1455282289Serj *  @hw: pointer to hardware structure
1456282289Serj *
1457282289Serj *  Enable malicious driver detection
1458282289Serj **/
1459282289Serjvoid ixgbe_enable_mdd_X550(struct ixgbe_hw *hw)
1460282289Serj{
1461282289Serj	u32 reg;
1462282289Serj
1463282289Serj	DEBUGFUNC("ixgbe_enable_mdd_X550");
1464282289Serj
1465282289Serj	/* Enable MDD for TX DMA and interrupt */
1466282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
1467282289Serj	reg |= (IXGBE_DMATXCTL_MDP_EN | IXGBE_DMATXCTL_MBINTEN);
1468282289Serj	IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg);
1469282289Serj
1470282289Serj	/* Enable MDD for RX and interrupt */
1471282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
1472282289Serj	reg |= (IXGBE_RDRXCTL_MDP_EN | IXGBE_RDRXCTL_MBINTEN);
1473282289Serj	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg);
1474282289Serj}
1475282289Serj
1476282289Serj/**
1477282289Serj *  ixgbe_restore_mdd_vf_X550
1478282289Serj *  @hw: pointer to hardware structure
1479282289Serj *  @vf: vf index
1480282289Serj *
1481282289Serj *  Restore VF that was disabled during malicious driver detection event
1482282289Serj **/
1483282289Serjvoid ixgbe_restore_mdd_vf_X550(struct ixgbe_hw *hw, u32 vf)
1484282289Serj{
1485282289Serj	u32 idx, reg, num_qs, start_q, bitmask;
1486282289Serj
1487282289Serj	DEBUGFUNC("ixgbe_restore_mdd_vf_X550");
1488282289Serj
1489282289Serj	/* Map VF to queues */
1490282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_MRQC);
1491282289Serj	switch (reg & IXGBE_MRQC_MRQE_MASK) {
1492282289Serj	case IXGBE_MRQC_VMDQRT8TCEN:
1493282289Serj		num_qs = 8;  /* 16 VFs / pools */
1494282289Serj		bitmask = 0x000000FF;
1495282289Serj		break;
1496282289Serj	case IXGBE_MRQC_VMDQRSS32EN:
1497282289Serj	case IXGBE_MRQC_VMDQRT4TCEN:
1498282289Serj		num_qs = 4;  /* 32 VFs / pools */
1499282289Serj		bitmask = 0x0000000F;
1500282289Serj		break;
1501315333Serj	default:            /* 64 VFs / pools */
1502282289Serj		num_qs = 2;
1503282289Serj		bitmask = 0x00000003;
1504282289Serj		break;
1505282289Serj	}
1506282289Serj	start_q = vf * num_qs;
1507282289Serj
1508282289Serj	/* Release vf's queues by clearing WQBR_TX and WQBR_RX (RW1C) */
1509282289Serj	idx = start_q / 32;
1510282289Serj	reg = 0;
1511282289Serj	reg |= (bitmask << (start_q % 32));
1512282289Serj	IXGBE_WRITE_REG(hw, IXGBE_WQBR_TX(idx), reg);
1513282289Serj	IXGBE_WRITE_REG(hw, IXGBE_WQBR_RX(idx), reg);
1514282289Serj}
1515282289Serj
1516282289Serj/**
1517282289Serj *  ixgbe_mdd_event_X550
1518282289Serj *  @hw: pointer to hardware structure
1519282289Serj *  @vf_bitmap: vf bitmap of malicious vfs
1520282289Serj *
1521282289Serj *  Handle malicious driver detection event.
1522282289Serj **/
1523282289Serjvoid ixgbe_mdd_event_X550(struct ixgbe_hw *hw, u32 *vf_bitmap)
1524282289Serj{
1525282289Serj	u32 wqbr;
1526282289Serj	u32 i, j, reg, q, shift, vf, idx;
1527282289Serj
1528282289Serj	DEBUGFUNC("ixgbe_mdd_event_X550");
1529282289Serj
1530282289Serj	/* figure out pool size for mapping to vf's */
1531282289Serj	reg = IXGBE_READ_REG(hw, IXGBE_MRQC);
1532282289Serj	switch (reg & IXGBE_MRQC_MRQE_MASK) {
1533282289Serj	case IXGBE_MRQC_VMDQRT8TCEN:
1534282289Serj		shift = 3;  /* 16 VFs / pools */
1535282289Serj		break;
1536282289Serj	case IXGBE_MRQC_VMDQRSS32EN:
1537282289Serj	case IXGBE_MRQC_VMDQRT4TCEN:
1538282289Serj		shift = 2;  /* 32 VFs / pools */
1539282289Serj		break;
1540282289Serj	default:
1541282289Serj		shift = 1;  /* 64 VFs / pools */
1542282289Serj		break;
1543282289Serj	}
1544282289Serj
1545282289Serj	/* Read WQBR_TX and WQBR_RX and check for malicious queues */
1546282289Serj	for (i = 0; i < 4; i++) {
1547282289Serj		wqbr = IXGBE_READ_REG(hw, IXGBE_WQBR_TX(i));
1548282289Serj		wqbr |= IXGBE_READ_REG(hw, IXGBE_WQBR_RX(i));
1549282289Serj
1550282289Serj		if (!wqbr)
1551282289Serj			continue;
1552282289Serj
1553282289Serj		/* Get malicious queue */
1554282289Serj		for (j = 0; j < 32 && wqbr; j++) {
1555282289Serj
1556282289Serj			if (!(wqbr & (1 << j)))
1557282289Serj				continue;
1558282289Serj
1559282289Serj			/* Get queue from bitmask */
1560282289Serj			q = j + (i * 32);
1561282289Serj
1562282289Serj			/* Map queue to vf */
1563282289Serj			vf = (q >> shift);
1564282289Serj
1565282289Serj			/* Set vf bit in vf_bitmap */
1566282289Serj			idx = vf / 32;
1567282289Serj			vf_bitmap[idx] |= (1 << (vf % 32));
1568282289Serj			wqbr &= ~(1 << j);
1569282289Serj		}
1570282289Serj	}
1571282289Serj}
1572282289Serj
1573282289Serj/**
1574282289Serj *  ixgbe_get_media_type_X550em - Get media type
1575282289Serj *  @hw: pointer to hardware structure
1576282289Serj *
1577282289Serj *  Returns the media type (fiber, copper, backplane)
1578282289Serj */
1579282289Serjenum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
1580282289Serj{
1581282289Serj	enum ixgbe_media_type media_type;
1582282289Serj
1583282289Serj	DEBUGFUNC("ixgbe_get_media_type_X550em");
1584282289Serj
1585282289Serj	/* Detect if there is a copper PHY attached. */
1586282289Serj	switch (hw->device_id) {
1587282289Serj	case IXGBE_DEV_ID_X550EM_X_KR:
1588282289Serj	case IXGBE_DEV_ID_X550EM_X_KX4:
1589315333Serj	case IXGBE_DEV_ID_X550EM_X_XFI:
1590315333Serj	case IXGBE_DEV_ID_X550EM_A_KR:
1591315333Serj	case IXGBE_DEV_ID_X550EM_A_KR_L:
1592282289Serj		media_type = ixgbe_media_type_backplane;
1593282289Serj		break;
1594282289Serj	case IXGBE_DEV_ID_X550EM_X_SFP:
1595315333Serj	case IXGBE_DEV_ID_X550EM_A_SFP:
1596315333Serj	case IXGBE_DEV_ID_X550EM_A_SFP_N:
1597315333Serj	case IXGBE_DEV_ID_X550EM_A_QSFP:
1598315333Serj	case IXGBE_DEV_ID_X550EM_A_QSFP_N:
1599282289Serj		media_type = ixgbe_media_type_fiber;
1600282289Serj		break;
1601282289Serj	case IXGBE_DEV_ID_X550EM_X_1G_T:
1602282289Serj	case IXGBE_DEV_ID_X550EM_X_10G_T:
1603315333Serj	case IXGBE_DEV_ID_X550EM_A_10G_T:
1604282289Serj		media_type = ixgbe_media_type_copper;
1605282289Serj		break;
1606315333Serj	case IXGBE_DEV_ID_X550EM_A_SGMII:
1607315333Serj	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
1608315333Serj		media_type = ixgbe_media_type_backplane;
1609315333Serj		hw->phy.type = ixgbe_phy_sgmii;
1610315333Serj		break;
1611315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T:
1612315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
1613315333Serj		media_type = ixgbe_media_type_copper;
1614315333Serj		break;
1615282289Serj	default:
1616282289Serj		media_type = ixgbe_media_type_unknown;
1617282289Serj		break;
1618282289Serj	}
1619282289Serj	return media_type;
1620282289Serj}
1621282289Serj
1622282289Serj/**
1623282289Serj *  ixgbe_supported_sfp_modules_X550em - Check if SFP module type is supported
1624282289Serj *  @hw: pointer to hardware structure
1625282289Serj *  @linear: TRUE if SFP module is linear
1626282289Serj */
1627282289Serjstatic s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear)
1628282289Serj{
1629282289Serj	DEBUGFUNC("ixgbe_supported_sfp_modules_X550em");
1630282289Serj
1631282289Serj	switch (hw->phy.sfp_type) {
1632282289Serj	case ixgbe_sfp_type_not_present:
1633282289Serj		return IXGBE_ERR_SFP_NOT_PRESENT;
1634282289Serj	case ixgbe_sfp_type_da_cu_core0:
1635282289Serj	case ixgbe_sfp_type_da_cu_core1:
1636282289Serj		*linear = TRUE;
1637282289Serj		break;
1638282289Serj	case ixgbe_sfp_type_srlr_core0:
1639282289Serj	case ixgbe_sfp_type_srlr_core1:
1640282289Serj	case ixgbe_sfp_type_da_act_lmt_core0:
1641282289Serj	case ixgbe_sfp_type_da_act_lmt_core1:
1642282289Serj	case ixgbe_sfp_type_1g_sx_core0:
1643282289Serj	case ixgbe_sfp_type_1g_sx_core1:
1644282289Serj	case ixgbe_sfp_type_1g_lx_core0:
1645282289Serj	case ixgbe_sfp_type_1g_lx_core1:
1646282289Serj		*linear = FALSE;
1647282289Serj		break;
1648282289Serj	case ixgbe_sfp_type_unknown:
1649282289Serj	case ixgbe_sfp_type_1g_cu_core0:
1650282289Serj	case ixgbe_sfp_type_1g_cu_core1:
1651282289Serj	default:
1652282289Serj		return IXGBE_ERR_SFP_NOT_SUPPORTED;
1653282289Serj	}
1654282289Serj
1655282289Serj	return IXGBE_SUCCESS;
1656282289Serj}
1657282289Serj
1658282289Serj/**
1659282289Serj *  ixgbe_identify_sfp_module_X550em - Identifies SFP modules
1660282289Serj *  @hw: pointer to hardware structure
1661282289Serj *
1662282289Serj *  Searches for and identifies the SFP module and assigns appropriate PHY type.
1663282289Serj **/
1664282289Serjs32 ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw)
1665282289Serj{
1666282289Serj	s32 status;
1667282289Serj	bool linear;
1668282289Serj
1669282289Serj	DEBUGFUNC("ixgbe_identify_sfp_module_X550em");
1670282289Serj
1671282289Serj	status = ixgbe_identify_module_generic(hw);
1672282289Serj
1673282289Serj	if (status != IXGBE_SUCCESS)
1674282289Serj		return status;
1675282289Serj
1676282289Serj	/* Check if SFP module is supported */
1677282289Serj	status = ixgbe_supported_sfp_modules_X550em(hw, &linear);
1678282289Serj
1679282289Serj	return status;
1680282289Serj}
1681282289Serj
1682282289Serj/**
1683282289Serj *  ixgbe_setup_sfp_modules_X550em - Setup MAC link ops
1684282289Serj *  @hw: pointer to hardware structure
1685282289Serj */
1686282289Serjs32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
1687282289Serj{
1688282289Serj	s32 status;
1689282289Serj	bool linear;
1690282289Serj
1691282289Serj	DEBUGFUNC("ixgbe_setup_sfp_modules_X550em");
1692282289Serj
1693282289Serj	/* Check if SFP module is supported */
1694282289Serj	status = ixgbe_supported_sfp_modules_X550em(hw, &linear);
1695282289Serj
1696282289Serj	if (status != IXGBE_SUCCESS)
1697282289Serj		return status;
1698282289Serj
1699282289Serj	ixgbe_init_mac_link_ops_X550em(hw);
1700282289Serj	hw->phy.ops.reset = NULL;
1701282289Serj
1702282289Serj	return IXGBE_SUCCESS;
1703282289Serj}
1704282289Serj
1705282289Serj/**
1706315333Serj*  ixgbe_restart_an_internal_phy_x550em - restart autonegotiation for the
1707315333Serj*  internal PHY
1708315333Serj*  @hw: pointer to hardware structure
1709315333Serj**/
1710315333Serjstatic s32 ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw)
1711315333Serj{
1712315333Serj	s32 status;
1713315333Serj	u32 link_ctrl;
1714315333Serj
1715315333Serj	/* Restart auto-negotiation. */
1716315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
1717315333Serj				       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1718315333Serj				       IXGBE_SB_IOSF_TARGET_KR_PHY, &link_ctrl);
1719315333Serj
1720315333Serj	if (status) {
1721315333Serj		DEBUGOUT("Auto-negotiation did not complete\n");
1722315333Serj		return status;
1723315333Serj	}
1724315333Serj
1725315333Serj	link_ctrl |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
1726315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
1727315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1728315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, link_ctrl);
1729315333Serj
1730315333Serj	if (hw->mac.type == ixgbe_mac_X550EM_a) {
1731315333Serj		u32 flx_mask_st20;
1732315333Serj
1733315333Serj		/* Indicate to FW that AN restart has been asserted */
1734315333Serj		status = hw->mac.ops.read_iosf_sb_reg(hw,
1735315333Serj				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1736315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_mask_st20);
1737315333Serj
1738315333Serj		if (status) {
1739315333Serj			DEBUGOUT("Auto-negotiation did not complete\n");
1740315333Serj			return status;
1741315333Serj		}
1742315333Serj
1743315333Serj		flx_mask_st20 |= IXGBE_KRM_PMD_FLX_MASK_ST20_FW_AN_RESTART;
1744315333Serj		status = hw->mac.ops.write_iosf_sb_reg(hw,
1745315333Serj				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1746315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, flx_mask_st20);
1747315333Serj	}
1748315333Serj
1749315333Serj	return status;
1750315333Serj}
1751315333Serj
1752315333Serj/**
1753315333Serj * ixgbe_setup_sgmii - Set up link for sgmii
1754315333Serj * @hw: pointer to hardware structure
1755315333Serj */
1756315333Serjstatic s32 ixgbe_setup_sgmii(struct ixgbe_hw *hw, ixgbe_link_speed speed,
1757315333Serj			     bool autoneg_wait)
1758315333Serj{
1759315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
1760315333Serj	u32 lval, sval, flx_val;
1761315333Serj	s32 rc;
1762315333Serj
1763315333Serj	rc = mac->ops.read_iosf_sb_reg(hw,
1764315333Serj				       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1765315333Serj				       IXGBE_SB_IOSF_TARGET_KR_PHY, &lval);
1766315333Serj	if (rc)
1767315333Serj		return rc;
1768315333Serj
1769315333Serj	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
1770315333Serj	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
1771315333Serj	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN;
1772315333Serj	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN;
1773315333Serj	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
1774315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1775315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1776315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, lval);
1777315333Serj	if (rc)
1778315333Serj		return rc;
1779315333Serj
1780315333Serj	rc = mac->ops.read_iosf_sb_reg(hw,
1781315333Serj				       IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1782315333Serj				       IXGBE_SB_IOSF_TARGET_KR_PHY, &sval);
1783315333Serj	if (rc)
1784315333Serj		return rc;
1785315333Serj
1786315333Serj	sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D;
1787315333Serj	sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D;
1788315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1789315333Serj					IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1790315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, sval);
1791315333Serj	if (rc)
1792315333Serj		return rc;
1793315333Serj
1794315333Serj	rc = mac->ops.read_iosf_sb_reg(hw,
1795315333Serj				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1796315333Serj				    IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val);
1797315333Serj	if (rc)
1798315333Serj		return rc;
1799315333Serj
1800315333Serj	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
1801315333Serj	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G;
1802315333Serj	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
1803315333Serj	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
1804315333Serj	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
1805315333Serj
1806315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1807315333Serj				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1808315333Serj				    IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val);
1809315333Serj	if (rc)
1810315333Serj		return rc;
1811315333Serj
1812315333Serj	rc = ixgbe_restart_an_internal_phy_x550em(hw);
1813315333Serj	if (rc)
1814315333Serj		return rc;
1815315333Serj
1816315333Serj	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
1817315333Serj}
1818315333Serj
1819315333Serj/**
1820315333Serj * ixgbe_setup_sgmii_fw - Set up link for sgmii with firmware-controlled PHYs
1821315333Serj * @hw: pointer to hardware structure
1822315333Serj */
1823315333Serjstatic s32 ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed,
1824315333Serj				bool autoneg_wait)
1825315333Serj{
1826315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
1827315333Serj	u32 lval, sval, flx_val;
1828315333Serj	s32 rc;
1829315333Serj
1830315333Serj	rc = mac->ops.read_iosf_sb_reg(hw,
1831315333Serj				       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1832315333Serj				       IXGBE_SB_IOSF_TARGET_KR_PHY, &lval);
1833315333Serj	if (rc)
1834315333Serj		return rc;
1835315333Serj
1836315333Serj	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
1837315333Serj	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
1838315333Serj	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN;
1839315333Serj	lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN;
1840315333Serj	lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
1841315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1842315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1843315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, lval);
1844315333Serj	if (rc)
1845315333Serj		return rc;
1846315333Serj
1847315333Serj	rc = mac->ops.read_iosf_sb_reg(hw,
1848315333Serj				       IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1849315333Serj				       IXGBE_SB_IOSF_TARGET_KR_PHY, &sval);
1850315333Serj	if (rc)
1851315333Serj		return rc;
1852315333Serj
1853315333Serj	sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D;
1854315333Serj	sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D;
1855315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1856315333Serj					IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id),
1857315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, sval);
1858315333Serj	if (rc)
1859315333Serj		return rc;
1860315333Serj
1861315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1862315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
1863315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, lval);
1864315333Serj	if (rc)
1865315333Serj		return rc;
1866315333Serj
1867315333Serj	rc = mac->ops.read_iosf_sb_reg(hw,
1868315333Serj				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1869315333Serj				    IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val);
1870315333Serj	if (rc)
1871315333Serj		return rc;
1872315333Serj
1873315333Serj	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
1874315333Serj	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN;
1875315333Serj	flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
1876315333Serj	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
1877315333Serj	flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
1878315333Serj
1879315333Serj	rc = mac->ops.write_iosf_sb_reg(hw,
1880315333Serj				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
1881315333Serj				    IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val);
1882315333Serj	if (rc)
1883315333Serj		return rc;
1884315333Serj
1885315333Serj	rc = ixgbe_restart_an_internal_phy_x550em(hw);
1886315333Serj
1887315333Serj	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
1888315333Serj}
1889315333Serj
1890315333Serj/**
1891282289Serj *  ixgbe_init_mac_link_ops_X550em - init mac link function pointers
1892282289Serj *  @hw: pointer to hardware structure
1893282289Serj */
1894282289Serjvoid ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
1895282289Serj{
1896282289Serj	struct ixgbe_mac_info *mac = &hw->mac;
1897282289Serj
1898282289Serj	DEBUGFUNC("ixgbe_init_mac_link_ops_X550em");
1899282289Serj
1900315333Serj	switch (hw->mac.ops.get_media_type(hw)) {
1901315333Serj	case ixgbe_media_type_fiber:
1902282289Serj		/* CS4227 does not support autoneg, so disable the laser control
1903282289Serj		 * functions for SFP+ fiber
1904282289Serj		 */
1905282289Serj		mac->ops.disable_tx_laser = NULL;
1906282289Serj		mac->ops.enable_tx_laser = NULL;
1907282289Serj		mac->ops.flap_tx_laser = NULL;
1908282289Serj		mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber;
1909282289Serj		mac->ops.set_rate_select_speed =
1910282289Serj					ixgbe_set_soft_rate_select_speed;
1911315333Serj
1912315333Serj		if ((hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) ||
1913315333Serj		    (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP))
1914315333Serj			mac->ops.setup_mac_link =
1915315333Serj						ixgbe_setup_mac_link_sfp_x550a;
1916315333Serj		else
1917315333Serj			mac->ops.setup_mac_link =
1918315333Serj						ixgbe_setup_mac_link_sfp_x550em;
1919282289Serj		break;
1920282289Serj	case ixgbe_media_type_copper:
1921315333Serj		if (hw->mac.type == ixgbe_mac_X550EM_a) {
1922315333Serj			if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T ||
1923315333Serj			    hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) {
1924315333Serj				mac->ops.setup_link = ixgbe_setup_sgmii_fw;
1925315333Serj				mac->ops.check_link =
1926315333Serj						   ixgbe_check_mac_link_generic;
1927315333Serj			} else {
1928315333Serj				mac->ops.setup_link =
1929315333Serj						  ixgbe_setup_mac_link_t_X550em;
1930315333Serj			}
1931315333Serj		} else {
1932315333Serj			mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
1933315333Serj			mac->ops.check_link = ixgbe_check_link_t_X550em;
1934315333Serj		}
1935282289Serj		break;
1936315333Serj	case ixgbe_media_type_backplane:
1937315333Serj		if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII ||
1938315333Serj		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L)
1939315333Serj			mac->ops.setup_link = ixgbe_setup_sgmii;
1940315333Serj		break;
1941282289Serj	default:
1942282289Serj		break;
1943315333Serj	}
1944282289Serj}
1945282289Serj
1946282289Serj/**
1947282289Serj *  ixgbe_get_link_capabilities_x550em - Determines link capabilities
1948282289Serj *  @hw: pointer to hardware structure
1949282289Serj *  @speed: pointer to link speed
1950282289Serj *  @autoneg: TRUE when autoneg or autotry is enabled
1951282289Serj */
1952282289Serjs32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
1953282289Serj				       ixgbe_link_speed *speed,
1954282289Serj				       bool *autoneg)
1955282289Serj{
1956282289Serj	DEBUGFUNC("ixgbe_get_link_capabilities_X550em");
1957282289Serj
1958315333Serj
1959315333Serj	if (hw->phy.type == ixgbe_phy_fw) {
1960315333Serj		*autoneg = TRUE;
1961315333Serj		*speed = hw->phy.speeds_supported;
1962315333Serj		return 0;
1963315333Serj	}
1964315333Serj
1965282289Serj	/* SFP */
1966282289Serj	if (hw->phy.media_type == ixgbe_media_type_fiber) {
1967282289Serj
1968282289Serj		/* CS4227 SFP must not enable auto-negotiation */
1969282289Serj		*autoneg = FALSE;
1970282289Serj
1971282289Serj		/* Check if 1G SFP module. */
1972282289Serj		if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
1973282289Serj		    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1
1974282289Serj		    || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
1975282289Serj		    hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1) {
1976282289Serj			*speed = IXGBE_LINK_SPEED_1GB_FULL;
1977282289Serj			return IXGBE_SUCCESS;
1978282289Serj		}
1979282289Serj
1980282289Serj		/* Link capabilities are based on SFP */
1981282289Serj		if (hw->phy.multispeed_fiber)
1982282289Serj			*speed = IXGBE_LINK_SPEED_10GB_FULL |
1983282289Serj				 IXGBE_LINK_SPEED_1GB_FULL;
1984282289Serj		else
1985282289Serj			*speed = IXGBE_LINK_SPEED_10GB_FULL;
1986282289Serj	} else {
1987315333Serj		switch (hw->phy.type) {
1988315333Serj		case ixgbe_phy_sgmii:
1989315333Serj			*speed = IXGBE_LINK_SPEED_1GB_FULL;
1990315333Serj			break;
1991315333Serj		case ixgbe_phy_x550em_kr:
1992315333Serj			if (hw->mac.type == ixgbe_mac_X550EM_a) {
1993315333Serj				/* check different backplane modes */
1994315333Serj				if (hw->phy.nw_mng_if_sel &
1995315333Serj					   IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G) {
1996315333Serj					*speed = IXGBE_LINK_SPEED_2_5GB_FULL;
1997315333Serj					break;
1998315333Serj				} else if (hw->device_id ==
1999315333Serj						   IXGBE_DEV_ID_X550EM_A_KR_L) {
2000315333Serj					*speed = IXGBE_LINK_SPEED_1GB_FULL;
2001315333Serj					break;
2002315333Serj				}
2003315333Serj			}
2004315333Serj			/* fall through */
2005315333Serj		default:
2006315333Serj			*speed = IXGBE_LINK_SPEED_10GB_FULL |
2007315333Serj				 IXGBE_LINK_SPEED_1GB_FULL;
2008315333Serj			break;
2009315333Serj		}
2010282289Serj		*autoneg = TRUE;
2011282289Serj	}
2012282289Serj
2013282289Serj	return IXGBE_SUCCESS;
2014282289Serj}
2015282289Serj
2016282289Serj/**
2017282289Serj * ixgbe_get_lasi_ext_t_x550em - Determime external Base T PHY interrupt cause
2018282289Serj * @hw: pointer to hardware structure
2019282289Serj * @lsc: pointer to boolean flag which indicates whether external Base T
2020282289Serj *       PHY interrupt is lsc
2021282289Serj *
2022282289Serj * Determime if external Base T PHY interrupt cause is high temperature
2023282289Serj * failure alarm or link status change.
2024282289Serj *
2025282289Serj * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
2026282289Serj * failure alarm, else return PHY access status.
2027282289Serj */
2028282289Serjstatic s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
2029282289Serj{
2030282289Serj	u32 status;
2031282289Serj	u16 reg;
2032282289Serj
2033282289Serj	*lsc = FALSE;
2034282289Serj
2035282289Serj	/* Vendor alarm triggered */
2036282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
2037282289Serj				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2038282289Serj				      &reg);
2039282289Serj
2040282289Serj	if (status != IXGBE_SUCCESS ||
2041282289Serj	    !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN))
2042282289Serj		return status;
2043282289Serj
2044282289Serj	/* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */
2045282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG,
2046282289Serj				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2047282289Serj				      &reg);
2048282289Serj
2049282289Serj	if (status != IXGBE_SUCCESS ||
2050282289Serj	    !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
2051282289Serj	    IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
2052282289Serj		return status;
2053282289Serj
2054295528Ssmh	/* Global alarm triggered */
2055282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
2056282289Serj				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2057282289Serj				      &reg);
2058282289Serj
2059282289Serj	if (status != IXGBE_SUCCESS)
2060282289Serj		return status;
2061282289Serj
2062282289Serj	/* If high temperature failure, then return over temp error and exit */
2063282289Serj	if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
2064282289Serj		/* power down the PHY in case the PHY FW didn't already */
2065282289Serj		ixgbe_set_copper_phy_power(hw, FALSE);
2066282289Serj		return IXGBE_ERR_OVERTEMP;
2067295528Ssmh	} else if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) {
2068295528Ssmh		/*  device fault alarm triggered */
2069295528Ssmh		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_FAULT_MSG,
2070295528Ssmh					  IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2071295528Ssmh					  &reg);
2072295528Ssmh
2073295528Ssmh		if (status != IXGBE_SUCCESS)
2074295528Ssmh			return status;
2075295528Ssmh
2076295528Ssmh		/* if device fault was due to high temp alarm handle and exit */
2077295528Ssmh		if (reg == IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP) {
2078295528Ssmh			/* power down the PHY in case the PHY FW didn't */
2079295528Ssmh			ixgbe_set_copper_phy_power(hw, FALSE);
2080295528Ssmh			return IXGBE_ERR_OVERTEMP;
2081295528Ssmh		}
2082282289Serj	}
2083282289Serj
2084282289Serj	/* Vendor alarm 2 triggered */
2085282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
2086282289Serj				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
2087282289Serj
2088282289Serj	if (status != IXGBE_SUCCESS ||
2089282289Serj	    !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT))
2090282289Serj		return status;
2091282289Serj
2092282289Serj	/* link connect/disconnect event occurred */
2093282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2,
2094282289Serj				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
2095282289Serj
2096282289Serj	if (status != IXGBE_SUCCESS)
2097282289Serj		return status;
2098282289Serj
2099282289Serj	/* Indicate LSC */
2100282289Serj	if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC)
2101282289Serj		*lsc = TRUE;
2102282289Serj
2103282289Serj	return IXGBE_SUCCESS;
2104282289Serj}
2105282289Serj
2106282289Serj/**
2107282289Serj * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts
2108282289Serj * @hw: pointer to hardware structure
2109282289Serj *
2110282289Serj * Enable link status change and temperature failure alarm for the external
2111282289Serj * Base T PHY
2112282289Serj *
2113282289Serj * Returns PHY access status
2114282289Serj */
2115282289Serjstatic s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
2116282289Serj{
2117282289Serj	u32 status;
2118282289Serj	u16 reg;
2119282289Serj	bool lsc;
2120282289Serj
2121282289Serj	/* Clear interrupt flags */
2122282289Serj	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
2123282289Serj
2124282289Serj	/* Enable link status change alarm */
2125282289Serj
2126315333Serj	/* Enable the LASI interrupts on X552 devices to receive notifications
2127315333Serj	 * of the link configurations of the external PHY and correspondingly
2128315333Serj	 * support the configuration of the internal iXFI link, since iXFI does
2129315333Serj	 * not support auto-negotiation. This is not required for X553 devices
2130315333Serj	 * having KR support, which performs auto-negotiations and which is used
2131315333Serj	 * as the internal link to the external PHY. Hence adding a check here
2132315333Serj	 * to avoid enabling LASI interrupts for X553 devices.
2133315333Serj	 */
2134315333Serj	if (hw->mac.type != ixgbe_mac_X550EM_a) {
2135315333Serj		status = hw->phy.ops.read_reg(hw,
2136315333Serj					IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
2137315333Serj					IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
2138282289Serj
2139315333Serj		if (status != IXGBE_SUCCESS)
2140315333Serj			return status;
2141282289Serj
2142315333Serj		reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
2143282289Serj
2144315333Serj		status = hw->phy.ops.write_reg(hw,
2145315333Serj					IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
2146315333Serj					IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg);
2147282289Serj
2148315333Serj		if (status != IXGBE_SUCCESS)
2149315333Serj			return status;
2150315333Serj	}
2151315333Serj
2152315333Serj	/* Enable high temperature failure and global fault alarms */
2153282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
2154282289Serj				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2155282289Serj				      &reg);
2156282289Serj
2157282289Serj	if (status != IXGBE_SUCCESS)
2158282289Serj		return status;
2159282289Serj
2160315333Serj	reg |= (IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN |
2161315333Serj		IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN);
2162282289Serj
2163282289Serj	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
2164282289Serj				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2165282289Serj				       reg);
2166282289Serj
2167282289Serj	if (status != IXGBE_SUCCESS)
2168282289Serj		return status;
2169282289Serj
2170282289Serj	/* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */
2171282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
2172282289Serj				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2173282289Serj				      &reg);
2174282289Serj
2175282289Serj	if (status != IXGBE_SUCCESS)
2176282289Serj		return status;
2177282289Serj
2178282289Serj	reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
2179282289Serj		IXGBE_MDIO_GLOBAL_ALARM_1_INT);
2180282289Serj
2181282289Serj	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
2182282289Serj				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2183282289Serj				       reg);
2184282289Serj
2185282289Serj	if (status != IXGBE_SUCCESS)
2186282289Serj		return status;
2187282289Serj
2188282289Serj	/* Enable chip-wide vendor alarm */
2189282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
2190282289Serj				      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2191282289Serj				      &reg);
2192282289Serj
2193282289Serj	if (status != IXGBE_SUCCESS)
2194282289Serj		return status;
2195282289Serj
2196282289Serj	reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN;
2197282289Serj
2198282289Serj	status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
2199282289Serj				       IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2200282289Serj				       reg);
2201282289Serj
2202282289Serj	return status;
2203282289Serj}
2204282289Serj
2205282289Serj/**
2206282289Serj *  ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed.
2207282289Serj *  @hw: pointer to hardware structure
2208282289Serj *  @speed: link speed
2209282289Serj *
2210282289Serj *  Configures the integrated KR PHY.
2211282289Serj **/
2212282289Serjstatic s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw,
2213282289Serj				       ixgbe_link_speed speed)
2214282289Serj{
2215282289Serj	s32 status;
2216282289Serj	u32 reg_val;
2217282289Serj
2218315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
2219315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2220315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2221282289Serj	if (status)
2222282289Serj		return status;
2223282289Serj
2224282289Serj	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
2225282289Serj	reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
2226282289Serj		     IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
2227282289Serj
2228282289Serj	/* Advertise 10G support. */
2229282289Serj	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
2230282289Serj		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
2231282289Serj
2232282289Serj	/* Advertise 1G support. */
2233282289Serj	if (speed & IXGBE_LINK_SPEED_1GB_FULL)
2234282289Serj		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
2235282289Serj
2236315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
2237315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2238315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2239282289Serj
2240315333Serj	if (hw->mac.type == ixgbe_mac_X550EM_a) {
2241315333Serj		/* Set lane mode  to KR auto negotiation */
2242315333Serj		status = hw->mac.ops.read_iosf_sb_reg(hw,
2243315333Serj				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2244315333Serj				    IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2245315333Serj
2246315333Serj		if (status)
2247315333Serj			return status;
2248315333Serj
2249315333Serj		reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
2250315333Serj		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN;
2251315333Serj		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
2252315333Serj		reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
2253315333Serj		reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
2254315333Serj
2255315333Serj		status = hw->mac.ops.write_iosf_sb_reg(hw,
2256315333Serj				    IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2257315333Serj				    IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2258315333Serj	}
2259315333Serj
2260315333Serj	return ixgbe_restart_an_internal_phy_x550em(hw);
2261282289Serj}
2262282289Serj
2263282289Serj/**
2264315333Serj * ixgbe_reset_phy_fw - Reset firmware-controlled PHYs
2265315333Serj * @hw: pointer to hardware structure
2266315333Serj */
2267315333Serjstatic s32 ixgbe_reset_phy_fw(struct ixgbe_hw *hw)
2268315333Serj{
2269315333Serj	u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 };
2270315333Serj	s32 rc;
2271315333Serj
2272315333Serj	if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw))
2273315333Serj		return IXGBE_SUCCESS;
2274315333Serj
2275315333Serj	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_PHY_SW_RESET, &store);
2276315333Serj	if (rc)
2277315333Serj		return rc;
2278315333Serj	memset(store, 0, sizeof(store));
2279315333Serj
2280315333Serj	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_INIT_PHY, &store);
2281315333Serj	if (rc)
2282315333Serj		return rc;
2283315333Serj
2284315333Serj	return ixgbe_setup_fw_link(hw);
2285315333Serj}
2286315333Serj
2287315333Serj/**
2288315333Serj * ixgbe_check_overtemp_fw - Check firmware-controlled PHYs for overtemp
2289315333Serj * @hw: pointer to hardware structure
2290315333Serj */
2291315333Serjstatic s32 ixgbe_check_overtemp_fw(struct ixgbe_hw *hw)
2292315333Serj{
2293315333Serj	u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 };
2294315333Serj	s32 rc;
2295315333Serj
2296315333Serj	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store);
2297315333Serj	if (rc)
2298315333Serj		return rc;
2299315333Serj
2300315333Serj	if (store[0] & FW_PHY_ACT_GET_LINK_INFO_TEMP) {
2301315333Serj		ixgbe_shutdown_fw_phy(hw);
2302315333Serj		return IXGBE_ERR_OVERTEMP;
2303315333Serj	}
2304315333Serj	return IXGBE_SUCCESS;
2305315333Serj}
2306315333Serj
2307315333Serj/**
2308315333Serj *  ixgbe_read_mng_if_sel_x550em - Read NW_MNG_IF_SEL register
2309315333Serj *  @hw: pointer to hardware structure
2310315333Serj *
2311315333Serj *  Read NW_MNG_IF_SEL register and save field values, and check for valid field
2312315333Serj *  values.
2313315333Serj **/
2314315333Serjstatic s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw)
2315315333Serj{
2316315333Serj	/* Save NW management interface connected on board. This is used
2317315333Serj	 * to determine internal PHY mode.
2318315333Serj	 */
2319315333Serj	hw->phy.nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
2320315333Serj
2321315333Serj	/* If X552 (X550EM_a) and MDIO is connected to external PHY, then set
2322315333Serj	 * PHY address. This register field was has only been used for X552.
2323315333Serj	 */
2324315333Serj	if (hw->mac.type == ixgbe_mac_X550EM_a &&
2325315333Serj	    hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_MDIO_ACT) {
2326315333Serj		hw->phy.addr = (hw->phy.nw_mng_if_sel &
2327315333Serj				IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
2328315333Serj			       IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
2329315333Serj	}
2330315333Serj
2331315333Serj	return IXGBE_SUCCESS;
2332315333Serj}
2333315333Serj
2334315333Serj/**
2335282289Serj *  ixgbe_init_phy_ops_X550em - PHY/SFP specific init
2336282289Serj *  @hw: pointer to hardware structure
2337282289Serj *
2338282289Serj *  Initialize any function pointers that were not able to be
2339282289Serj *  set during init_shared_code because the PHY/SFP type was
2340282289Serj *  not known.  Perform the SFP init if necessary.
2341282289Serj */
2342282289Serjs32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
2343282289Serj{
2344282289Serj	struct ixgbe_phy_info *phy = &hw->phy;
2345282289Serj	s32 ret_val;
2346282289Serj
2347282289Serj	DEBUGFUNC("ixgbe_init_phy_ops_X550em");
2348282289Serj
2349282289Serj	hw->mac.ops.set_lan_id(hw);
2350315333Serj	ixgbe_read_mng_if_sel_x550em(hw);
2351282289Serj
2352282289Serj	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
2353282289Serj		phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
2354282289Serj		ixgbe_setup_mux_ctl(hw);
2355282289Serj		phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em;
2356282289Serj	}
2357282289Serj
2358315333Serj	switch (hw->device_id) {
2359315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T:
2360315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
2361315333Serj		phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi_22;
2362315333Serj		phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi_22;
2363315333Serj		hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
2364315333Serj		hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
2365315333Serj		phy->ops.check_overtemp = ixgbe_check_overtemp_fw;
2366315333Serj		if (hw->bus.lan_id)
2367315333Serj			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
2368315333Serj		else
2369315333Serj			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
2370315333Serj
2371315333Serj		break;
2372315333Serj	case IXGBE_DEV_ID_X550EM_A_10G_T:
2373315333Serj	case IXGBE_DEV_ID_X550EM_A_SFP:
2374315333Serj		hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
2375315333Serj		hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
2376315333Serj		if (hw->bus.lan_id)
2377315333Serj			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
2378315333Serj		else
2379315333Serj			hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
2380315333Serj		break;
2381315333Serj	case IXGBE_DEV_ID_X550EM_X_SFP:
2382315333Serj		/* set up for CS4227 usage */
2383315333Serj		hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
2384315333Serj		break;
2385315333Serj	default:
2386315333Serj		break;
2387315333Serj	}
2388315333Serj
2389282289Serj	/* Identify the PHY or SFP module */
2390282289Serj	ret_val = phy->ops.identify(hw);
2391315333Serj	if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED ||
2392315333Serj	    ret_val == IXGBE_ERR_PHY_ADDR_INVALID)
2393282289Serj		return ret_val;
2394282289Serj
2395282289Serj	/* Setup function pointers based on detected hardware */
2396282289Serj	ixgbe_init_mac_link_ops_X550em(hw);
2397282289Serj	if (phy->sfp_type != ixgbe_sfp_type_unknown)
2398282289Serj		phy->ops.reset = NULL;
2399282289Serj
2400282289Serj	/* Set functions pointers based on phy type */
2401282289Serj	switch (hw->phy.type) {
2402282289Serj	case ixgbe_phy_x550em_kx4:
2403295524Ssbruno		phy->ops.setup_link = NULL;
2404282289Serj		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
2405282289Serj		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
2406282289Serj		break;
2407282289Serj	case ixgbe_phy_x550em_kr:
2408282289Serj		phy->ops.setup_link = ixgbe_setup_kr_x550em;
2409282289Serj		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
2410282289Serj		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
2411282289Serj		break;
2412315333Serj	case ixgbe_phy_x550em_xfi:
2413315333Serj		/* link is managed by HW */
2414315333Serj		phy->ops.setup_link = NULL;
2415315333Serj		phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
2416315333Serj		phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
2417315333Serj		break;
2418282289Serj	case ixgbe_phy_x550em_ext_t:
2419282289Serj		/* If internal link mode is XFI, then setup iXFI internal link,
2420282289Serj		 * else setup KR now.
2421282289Serj		 */
2422315333Serj		phy->ops.setup_internal_link =
2423282289Serj					      ixgbe_setup_internal_phy_t_x550em;
2424282289Serj
2425315333Serj		/* setup SW LPLU only for first revision of X550EM_x */
2426315333Serj		if ((hw->mac.type == ixgbe_mac_X550EM_x) &&
2427315333Serj		    !(IXGBE_FUSES0_REV_MASK &
2428315333Serj		      IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))))
2429295524Ssbruno			phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em;
2430295524Ssbruno
2431282289Serj		phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
2432282289Serj		phy->ops.reset = ixgbe_reset_phy_t_X550em;
2433282289Serj		break;
2434315333Serj	case ixgbe_phy_sgmii:
2435315333Serj		phy->ops.setup_link = NULL;
2436315333Serj		break;
2437315333Serj	case ixgbe_phy_fw:
2438315333Serj		phy->ops.setup_link = ixgbe_setup_fw_link;
2439315333Serj		phy->ops.reset = ixgbe_reset_phy_fw;
2440315333Serj		break;
2441282289Serj	default:
2442282289Serj		break;
2443282289Serj	}
2444282289Serj	return ret_val;
2445282289Serj}
2446282289Serj
2447282289Serj/**
2448315333Serj * ixgbe_set_mdio_speed - Set MDIO clock speed
2449315333Serj *  @hw: pointer to hardware structure
2450315333Serj */
2451315333Serjstatic void ixgbe_set_mdio_speed(struct ixgbe_hw *hw)
2452315333Serj{
2453315333Serj	u32 hlreg0;
2454315333Serj
2455315333Serj	switch (hw->device_id) {
2456315333Serj	case IXGBE_DEV_ID_X550EM_X_10G_T:
2457315333Serj	case IXGBE_DEV_ID_X550EM_A_SGMII:
2458315333Serj	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
2459315333Serj	case IXGBE_DEV_ID_X550EM_A_10G_T:
2460315333Serj	case IXGBE_DEV_ID_X550EM_A_SFP:
2461315333Serj	case IXGBE_DEV_ID_X550EM_A_QSFP:
2462315333Serj		/* Config MDIO clock speed before the first MDIO PHY access */
2463315333Serj		hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2464315333Serj		hlreg0 &= ~IXGBE_HLREG0_MDCSPD;
2465315333Serj		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
2466315333Serj		break;
2467315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T:
2468315333Serj	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
2469315333Serj		/* Select fast MDIO clock speed for these devices */
2470315333Serj		hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2471315333Serj		hlreg0 |= IXGBE_HLREG0_MDCSPD;
2472315333Serj		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
2473315333Serj		break;
2474315333Serj	default:
2475315333Serj		break;
2476315333Serj	}
2477315333Serj}
2478315333Serj
2479315333Serj/**
2480282289Serj *  ixgbe_reset_hw_X550em - Perform hardware reset
2481282289Serj *  @hw: pointer to hardware structure
2482282289Serj *
2483282289Serj *  Resets the hardware by resetting the transmit and receive units, masks
2484282289Serj *  and clears all interrupts, perform a PHY reset, and perform a link (MAC)
2485282289Serj *  reset.
2486282289Serj */
2487282289Serjs32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
2488282289Serj{
2489282289Serj	ixgbe_link_speed link_speed;
2490282289Serj	s32 status;
2491282289Serj	u32 ctrl = 0;
2492282289Serj	u32 i;
2493282289Serj	bool link_up = FALSE;
2494282289Serj
2495282289Serj	DEBUGFUNC("ixgbe_reset_hw_X550em");
2496282289Serj
2497282289Serj	/* Call adapter stop to disable Tx/Rx and clear interrupts */
2498282289Serj	status = hw->mac.ops.stop_adapter(hw);
2499315333Serj	if (status != IXGBE_SUCCESS) {
2500315333Serj		DEBUGOUT1("Failed to stop adapter, STATUS = %d\n", status);
2501282289Serj		return status;
2502315333Serj	}
2503282289Serj	/* flush pending Tx transactions */
2504282289Serj	ixgbe_clear_tx_pending(hw);
2505282289Serj
2506315333Serj	ixgbe_set_mdio_speed(hw);
2507295524Ssbruno
2508282289Serj	/* PHY ops must be identified and initialized prior to reset */
2509282289Serj	status = hw->phy.ops.init(hw);
2510282289Serj
2511315333Serj	if (status)
2512315333Serj		DEBUGOUT1("Failed to initialize PHY ops, STATUS = %d\n",
2513315333Serj			  status);
2514315333Serj
2515315333Serj	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) {
2516315333Serj		DEBUGOUT("Returning from reset HW due to PHY init failure\n");
2517282289Serj		return status;
2518315333Serj	}
2519282289Serj
2520282289Serj	/* start the external PHY */
2521282289Serj	if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
2522282289Serj		status = ixgbe_init_ext_t_x550em(hw);
2523315333Serj		if (status) {
2524315333Serj			DEBUGOUT1("Failed to start the external PHY, STATUS = %d\n",
2525315333Serj				  status);
2526282289Serj			return status;
2527315333Serj		}
2528282289Serj	}
2529282289Serj
2530282289Serj	/* Setup SFP module if there is one present. */
2531282289Serj	if (hw->phy.sfp_setup_needed) {
2532282289Serj		status = hw->mac.ops.setup_sfp(hw);
2533282289Serj		hw->phy.sfp_setup_needed = FALSE;
2534282289Serj	}
2535282289Serj
2536282289Serj	if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
2537282289Serj		return status;
2538282289Serj
2539282289Serj	/* Reset PHY */
2540315333Serj	if (!hw->phy.reset_disable && hw->phy.ops.reset) {
2541315333Serj		if (hw->phy.ops.reset(hw) == IXGBE_ERR_OVERTEMP)
2542315333Serj			return IXGBE_ERR_OVERTEMP;
2543315333Serj	}
2544282289Serj
2545282289Serjmac_reset_top:
2546282289Serj	/* Issue global reset to the MAC.  Needs to be SW reset if link is up.
2547282289Serj	 * If link reset is used when link is up, it might reset the PHY when
2548282289Serj	 * mng is using it.  If link is down or the flag to force full link
2549282289Serj	 * reset is set, then perform link reset.
2550282289Serj	 */
2551282289Serj	ctrl = IXGBE_CTRL_LNK_RST;
2552282289Serj	if (!hw->force_full_reset) {
2553282289Serj		hw->mac.ops.check_link(hw, &link_speed, &link_up, FALSE);
2554282289Serj		if (link_up)
2555282289Serj			ctrl = IXGBE_CTRL_RST;
2556282289Serj	}
2557282289Serj
2558282289Serj	ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
2559282289Serj	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
2560282289Serj	IXGBE_WRITE_FLUSH(hw);
2561282289Serj
2562282289Serj	/* Poll for reset bit to self-clear meaning reset is complete */
2563282289Serj	for (i = 0; i < 10; i++) {
2564282289Serj		usec_delay(1);
2565282289Serj		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
2566282289Serj		if (!(ctrl & IXGBE_CTRL_RST_MASK))
2567282289Serj			break;
2568282289Serj	}
2569282289Serj
2570282289Serj	if (ctrl & IXGBE_CTRL_RST_MASK) {
2571282289Serj		status = IXGBE_ERR_RESET_FAILED;
2572282289Serj		DEBUGOUT("Reset polling failed to complete.\n");
2573282289Serj	}
2574282289Serj
2575282289Serj	msec_delay(50);
2576282289Serj
2577282289Serj	/* Double resets are required for recovery from certain error
2578282289Serj	 * conditions.  Between resets, it is necessary to stall to
2579282289Serj	 * allow time for any pending HW events to complete.
2580282289Serj	 */
2581282289Serj	if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
2582282289Serj		hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
2583282289Serj		goto mac_reset_top;
2584282289Serj	}
2585282289Serj
2586282289Serj	/* Store the permanent mac address */
2587282289Serj	hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
2588282289Serj
2589282289Serj	/* Store MAC address from RAR0, clear receive address registers, and
2590282289Serj	 * clear the multicast table.  Also reset num_rar_entries to 128,
2591282289Serj	 * since we modify this value when programming the SAN MAC address.
2592282289Serj	 */
2593282289Serj	hw->mac.num_rar_entries = 128;
2594282289Serj	hw->mac.ops.init_rx_addrs(hw);
2595282289Serj
2596315333Serj	ixgbe_set_mdio_speed(hw);
2597315333Serj
2598282289Serj	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
2599282289Serj		ixgbe_setup_mux_ctl(hw);
2600282289Serj
2601315333Serj	if (status != IXGBE_SUCCESS)
2602315333Serj		DEBUGOUT1("Reset HW failed, STATUS = %d\n", status);
2603315333Serj
2604282289Serj	return status;
2605282289Serj}
2606282289Serj
2607282289Serj/**
2608282289Serj * ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY.
2609282289Serj * @hw: pointer to hardware structure
2610282289Serj */
2611282289Serjs32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
2612282289Serj{
2613282289Serj	u32 status;
2614282289Serj	u16 reg;
2615282289Serj
2616282289Serj	status = hw->phy.ops.read_reg(hw,
2617282289Serj				      IXGBE_MDIO_TX_VENDOR_ALARMS_3,
2618282289Serj				      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
2619282289Serj				      &reg);
2620282289Serj
2621282289Serj	if (status != IXGBE_SUCCESS)
2622282289Serj		return status;
2623282289Serj
2624282289Serj	/* If PHY FW reset completed bit is set then this is the first
2625282289Serj	 * SW instance after a power on so the PHY FW must be un-stalled.
2626282289Serj	 */
2627282289Serj	if (reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
2628282289Serj		status = hw->phy.ops.read_reg(hw,
2629282289Serj					IXGBE_MDIO_GLOBAL_RES_PR_10,
2630282289Serj					IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2631282289Serj					&reg);
2632282289Serj
2633282289Serj		if (status != IXGBE_SUCCESS)
2634282289Serj			return status;
2635282289Serj
2636282289Serj		reg &= ~IXGBE_MDIO_POWER_UP_STALL;
2637282289Serj
2638282289Serj		status = hw->phy.ops.write_reg(hw,
2639282289Serj					IXGBE_MDIO_GLOBAL_RES_PR_10,
2640282289Serj					IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
2641282289Serj					reg);
2642282289Serj
2643282289Serj		if (status != IXGBE_SUCCESS)
2644282289Serj			return status;
2645282289Serj	}
2646282289Serj
2647282289Serj	return status;
2648282289Serj}
2649282289Serj
2650282289Serj/**
2651282289Serj *  ixgbe_setup_kr_x550em - Configure the KR PHY.
2652282289Serj *  @hw: pointer to hardware structure
2653282289Serj **/
2654282289Serjs32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
2655282289Serj{
2656315333Serj	/* leave link alone for 2.5G */
2657315333Serj	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
2658315333Serj		return IXGBE_SUCCESS;
2659315333Serj
2660282289Serj	return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised);
2661282289Serj}
2662282289Serj
2663282289Serj/**
2664282289Serj *  ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP
2665282289Serj *  @hw: pointer to hardware structure
2666282289Serj *
2667282289Serj *  Configure the external PHY and the integrated KR PHY for SFP support.
2668282289Serj **/
2669282289Serjs32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
2670282289Serj				    ixgbe_link_speed speed,
2671282289Serj				    bool autoneg_wait_to_complete)
2672282289Serj{
2673282289Serj	s32 ret_val;
2674282289Serj	u16 reg_slice, reg_val;
2675282289Serj	bool setup_linear = FALSE;
2676282289Serj	UNREFERENCED_1PARAMETER(autoneg_wait_to_complete);
2677282289Serj
2678282289Serj	/* Check if SFP module is supported and linear */
2679282289Serj	ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
2680282289Serj
2681282289Serj	/* If no SFP module present, then return success. Return success since
2682282289Serj	 * there is no reason to configure CS4227 and SFP not present error is
2683282289Serj	 * not excepted in the setup MAC link flow.
2684282289Serj	 */
2685282289Serj	if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
2686282289Serj		return IXGBE_SUCCESS;
2687282289Serj
2688282289Serj	if (ret_val != IXGBE_SUCCESS)
2689282289Serj		return ret_val;
2690282289Serj
2691315333Serj	/* Configure internal PHY for KR/KX. */
2692315333Serj	ixgbe_setup_kr_speed_x550em(hw, speed);
2693282289Serj
2694315333Serj	/* Configure CS4227 LINE side to proper mode. */
2695315333Serj	reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB +
2696315333Serj		    (hw->bus.lan_id << 12);
2697315333Serj	if (setup_linear)
2698315333Serj		reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
2699315333Serj	else
2700282289Serj		reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
2701315333Serj	ret_val = hw->link.ops.write_link(hw, hw->link.addr, reg_slice,
2702315333Serj					  reg_val);
2703282289Serj	return ret_val;
2704282289Serj}
2705282289Serj
2706282289Serj/**
2707315333Serj *  ixgbe_setup_sfi_x550a - Configure the internal PHY for native SFI mode
2708282289Serj *  @hw: pointer to hardware structure
2709282289Serj *  @speed: the link speed to force
2710282289Serj *
2711315333Serj *  Configures the integrated PHY for native SFI mode. Used to connect the
2712315333Serj *  internal PHY directly to an SFP cage, without autonegotiation.
2713282289Serj **/
2714315333Serjstatic s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
2715282289Serj{
2716315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
2717282289Serj	s32 status;
2718282289Serj	u32 reg_val;
2719282289Serj
2720315333Serj	/* Disable all AN and force speed to 10G Serial. */
2721315333Serj	status = mac->ops.read_iosf_sb_reg(hw,
2722315333Serj				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2723315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2724282289Serj	if (status != IXGBE_SUCCESS)
2725282289Serj		return status;
2726282289Serj
2727315333Serj	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN;
2728315333Serj	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN;
2729315333Serj	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN;
2730315333Serj	reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK;
2731282289Serj
2732282289Serj	/* Select forced link speed for internal PHY. */
2733282289Serj	switch (*speed) {
2734282289Serj	case IXGBE_LINK_SPEED_10GB_FULL:
2735315333Serj		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_10G;
2736282289Serj		break;
2737282289Serj	case IXGBE_LINK_SPEED_1GB_FULL:
2738315333Serj		reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G;
2739282289Serj		break;
2740282289Serj	default:
2741315333Serj		/* Other link speeds are not supported by internal PHY. */
2742282289Serj		return IXGBE_ERR_LINK_SETUP;
2743282289Serj	}
2744282289Serj
2745315333Serj	status = mac->ops.write_iosf_sb_reg(hw,
2746315333Serj				IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2747315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2748282289Serj
2749315333Serj	/* Toggle port SW reset by AN reset. */
2750315333Serj	status = ixgbe_restart_an_internal_phy_x550em(hw);
2751315333Serj
2752315333Serj	return status;
2753315333Serj}
2754315333Serj
2755315333Serj/**
2756315333Serj *  ixgbe_setup_mac_link_sfp_x550a - Setup internal PHY for SFP
2757315333Serj *  @hw: pointer to hardware structure
2758315333Serj *
2759315333Serj *  Configure the the integrated PHY for SFP support.
2760315333Serj **/
2761315333Serjs32 ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw,
2762315333Serj				    ixgbe_link_speed speed,
2763315333Serj				    bool autoneg_wait_to_complete)
2764315333Serj{
2765315333Serj	s32 ret_val;
2766315333Serj	u16 reg_phy_ext;
2767315333Serj	bool setup_linear = FALSE;
2768315333Serj	u32 reg_slice, reg_phy_int, slice_offset;
2769315333Serj
2770315333Serj	UNREFERENCED_1PARAMETER(autoneg_wait_to_complete);
2771315333Serj
2772315333Serj	/* Check if SFP module is supported and linear */
2773315333Serj	ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
2774315333Serj
2775315333Serj	/* If no SFP module present, then return success. Return success since
2776315333Serj	 * SFP not present error is not excepted in the setup MAC link flow.
2777315333Serj	 */
2778315333Serj	if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
2779315333Serj		return IXGBE_SUCCESS;
2780315333Serj
2781315333Serj	if (ret_val != IXGBE_SUCCESS)
2782315333Serj		return ret_val;
2783315333Serj
2784315333Serj	if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) {
2785315333Serj		/* Configure internal PHY for native SFI based on module type */
2786315333Serj		ret_val = hw->mac.ops.read_iosf_sb_reg(hw,
2787315333Serj				   IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2788315333Serj				   IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_phy_int);
2789315333Serj
2790315333Serj		if (ret_val != IXGBE_SUCCESS)
2791315333Serj			return ret_val;
2792315333Serj
2793315333Serj		reg_phy_int &= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA;
2794315333Serj		if (!setup_linear)
2795315333Serj			reg_phy_int |= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_SR;
2796315333Serj
2797315333Serj		ret_val = hw->mac.ops.write_iosf_sb_reg(hw,
2798315333Serj				   IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id),
2799315333Serj				   IXGBE_SB_IOSF_TARGET_KR_PHY, reg_phy_int);
2800315333Serj
2801315333Serj		if (ret_val != IXGBE_SUCCESS)
2802315333Serj			return ret_val;
2803315333Serj
2804315333Serj		/* Setup SFI internal link. */
2805315333Serj		ret_val = ixgbe_setup_sfi_x550a(hw, &speed);
2806315333Serj	} else {
2807315333Serj		/* Configure internal PHY for KR/KX. */
2808315333Serj		ixgbe_setup_kr_speed_x550em(hw, speed);
2809315333Serj
2810315333Serj		if (hw->phy.addr == 0x0 || hw->phy.addr == 0xFFFF) {
2811315333Serj			/* Find Address */
2812315333Serj			DEBUGOUT("Invalid NW_MNG_IF_SEL.MDIO_PHY_ADD value\n");
2813315333Serj			return IXGBE_ERR_PHY_ADDR_INVALID;
2814315333Serj		}
2815315333Serj
2816315333Serj		/* Get external PHY SKU id */
2817315333Serj		ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU,
2818315333Serj					IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
2819315333Serj
2820315333Serj		if (ret_val != IXGBE_SUCCESS)
2821315333Serj			return ret_val;
2822315333Serj
2823315333Serj		/* When configuring quad port CS4223, the MAC instance is part
2824315333Serj		 * of the slice offset.
2825315333Serj		 */
2826315333Serj		if (reg_phy_ext == IXGBE_CS4223_SKU_ID)
2827315333Serj			slice_offset = (hw->bus.lan_id +
2828315333Serj					(hw->bus.instance_id << 1)) << 12;
2829315333Serj		else
2830315333Serj			slice_offset = hw->bus.lan_id << 12;
2831315333Serj
2832315333Serj		/* Configure CS4227/CS4223 LINE side to proper mode. */
2833315333Serj		reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset;
2834315333Serj
2835315333Serj		ret_val = hw->phy.ops.read_reg(hw, reg_slice,
2836315333Serj					IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
2837315333Serj
2838315333Serj		if (ret_val != IXGBE_SUCCESS)
2839315333Serj			return ret_val;
2840315333Serj
2841315333Serj		reg_phy_ext &= ~((IXGBE_CS4227_EDC_MODE_CX1 << 1) |
2842315333Serj				 (IXGBE_CS4227_EDC_MODE_SR << 1));
2843315333Serj
2844315333Serj		if (setup_linear)
2845315333Serj			reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
2846315333Serj		else
2847315333Serj			reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
2848315333Serj		ret_val = hw->phy.ops.write_reg(hw, reg_slice,
2849315333Serj					 IXGBE_MDIO_ZERO_DEV_TYPE, reg_phy_ext);
2850315333Serj
2851315333Serj		/* Flush previous write with a read */
2852315333Serj		ret_val = hw->phy.ops.read_reg(hw, reg_slice,
2853315333Serj					IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
2854315333Serj	}
2855315333Serj	return ret_val;
2856315333Serj}
2857315333Serj
2858315333Serj/**
2859315333Serj *  ixgbe_setup_ixfi_x550em_x - MAC specific iXFI configuration
2860315333Serj *  @hw: pointer to hardware structure
2861315333Serj *
2862315333Serj *  iXfI configuration needed for ixgbe_mac_X550EM_x devices.
2863315333Serj **/
2864315333Serjstatic s32 ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw)
2865315333Serj{
2866315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
2867315333Serj	s32 status;
2868315333Serj	u32 reg_val;
2869315333Serj
2870282289Serj	/* Disable training protocol FSM. */
2871315333Serj	status = mac->ops.read_iosf_sb_reg(hw,
2872282289Serj				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
2873282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2874282289Serj	if (status != IXGBE_SUCCESS)
2875282289Serj		return status;
2876282289Serj	reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
2877315333Serj	status = mac->ops.write_iosf_sb_reg(hw,
2878282289Serj				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
2879282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2880282289Serj	if (status != IXGBE_SUCCESS)
2881282289Serj		return status;
2882282289Serj
2883282289Serj	/* Disable Flex from training TXFFE. */
2884315333Serj	status = mac->ops.read_iosf_sb_reg(hw,
2885282289Serj				IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
2886282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2887282289Serj	if (status != IXGBE_SUCCESS)
2888282289Serj		return status;
2889282289Serj	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
2890282289Serj	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
2891282289Serj	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
2892315333Serj	status = mac->ops.write_iosf_sb_reg(hw,
2893282289Serj				IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
2894282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2895282289Serj	if (status != IXGBE_SUCCESS)
2896282289Serj		return status;
2897315333Serj	status = mac->ops.read_iosf_sb_reg(hw,
2898282289Serj				IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
2899282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2900282289Serj	if (status != IXGBE_SUCCESS)
2901282289Serj		return status;
2902282289Serj	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
2903282289Serj	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
2904282289Serj	reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
2905315333Serj	status = mac->ops.write_iosf_sb_reg(hw,
2906282289Serj				IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
2907282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2908282289Serj	if (status != IXGBE_SUCCESS)
2909282289Serj		return status;
2910282289Serj
2911282289Serj	/* Enable override for coefficients. */
2912315333Serj	status = mac->ops.read_iosf_sb_reg(hw,
2913282289Serj				IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
2914282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2915282289Serj	if (status != IXGBE_SUCCESS)
2916282289Serj		return status;
2917282289Serj	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN;
2918282289Serj	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN;
2919282289Serj	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
2920282289Serj	reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
2921315333Serj	status = mac->ops.write_iosf_sb_reg(hw,
2922282289Serj				IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
2923282289Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2924315333Serj	return status;
2925315333Serj}
2926282289Serj
2927315333Serj/**
2928315333Serj *  ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
2929315333Serj *  @hw: pointer to hardware structure
2930315333Serj *  @speed: the link speed to force
2931315333Serj *
2932315333Serj *  Configures the integrated KR PHY to use iXFI mode. Used to connect an
2933315333Serj *  internal and external PHY at a specific speed, without autonegotiation.
2934315333Serj **/
2935315333Serjstatic s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
2936315333Serj{
2937315333Serj	struct ixgbe_mac_info *mac = &hw->mac;
2938315333Serj	s32 status;
2939315333Serj	u32 reg_val;
2940315333Serj
2941315333Serj	/* iXFI is only supported with X552 */
2942315333Serj	if (mac->type != ixgbe_mac_X550EM_x)
2943315333Serj		return IXGBE_ERR_LINK_SETUP;
2944315333Serj
2945315333Serj	/* Disable AN and force speed to 10G Serial. */
2946315333Serj	status = mac->ops.read_iosf_sb_reg(hw,
2947282289Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2948282289Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
2949282289Serj	if (status != IXGBE_SUCCESS)
2950282289Serj		return status;
2951315333Serj
2952315333Serj	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
2953315333Serj	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
2954315333Serj
2955315333Serj	/* Select forced link speed for internal PHY. */
2956315333Serj	switch (*speed) {
2957315333Serj	case IXGBE_LINK_SPEED_10GB_FULL:
2958315333Serj		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
2959315333Serj		break;
2960315333Serj	case IXGBE_LINK_SPEED_1GB_FULL:
2961315333Serj		reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
2962315333Serj		break;
2963315333Serj	default:
2964315333Serj		/* Other link speeds are not supported by internal KR PHY. */
2965315333Serj		return IXGBE_ERR_LINK_SETUP;
2966315333Serj	}
2967315333Serj
2968315333Serj	status = mac->ops.write_iosf_sb_reg(hw,
2969282289Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
2970282289Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
2971315333Serj	if (status != IXGBE_SUCCESS)
2972315333Serj		return status;
2973282289Serj
2974315333Serj	/* Additional configuration needed for x550em_x */
2975315333Serj	if (hw->mac.type == ixgbe_mac_X550EM_x) {
2976315333Serj		status = ixgbe_setup_ixfi_x550em_x(hw);
2977315333Serj		if (status != IXGBE_SUCCESS)
2978315333Serj			return status;
2979315333Serj	}
2980315333Serj
2981315333Serj	/* Toggle port SW reset by AN reset. */
2982315333Serj	status = ixgbe_restart_an_internal_phy_x550em(hw);
2983315333Serj
2984282289Serj	return status;
2985282289Serj}
2986282289Serj
2987282289Serj/**
2988282289Serj * ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status
2989282289Serj * @hw: address of hardware structure
2990282289Serj * @link_up: address of boolean to indicate link status
2991282289Serj *
2992282289Serj * Returns error code if unable to get link status.
2993282289Serj */
2994282289Serjstatic s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
2995282289Serj{
2996282289Serj	u32 ret;
2997282289Serj	u16 autoneg_status;
2998282289Serj
2999282289Serj	*link_up = FALSE;
3000282289Serj
3001282289Serj	/* read this twice back to back to indicate current status */
3002282289Serj	ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
3003282289Serj				   IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3004282289Serj				   &autoneg_status);
3005282289Serj	if (ret != IXGBE_SUCCESS)
3006282289Serj		return ret;
3007282289Serj
3008282289Serj	ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
3009282289Serj				   IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3010282289Serj				   &autoneg_status);
3011282289Serj	if (ret != IXGBE_SUCCESS)
3012282289Serj		return ret;
3013282289Serj
3014282289Serj	*link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS);
3015282289Serj
3016282289Serj	return IXGBE_SUCCESS;
3017282289Serj}
3018282289Serj
3019282289Serj/**
3020282289Serj * ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link
3021282289Serj * @hw: point to hardware structure
3022282289Serj *
3023282289Serj * Configures the link between the integrated KR PHY and the external X557 PHY
3024282289Serj * The driver will call this function when it gets a link status change
3025282289Serj * interrupt from the X557 PHY. This function configures the link speed
3026282289Serj * between the PHYs to match the link speed of the BASE-T link.
3027282289Serj *
3028282289Serj * A return of a non-zero value indicates an error, and the base driver should
3029282289Serj * not report link up.
3030282289Serj */
3031282289Serjs32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
3032282289Serj{
3033282289Serj	ixgbe_link_speed force_speed;
3034282289Serj	bool link_up;
3035282289Serj	u32 status;
3036282289Serj	u16 speed;
3037282289Serj
3038282289Serj	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
3039282289Serj		return IXGBE_ERR_CONFIG;
3040282289Serj
3041315333Serj	if (hw->mac.type == ixgbe_mac_X550EM_x &&
3042315333Serj	    !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
3043315333Serj		/* If link is down, there is no setup necessary so return  */
3044315333Serj		status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
3045315333Serj		if (status != IXGBE_SUCCESS)
3046315333Serj			return status;
3047282289Serj
3048315333Serj		if (!link_up)
3049315333Serj			return IXGBE_SUCCESS;
3050282289Serj
3051315333Serj		status = hw->phy.ops.read_reg(hw,
3052315333Serj					      IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
3053315333Serj					      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3054315333Serj					      &speed);
3055315333Serj		if (status != IXGBE_SUCCESS)
3056315333Serj			return status;
3057282289Serj
3058315333Serj		/* If link is still down - no setup is required so return */
3059315333Serj		status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
3060315333Serj		if (status != IXGBE_SUCCESS)
3061315333Serj			return status;
3062315333Serj		if (!link_up)
3063315333Serj			return IXGBE_SUCCESS;
3064282289Serj
3065315333Serj		/* clear everything but the speed and duplex bits */
3066315333Serj		speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
3067282289Serj
3068315333Serj		switch (speed) {
3069315333Serj		case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL:
3070315333Serj			force_speed = IXGBE_LINK_SPEED_10GB_FULL;
3071315333Serj			break;
3072315333Serj		case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL:
3073315333Serj			force_speed = IXGBE_LINK_SPEED_1GB_FULL;
3074315333Serj			break;
3075315333Serj		default:
3076315333Serj			/* Internal PHY does not support anything else */
3077315333Serj			return IXGBE_ERR_INVALID_LINK_SETTINGS;
3078315333Serj		}
3079315333Serj
3080315333Serj		return ixgbe_setup_ixfi_x550em(hw, &force_speed);
3081315333Serj	} else {
3082315333Serj		speed = IXGBE_LINK_SPEED_10GB_FULL |
3083315333Serj			IXGBE_LINK_SPEED_1GB_FULL;
3084315333Serj		return ixgbe_setup_kr_speed_x550em(hw, speed);
3085282289Serj	}
3086282289Serj}
3087282289Serj
3088282289Serj/**
3089282289Serj *  ixgbe_setup_phy_loopback_x550em - Configure the KR PHY for loopback.
3090282289Serj *  @hw: pointer to hardware structure
3091282289Serj *
3092282289Serj *  Configures the integrated KR PHY to use internal loopback mode.
3093282289Serj **/
3094282289Serjs32 ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw)
3095282289Serj{
3096282289Serj	s32 status;
3097282289Serj	u32 reg_val;
3098282289Serj
3099282289Serj	/* Disable AN and force speed to 10G Serial. */
3100315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
3101315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
3102315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
3103282289Serj	if (status != IXGBE_SUCCESS)
3104282289Serj		return status;
3105282289Serj	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
3106282289Serj	reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
3107282289Serj	reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
3108315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
3109315333Serj					IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
3110315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
3111282289Serj	if (status != IXGBE_SUCCESS)
3112282289Serj		return status;
3113282289Serj
3114282289Serj	/* Set near-end loopback clocks. */
3115315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
3116315333Serj				IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
3117315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
3118282289Serj	if (status != IXGBE_SUCCESS)
3119282289Serj		return status;
3120282289Serj	reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B;
3121282289Serj	reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS;
3122315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
3123315333Serj				IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
3124315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
3125282289Serj	if (status != IXGBE_SUCCESS)
3126282289Serj		return status;
3127282289Serj
3128282289Serj	/* Set loopback enable. */
3129315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
3130315333Serj				IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
3131315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
3132282289Serj	if (status != IXGBE_SUCCESS)
3133282289Serj		return status;
3134282289Serj	reg_val |= IXGBE_KRM_PMD_DFX_BURNIN_TX_RX_KR_LB_MASK;
3135315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
3136315333Serj				IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
3137315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
3138282289Serj	if (status != IXGBE_SUCCESS)
3139282289Serj		return status;
3140282289Serj
3141282289Serj	/* Training bypass. */
3142315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
3143315333Serj				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
3144315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
3145282289Serj	if (status != IXGBE_SUCCESS)
3146282289Serj		return status;
3147282289Serj	reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_PROTOCOL_BYPASS;
3148315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
3149315333Serj				IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
3150315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
3151282289Serj
3152282289Serj	return status;
3153282289Serj}
3154282289Serj
3155282289Serj/**
3156282289Serj *  ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command
3157282289Serj *  assuming that the semaphore is already obtained.
3158282289Serj *  @hw: pointer to hardware structure
3159282289Serj *  @offset: offset of  word in the EEPROM to read
3160282289Serj *  @data: word read from the EEPROM
3161282289Serj *
3162282289Serj *  Reads a 16 bit word from the EEPROM using the hostif.
3163282289Serj **/
3164315333Serjs32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
3165282289Serj{
3166315333Serj	const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM;
3167315333Serj	struct ixgbe_hic_read_shadow_ram buffer;
3168282289Serj	s32 status;
3169282289Serj
3170315333Serj	DEBUGFUNC("ixgbe_read_ee_hostif_X550");
3171282289Serj	buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
3172282289Serj	buffer.hdr.req.buf_lenh = 0;
3173282289Serj	buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
3174282289Serj	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
3175282289Serj
3176282289Serj	/* convert offset from words to bytes */
3177282289Serj	buffer.address = IXGBE_CPU_TO_BE32(offset * 2);
3178282289Serj	/* one word */
3179282289Serj	buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16));
3180282289Serj
3181315333Serj	status = hw->mac.ops.acquire_swfw_sync(hw, mask);
3182282289Serj	if (status)
3183282289Serj		return status;
3184282289Serj
3185315333Serj	status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer),
3186315333Serj				    IXGBE_HI_COMMAND_TIMEOUT);
3187315333Serj	if (!status) {
3188315333Serj		*data = (u16)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG,
3189315333Serj						  FW_NVM_DATA_OFFSET);
3190282289Serj	}
3191282289Serj
3192315333Serj	hw->mac.ops.release_swfw_sync(hw, mask);
3193282289Serj	return status;
3194282289Serj}
3195282289Serj
3196282289Serj/**
3197282289Serj *  ixgbe_read_ee_hostif_buffer_X550- Read EEPROM word(s) using hostif
3198282289Serj *  @hw: pointer to hardware structure
3199282289Serj *  @offset: offset of  word in the EEPROM to read
3200282289Serj *  @words: number of words
3201282289Serj *  @data: word(s) read from the EEPROM
3202282289Serj *
3203282289Serj *  Reads a 16 bit word(s) from the EEPROM using the hostif.
3204282289Serj **/
3205282289Serjs32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
3206282289Serj				     u16 offset, u16 words, u16 *data)
3207282289Serj{
3208315333Serj	const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM;
3209282289Serj	struct ixgbe_hic_read_shadow_ram buffer;
3210282289Serj	u32 current_word = 0;
3211282289Serj	u16 words_to_read;
3212282289Serj	s32 status;
3213282289Serj	u32 i;
3214282289Serj
3215282289Serj	DEBUGFUNC("ixgbe_read_ee_hostif_buffer_X550");
3216282289Serj
3217282289Serj	/* Take semaphore for the entire operation. */
3218315333Serj	status = hw->mac.ops.acquire_swfw_sync(hw, mask);
3219282289Serj	if (status) {
3220282289Serj		DEBUGOUT("EEPROM read buffer - semaphore failed\n");
3221282289Serj		return status;
3222282289Serj	}
3223315333Serj
3224282289Serj	while (words) {
3225282289Serj		if (words > FW_MAX_READ_BUFFER_SIZE / 2)
3226282289Serj			words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
3227282289Serj		else
3228282289Serj			words_to_read = words;
3229282289Serj
3230282289Serj		buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
3231282289Serj		buffer.hdr.req.buf_lenh = 0;
3232282289Serj		buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
3233282289Serj		buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
3234282289Serj
3235282289Serj		/* convert offset from words to bytes */
3236282289Serj		buffer.address = IXGBE_CPU_TO_BE32((offset + current_word) * 2);
3237282289Serj		buffer.length = IXGBE_CPU_TO_BE16(words_to_read * 2);
3238282289Serj
3239315333Serj		status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer),
3240315333Serj					    IXGBE_HI_COMMAND_TIMEOUT);
3241282289Serj
3242282289Serj		if (status) {
3243282289Serj			DEBUGOUT("Host interface command failed\n");
3244282289Serj			goto out;
3245282289Serj		}
3246282289Serj
3247282289Serj		for (i = 0; i < words_to_read; i++) {
3248282289Serj			u32 reg = IXGBE_FLEX_MNG + (FW_NVM_DATA_OFFSET << 2) +
3249282289Serj				  2 * i;
3250282289Serj			u32 value = IXGBE_READ_REG(hw, reg);
3251282289Serj
3252282289Serj			data[current_word] = (u16)(value & 0xffff);
3253282289Serj			current_word++;
3254282289Serj			i++;
3255282289Serj			if (i < words_to_read) {
3256282289Serj				value >>= 16;
3257282289Serj				data[current_word] = (u16)(value & 0xffff);
3258282289Serj				current_word++;
3259282289Serj			}
3260282289Serj		}
3261282289Serj		words -= words_to_read;
3262282289Serj	}
3263282289Serj
3264282289Serjout:
3265315333Serj	hw->mac.ops.release_swfw_sync(hw, mask);
3266282289Serj	return status;
3267282289Serj}
3268282289Serj
3269282289Serj/**
3270282289Serj *  ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
3271282289Serj *  @hw: pointer to hardware structure
3272282289Serj *  @offset: offset of  word in the EEPROM to write
3273282289Serj *  @data: word write to the EEPROM
3274282289Serj *
3275282289Serj *  Write a 16 bit word to the EEPROM using the hostif.
3276282289Serj **/
3277282289Serjs32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
3278282289Serj				    u16 data)
3279282289Serj{
3280282289Serj	s32 status;
3281282289Serj	struct ixgbe_hic_write_shadow_ram buffer;
3282282289Serj
3283282289Serj	DEBUGFUNC("ixgbe_write_ee_hostif_data_X550");
3284282289Serj
3285282289Serj	buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
3286282289Serj	buffer.hdr.req.buf_lenh = 0;
3287282289Serj	buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
3288282289Serj	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
3289282289Serj
3290282289Serj	 /* one word */
3291282289Serj	buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16));
3292282289Serj	buffer.data = data;
3293282289Serj	buffer.address = IXGBE_CPU_TO_BE32(offset * 2);
3294282289Serj
3295282289Serj	status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
3296282289Serj					      sizeof(buffer),
3297282289Serj					      IXGBE_HI_COMMAND_TIMEOUT, FALSE);
3298282289Serj
3299282289Serj	return status;
3300282289Serj}
3301282289Serj
3302282289Serj/**
3303282289Serj *  ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
3304282289Serj *  @hw: pointer to hardware structure
3305282289Serj *  @offset: offset of  word in the EEPROM to write
3306282289Serj *  @data: word write to the EEPROM
3307282289Serj *
3308282289Serj *  Write a 16 bit word to the EEPROM using the hostif.
3309282289Serj **/
3310282289Serjs32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset,
3311282289Serj			       u16 data)
3312282289Serj{
3313282289Serj	s32 status = IXGBE_SUCCESS;
3314282289Serj
3315282289Serj	DEBUGFUNC("ixgbe_write_ee_hostif_X550");
3316282289Serj
3317282289Serj	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
3318282289Serj	    IXGBE_SUCCESS) {
3319282289Serj		status = ixgbe_write_ee_hostif_data_X550(hw, offset, data);
3320282289Serj		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
3321282289Serj	} else {
3322282289Serj		DEBUGOUT("write ee hostif failed to get semaphore");
3323282289Serj		status = IXGBE_ERR_SWFW_SYNC;
3324282289Serj	}
3325282289Serj
3326282289Serj	return status;
3327282289Serj}
3328282289Serj
3329282289Serj/**
3330282289Serj *  ixgbe_write_ee_hostif_buffer_X550 - Write EEPROM word(s) using hostif
3331282289Serj *  @hw: pointer to hardware structure
3332282289Serj *  @offset: offset of  word in the EEPROM to write
3333282289Serj *  @words: number of words
3334282289Serj *  @data: word(s) write to the EEPROM
3335282289Serj *
3336282289Serj *  Write a 16 bit word(s) to the EEPROM using the hostif.
3337282289Serj **/
3338282289Serjs32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
3339282289Serj				      u16 offset, u16 words, u16 *data)
3340282289Serj{
3341282289Serj	s32 status = IXGBE_SUCCESS;
3342282289Serj	u32 i = 0;
3343282289Serj
3344282289Serj	DEBUGFUNC("ixgbe_write_ee_hostif_buffer_X550");
3345282289Serj
3346282289Serj	/* Take semaphore for the entire operation. */
3347282289Serj	status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
3348282289Serj	if (status != IXGBE_SUCCESS) {
3349282289Serj		DEBUGOUT("EEPROM write buffer - semaphore failed\n");
3350282289Serj		goto out;
3351282289Serj	}
3352282289Serj
3353282289Serj	for (i = 0; i < words; i++) {
3354282289Serj		status = ixgbe_write_ee_hostif_data_X550(hw, offset + i,
3355282289Serj							 data[i]);
3356282289Serj
3357282289Serj		if (status != IXGBE_SUCCESS) {
3358282289Serj			DEBUGOUT("Eeprom buffered write failed\n");
3359282289Serj			break;
3360282289Serj		}
3361282289Serj	}
3362282289Serj
3363282289Serj	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
3364282289Serjout:
3365282289Serj
3366282289Serj	return status;
3367282289Serj}
3368282289Serj
3369282289Serj/**
3370282289Serj * ixgbe_checksum_ptr_x550 - Checksum one pointer region
3371282289Serj * @hw: pointer to hardware structure
3372282289Serj * @ptr: pointer offset in eeprom
3373282289Serj * @size: size of section pointed by ptr, if 0 first word will be used as size
3374282289Serj * @csum: address of checksum to update
3375282289Serj *
3376282289Serj * Returns error status for any failure
3377282289Serj */
3378282289Serjstatic s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
3379282289Serj				   u16 size, u16 *csum, u16 *buffer,
3380282289Serj				   u32 buffer_size)
3381282289Serj{
3382282289Serj	u16 buf[256];
3383282289Serj	s32 status;
3384282289Serj	u16 length, bufsz, i, start;
3385282289Serj	u16 *local_buffer;
3386282289Serj
3387282289Serj	bufsz = sizeof(buf) / sizeof(buf[0]);
3388282289Serj
3389282289Serj	/* Read a chunk at the pointer location */
3390282289Serj	if (!buffer) {
3391282289Serj		status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf);
3392282289Serj		if (status) {
3393282289Serj			DEBUGOUT("Failed to read EEPROM image\n");
3394282289Serj			return status;
3395282289Serj		}
3396282289Serj		local_buffer = buf;
3397282289Serj	} else {
3398282289Serj		if (buffer_size < ptr)
3399282289Serj			return  IXGBE_ERR_PARAM;
3400282289Serj		local_buffer = &buffer[ptr];
3401282289Serj	}
3402282289Serj
3403282289Serj	if (size) {
3404282289Serj		start = 0;
3405282289Serj		length = size;
3406282289Serj	} else {
3407282289Serj		start = 1;
3408282289Serj		length = local_buffer[0];
3409282289Serj
3410282289Serj		/* Skip pointer section if length is invalid. */
3411282289Serj		if (length == 0xFFFF || length == 0 ||
3412282289Serj		    (ptr + length) >= hw->eeprom.word_size)
3413282289Serj			return IXGBE_SUCCESS;
3414282289Serj	}
3415282289Serj
3416282289Serj	if (buffer && ((u32)start + (u32)length > buffer_size))
3417282289Serj		return IXGBE_ERR_PARAM;
3418282289Serj
3419282289Serj	for (i = start; length; i++, length--) {
3420282289Serj		if (i == bufsz && !buffer) {
3421282289Serj			ptr += bufsz;
3422282289Serj			i = 0;
3423282289Serj			if (length < bufsz)
3424282289Serj				bufsz = length;
3425282289Serj
3426282289Serj			/* Read a chunk at the pointer location */
3427282289Serj			status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr,
3428282289Serj								  bufsz, buf);
3429282289Serj			if (status) {
3430282289Serj				DEBUGOUT("Failed to read EEPROM image\n");
3431282289Serj				return status;
3432282289Serj			}
3433282289Serj		}
3434282289Serj		*csum += local_buffer[i];
3435282289Serj	}
3436282289Serj	return IXGBE_SUCCESS;
3437282289Serj}
3438282289Serj
3439282289Serj/**
3440282289Serj *  ixgbe_calc_checksum_X550 - Calculates and returns the checksum
3441282289Serj *  @hw: pointer to hardware structure
3442282289Serj *  @buffer: pointer to buffer containing calculated checksum
3443282289Serj *  @buffer_size: size of buffer
3444282289Serj *
3445282289Serj *  Returns a negative error code on error, or the 16-bit checksum
3446282289Serj **/
3447282289Serjs32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size)
3448282289Serj{
3449282289Serj	u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1];
3450282289Serj	u16 *local_buffer;
3451282289Serj	s32 status;
3452282289Serj	u16 checksum = 0;
3453282289Serj	u16 pointer, i, size;
3454282289Serj
3455282289Serj	DEBUGFUNC("ixgbe_calc_eeprom_checksum_X550");
3456282289Serj
3457282289Serj	hw->eeprom.ops.init_params(hw);
3458282289Serj
3459282289Serj	if (!buffer) {
3460282289Serj		/* Read pointer area */
3461282289Serj		status = ixgbe_read_ee_hostif_buffer_X550(hw, 0,
3462282289Serj						     IXGBE_EEPROM_LAST_WORD + 1,
3463282289Serj						     eeprom_ptrs);
3464282289Serj		if (status) {
3465282289Serj			DEBUGOUT("Failed to read EEPROM image\n");
3466282289Serj			return status;
3467282289Serj		}
3468282289Serj		local_buffer = eeprom_ptrs;
3469282289Serj	} else {
3470282289Serj		if (buffer_size < IXGBE_EEPROM_LAST_WORD)
3471282289Serj			return IXGBE_ERR_PARAM;
3472282289Serj		local_buffer = buffer;
3473282289Serj	}
3474282289Serj
3475282289Serj	/*
3476282289Serj	 * For X550 hardware include 0x0-0x41 in the checksum, skip the
3477282289Serj	 * checksum word itself
3478282289Serj	 */
3479282289Serj	for (i = 0; i <= IXGBE_EEPROM_LAST_WORD; i++)
3480282289Serj		if (i != IXGBE_EEPROM_CHECKSUM)
3481282289Serj			checksum += local_buffer[i];
3482282289Serj
3483282289Serj	/*
3484282289Serj	 * Include all data from pointers 0x3, 0x6-0xE.  This excludes the
3485282289Serj	 * FW, PHY module, and PCIe Expansion/Option ROM pointers.
3486282289Serj	 */
3487282289Serj	for (i = IXGBE_PCIE_ANALOG_PTR_X550; i < IXGBE_FW_PTR; i++) {
3488282289Serj		if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
3489282289Serj			continue;
3490282289Serj
3491282289Serj		pointer = local_buffer[i];
3492282289Serj
3493282289Serj		/* Skip pointer section if the pointer is invalid. */
3494282289Serj		if (pointer == 0xFFFF || pointer == 0 ||
3495282289Serj		    pointer >= hw->eeprom.word_size)
3496282289Serj			continue;
3497282289Serj
3498282289Serj		switch (i) {
3499282289Serj		case IXGBE_PCIE_GENERAL_PTR:
3500282289Serj			size = IXGBE_IXGBE_PCIE_GENERAL_SIZE;
3501282289Serj			break;
3502282289Serj		case IXGBE_PCIE_CONFIG0_PTR:
3503282289Serj		case IXGBE_PCIE_CONFIG1_PTR:
3504282289Serj			size = IXGBE_PCIE_CONFIG_SIZE;
3505282289Serj			break;
3506282289Serj		default:
3507282289Serj			size = 0;
3508282289Serj			break;
3509282289Serj		}
3510282289Serj
3511282289Serj		status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum,
3512282289Serj						buffer, buffer_size);
3513282289Serj		if (status)
3514282289Serj			return status;
3515282289Serj	}
3516282289Serj
3517282289Serj	checksum = (u16)IXGBE_EEPROM_SUM - checksum;
3518282289Serj
3519282289Serj	return (s32)checksum;
3520282289Serj}
3521282289Serj
3522282289Serj/**
3523282289Serj *  ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum
3524282289Serj *  @hw: pointer to hardware structure
3525282289Serj *
3526282289Serj *  Returns a negative error code on error, or the 16-bit checksum
3527282289Serj **/
3528282289Serjs32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
3529282289Serj{
3530282289Serj	return ixgbe_calc_checksum_X550(hw, NULL, 0);
3531282289Serj}
3532282289Serj
3533282289Serj/**
3534282289Serj *  ixgbe_validate_eeprom_checksum_X550 - Validate EEPROM checksum
3535282289Serj *  @hw: pointer to hardware structure
3536282289Serj *  @checksum_val: calculated checksum
3537282289Serj *
3538282289Serj *  Performs checksum calculation and validates the EEPROM checksum.  If the
3539282289Serj *  caller does not need checksum_val, the value can be NULL.
3540282289Serj **/
3541282289Serjs32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val)
3542282289Serj{
3543282289Serj	s32 status;
3544282289Serj	u16 checksum;
3545282289Serj	u16 read_checksum = 0;
3546282289Serj
3547282289Serj	DEBUGFUNC("ixgbe_validate_eeprom_checksum_X550");
3548282289Serj
3549282289Serj	/* Read the first word from the EEPROM. If this times out or fails, do
3550282289Serj	 * not continue or we could be in for a very long wait while every
3551282289Serj	 * EEPROM read fails
3552282289Serj	 */
3553282289Serj	status = hw->eeprom.ops.read(hw, 0, &checksum);
3554282289Serj	if (status) {
3555282289Serj		DEBUGOUT("EEPROM read failed\n");
3556282289Serj		return status;
3557282289Serj	}
3558282289Serj
3559282289Serj	status = hw->eeprom.ops.calc_checksum(hw);
3560282289Serj	if (status < 0)
3561282289Serj		return status;
3562282289Serj
3563282289Serj	checksum = (u16)(status & 0xffff);
3564282289Serj
3565282289Serj	status = ixgbe_read_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
3566282289Serj					   &read_checksum);
3567282289Serj	if (status)
3568282289Serj		return status;
3569282289Serj
3570282289Serj	/* Verify read checksum from EEPROM is the same as
3571282289Serj	 * calculated checksum
3572282289Serj	 */
3573282289Serj	if (read_checksum != checksum) {
3574282289Serj		status = IXGBE_ERR_EEPROM_CHECKSUM;
3575282289Serj		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
3576282289Serj			     "Invalid EEPROM checksum");
3577282289Serj	}
3578282289Serj
3579282289Serj	/* If the user cares, return the calculated checksum */
3580282289Serj	if (checksum_val)
3581282289Serj		*checksum_val = checksum;
3582282289Serj
3583282289Serj	return status;
3584282289Serj}
3585282289Serj
3586282289Serj/**
3587282289Serj * ixgbe_update_eeprom_checksum_X550 - Updates the EEPROM checksum and flash
3588282289Serj * @hw: pointer to hardware structure
3589282289Serj *
3590282289Serj * After writing EEPROM to shadow RAM using EEWR register, software calculates
3591282289Serj * checksum and updates the EEPROM and instructs the hardware to update
3592282289Serj * the flash.
3593282289Serj **/
3594282289Serjs32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
3595282289Serj{
3596282289Serj	s32 status;
3597282289Serj	u16 checksum = 0;
3598282289Serj
3599282289Serj	DEBUGFUNC("ixgbe_update_eeprom_checksum_X550");
3600282289Serj
3601282289Serj	/* Read the first word from the EEPROM. If this times out or fails, do
3602282289Serj	 * not continue or we could be in for a very long wait while every
3603282289Serj	 * EEPROM read fails
3604282289Serj	 */
3605282289Serj	status = ixgbe_read_ee_hostif_X550(hw, 0, &checksum);
3606282289Serj	if (status) {
3607282289Serj		DEBUGOUT("EEPROM read failed\n");
3608282289Serj		return status;
3609282289Serj	}
3610282289Serj
3611282289Serj	status = ixgbe_calc_eeprom_checksum_X550(hw);
3612282289Serj	if (status < 0)
3613282289Serj		return status;
3614282289Serj
3615282289Serj	checksum = (u16)(status & 0xffff);
3616282289Serj
3617282289Serj	status = ixgbe_write_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
3618282289Serj					    checksum);
3619282289Serj	if (status)
3620282289Serj		return status;
3621282289Serj
3622282289Serj	status = ixgbe_update_flash_X550(hw);
3623282289Serj
3624282289Serj	return status;
3625282289Serj}
3626282289Serj
3627282289Serj/**
3628282289Serj *  ixgbe_update_flash_X550 - Instruct HW to copy EEPROM to Flash device
3629282289Serj *  @hw: pointer to hardware structure
3630282289Serj *
3631282289Serj *  Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash.
3632282289Serj **/
3633282289Serjs32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
3634282289Serj{
3635282289Serj	s32 status = IXGBE_SUCCESS;
3636282289Serj	union ixgbe_hic_hdr2 buffer;
3637282289Serj
3638282289Serj	DEBUGFUNC("ixgbe_update_flash_X550");
3639282289Serj
3640282289Serj	buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD;
3641282289Serj	buffer.req.buf_lenh = 0;
3642282289Serj	buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
3643282289Serj	buffer.req.checksum = FW_DEFAULT_CHECKSUM;
3644282289Serj
3645282289Serj	status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
3646282289Serj					      sizeof(buffer),
3647282289Serj					      IXGBE_HI_COMMAND_TIMEOUT, FALSE);
3648282289Serj
3649282289Serj	return status;
3650282289Serj}
3651282289Serj
3652282289Serj/**
3653282289Serj *  ixgbe_get_supported_physical_layer_X550em - Returns physical layer type
3654282289Serj *  @hw: pointer to hardware structure
3655282289Serj *
3656282289Serj *  Determines physical layer capabilities of the current configuration.
3657282289Serj **/
3658282289Serju32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw)
3659282289Serj{
3660282289Serj	u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
3661282289Serj	u16 ext_ability = 0;
3662282289Serj
3663282289Serj	DEBUGFUNC("ixgbe_get_supported_physical_layer_X550em");
3664282289Serj
3665282289Serj	hw->phy.ops.identify(hw);
3666282289Serj
3667282289Serj	switch (hw->phy.type) {
3668282289Serj	case ixgbe_phy_x550em_kr:
3669315333Serj	case ixgbe_phy_x550em_xfi:
3670282289Serj		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR |
3671282289Serj				 IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3672282289Serj		break;
3673282289Serj	case ixgbe_phy_x550em_kx4:
3674282289Serj		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
3675282289Serj				 IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3676282289Serj		break;
3677282289Serj	case ixgbe_phy_x550em_ext_t:
3678282289Serj		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY,
3679282289Serj				     IXGBE_MDIO_PMA_PMD_DEV_TYPE,
3680282289Serj				     &ext_ability);
3681282289Serj		if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY)
3682282289Serj			physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T;
3683282289Serj		if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY)
3684282289Serj			physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
3685282289Serj		break;
3686315333Serj	case ixgbe_phy_fw:
3687315333Serj		if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_1GB_FULL)
3688315333Serj			physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
3689315333Serj		if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_100_FULL)
3690315333Serj			physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX;
3691315333Serj		if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_10_FULL)
3692315333Serj			physical_layer |= IXGBE_PHYSICAL_LAYER_10BASE_T;
3693315333Serj		break;
3694315333Serj	case ixgbe_phy_sgmii:
3695315333Serj		physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX;
3696315333Serj		break;
3697282289Serj	default:
3698282289Serj		break;
3699282289Serj	}
3700282289Serj
3701282289Serj	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber)
3702282289Serj		physical_layer = ixgbe_get_supported_phy_sfp_layer_generic(hw);
3703282289Serj
3704282289Serj	return physical_layer;
3705282289Serj}
3706282289Serj
3707282289Serj/**
3708282289Serj * ixgbe_get_bus_info_x550em - Set PCI bus info
3709282289Serj * @hw: pointer to hardware structure
3710282289Serj *
3711282289Serj * Sets bus link width and speed to unknown because X550em is
3712282289Serj * not a PCI device.
3713282289Serj **/
3714282289Serjs32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw)
3715282289Serj{
3716282289Serj
3717282289Serj	DEBUGFUNC("ixgbe_get_bus_info_x550em");
3718282289Serj
3719282289Serj	hw->bus.width = ixgbe_bus_width_unknown;
3720282289Serj	hw->bus.speed = ixgbe_bus_speed_unknown;
3721282289Serj
3722282289Serj	hw->mac.ops.set_lan_id(hw);
3723282289Serj
3724282289Serj	return IXGBE_SUCCESS;
3725282289Serj}
3726282289Serj
3727282289Serj/**
3728282289Serj * ixgbe_disable_rx_x550 - Disable RX unit
3729282289Serj *
3730282289Serj * Enables the Rx DMA unit for x550
3731282289Serj **/
3732282289Serjvoid ixgbe_disable_rx_x550(struct ixgbe_hw *hw)
3733282289Serj{
3734282289Serj	u32 rxctrl, pfdtxgswc;
3735282289Serj	s32 status;
3736282289Serj	struct ixgbe_hic_disable_rxen fw_cmd;
3737282289Serj
3738282289Serj	DEBUGFUNC("ixgbe_enable_rx_dma_x550");
3739282289Serj
3740282289Serj	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
3741282289Serj	if (rxctrl & IXGBE_RXCTRL_RXEN) {
3742282289Serj		pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
3743282289Serj		if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
3744282289Serj			pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
3745282289Serj			IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
3746282289Serj			hw->mac.set_lben = TRUE;
3747282289Serj		} else {
3748282289Serj			hw->mac.set_lben = FALSE;
3749282289Serj		}
3750282289Serj
3751282289Serj		fw_cmd.hdr.cmd = FW_DISABLE_RXEN_CMD;
3752282289Serj		fw_cmd.hdr.buf_len = FW_DISABLE_RXEN_LEN;
3753282289Serj		fw_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
3754282289Serj		fw_cmd.port_number = (u8)hw->bus.lan_id;
3755282289Serj
3756282289Serj		status = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd,
3757282289Serj					sizeof(struct ixgbe_hic_disable_rxen),
3758282289Serj					IXGBE_HI_COMMAND_TIMEOUT, TRUE);
3759282289Serj
3760282289Serj		/* If we fail - disable RX using register write */
3761282289Serj		if (status) {
3762282289Serj			rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
3763282289Serj			if (rxctrl & IXGBE_RXCTRL_RXEN) {
3764282289Serj				rxctrl &= ~IXGBE_RXCTRL_RXEN;
3765282289Serj				IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
3766282289Serj			}
3767282289Serj		}
3768282289Serj	}
3769282289Serj}
3770282289Serj
3771282289Serj/**
3772282289Serj * ixgbe_enter_lplu_x550em - Transition to low power states
3773282289Serj *  @hw: pointer to hardware structure
3774282289Serj *
3775282289Serj * Configures Low Power Link Up on transition to low power states
3776282289Serj * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
3777282289Serj * X557 PHY immediately prior to entering LPLU.
3778282289Serj **/
3779282289Serjs32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw)
3780282289Serj{
3781282289Serj	u16 an_10g_cntl_reg, autoneg_reg, speed;
3782282289Serj	s32 status;
3783282289Serj	ixgbe_link_speed lcd_speed;
3784282289Serj	u32 save_autoneg;
3785282289Serj	bool link_up;
3786282289Serj
3787295524Ssbruno	/* SW LPLU not required on later HW revisions. */
3788315333Serj	if ((hw->mac.type == ixgbe_mac_X550EM_x) &&
3789315333Serj	    (IXGBE_FUSES0_REV_MASK &
3790315333Serj	     IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))))
3791295524Ssbruno		return IXGBE_SUCCESS;
3792295524Ssbruno
3793282289Serj	/* If blocked by MNG FW, then don't restart AN */
3794282289Serj	if (ixgbe_check_reset_blocked(hw))
3795282289Serj		return IXGBE_SUCCESS;
3796282289Serj
3797282289Serj	status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
3798282289Serj	if (status != IXGBE_SUCCESS)
3799282289Serj		return status;
3800282289Serj
3801282289Serj	status = ixgbe_read_eeprom(hw, NVM_INIT_CTRL_3, &hw->eeprom.ctrl_word_3);
3802282289Serj
3803282289Serj	if (status != IXGBE_SUCCESS)
3804282289Serj		return status;
3805282289Serj
3806282289Serj	/* If link is down, LPLU disabled in NVM, WoL disabled, or manageability
3807282289Serj	 * disabled, then force link down by entering low power mode.
3808282289Serj	 */
3809282289Serj	if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) ||
3810282289Serj	    !(hw->wol_enabled || ixgbe_mng_present(hw)))
3811282289Serj		return ixgbe_set_copper_phy_power(hw, FALSE);
3812282289Serj
3813282289Serj	/* Determine LCD */
3814282289Serj	status = ixgbe_get_lcd_t_x550em(hw, &lcd_speed);
3815282289Serj
3816282289Serj	if (status != IXGBE_SUCCESS)
3817282289Serj		return status;
3818282289Serj
3819282289Serj	/* If no valid LCD link speed, then force link down and exit. */
3820282289Serj	if (lcd_speed == IXGBE_LINK_SPEED_UNKNOWN)
3821282289Serj		return ixgbe_set_copper_phy_power(hw, FALSE);
3822282289Serj
3823282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
3824282289Serj				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3825282289Serj				      &speed);
3826282289Serj
3827282289Serj	if (status != IXGBE_SUCCESS)
3828282289Serj		return status;
3829282289Serj
3830282289Serj	/* If no link now, speed is invalid so take link down */
3831282289Serj	status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
3832282289Serj	if (status != IXGBE_SUCCESS)
3833282289Serj		return ixgbe_set_copper_phy_power(hw, FALSE);
3834282289Serj
3835282289Serj	/* clear everything but the speed bits */
3836282289Serj	speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK;
3837282289Serj
3838282289Serj	/* If current speed is already LCD, then exit. */
3839282289Serj	if (((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB) &&
3840282289Serj	     (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) ||
3841282289Serj	    ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) &&
3842282289Serj	     (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL)))
3843282289Serj		return status;
3844282289Serj
3845282289Serj	/* Clear AN completed indication */
3846282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM,
3847282289Serj				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3848282289Serj				      &autoneg_reg);
3849282289Serj
3850282289Serj	if (status != IXGBE_SUCCESS)
3851282289Serj		return status;
3852282289Serj
3853282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
3854282289Serj			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3855282289Serj			     &an_10g_cntl_reg);
3856282289Serj
3857282289Serj	if (status != IXGBE_SUCCESS)
3858282289Serj		return status;
3859282289Serj
3860282289Serj	status = hw->phy.ops.read_reg(hw,
3861282289Serj			     IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
3862282289Serj			     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3863282289Serj			     &autoneg_reg);
3864282289Serj
3865282289Serj	if (status != IXGBE_SUCCESS)
3866282289Serj		return status;
3867282289Serj
3868282289Serj	save_autoneg = hw->phy.autoneg_advertised;
3869282289Serj
3870282289Serj	/* Setup link at least common link speed */
3871282289Serj	status = hw->mac.ops.setup_link(hw, lcd_speed, FALSE);
3872282289Serj
3873282289Serj	/* restore autoneg from before setting lplu speed */
3874282289Serj	hw->phy.autoneg_advertised = save_autoneg;
3875282289Serj
3876282289Serj	return status;
3877282289Serj}
3878282289Serj
3879282289Serj/**
3880282289Serj * ixgbe_get_lcd_x550em - Determine lowest common denominator
3881282289Serj *  @hw: pointer to hardware structure
3882282289Serj *  @lcd_speed: pointer to lowest common link speed
3883282289Serj *
3884282289Serj * Determine lowest common link speed with link partner.
3885282289Serj **/
3886282289Serjs32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed)
3887282289Serj{
3888282289Serj	u16 an_lp_status;
3889282289Serj	s32 status;
3890282289Serj	u16 word = hw->eeprom.ctrl_word_3;
3891282289Serj
3892282289Serj	*lcd_speed = IXGBE_LINK_SPEED_UNKNOWN;
3893282289Serj
3894282289Serj	status = hw->phy.ops.read_reg(hw, IXGBE_AUTO_NEG_LP_STATUS,
3895282289Serj				      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
3896282289Serj				      &an_lp_status);
3897282289Serj
3898282289Serj	if (status != IXGBE_SUCCESS)
3899282289Serj		return status;
3900282289Serj
3901282289Serj	/* If link partner advertised 1G, return 1G */
3902282289Serj	if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) {
3903282289Serj		*lcd_speed = IXGBE_LINK_SPEED_1GB_FULL;
3904282289Serj		return status;
3905282289Serj	}
3906282289Serj
3907282289Serj	/* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */
3908282289Serj	if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) ||
3909282289Serj	    (word & NVM_INIT_CTRL_3_D10GMP_PORT0))
3910282289Serj		return status;
3911282289Serj
3912282289Serj	/* Link partner not capable of lower speeds, return 10G */
3913282289Serj	*lcd_speed = IXGBE_LINK_SPEED_10GB_FULL;
3914282289Serj	return status;
3915282289Serj}
3916282289Serj
3917282289Serj/**
3918282289Serj *  ixgbe_setup_fc_X550em - Set up flow control
3919282289Serj *  @hw: pointer to hardware structure
3920282289Serj *
3921282289Serj *  Called at init time to set up flow control.
3922282289Serj **/
3923282289Serjs32 ixgbe_setup_fc_X550em(struct ixgbe_hw *hw)
3924282289Serj{
3925282289Serj	s32 ret_val = IXGBE_SUCCESS;
3926282289Serj	u32 pause, asm_dir, reg_val;
3927282289Serj
3928282289Serj	DEBUGFUNC("ixgbe_setup_fc_X550em");
3929282289Serj
3930282289Serj	/* Validate the requested mode */
3931282289Serj	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
3932282289Serj		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
3933282289Serj			"ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
3934282289Serj		ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
3935282289Serj		goto out;
3936282289Serj	}
3937282289Serj
3938282289Serj	/* 10gig parts do not have a word in the EEPROM to determine the
3939282289Serj	 * default flow control setting, so we explicitly set it to full.
3940282289Serj	 */
3941282289Serj	if (hw->fc.requested_mode == ixgbe_fc_default)
3942282289Serj		hw->fc.requested_mode = ixgbe_fc_full;
3943282289Serj
3944282289Serj	/* Determine PAUSE and ASM_DIR bits. */
3945282289Serj	switch (hw->fc.requested_mode) {
3946282289Serj	case ixgbe_fc_none:
3947282289Serj		pause = 0;
3948282289Serj		asm_dir = 0;
3949282289Serj		break;
3950282289Serj	case ixgbe_fc_tx_pause:
3951282289Serj		pause = 0;
3952282289Serj		asm_dir = 1;
3953282289Serj		break;
3954282289Serj	case ixgbe_fc_rx_pause:
3955282289Serj		/* Rx Flow control is enabled and Tx Flow control is
3956282289Serj		 * disabled by software override. Since there really
3957282289Serj		 * isn't a way to advertise that we are capable of RX
3958282289Serj		 * Pause ONLY, we will advertise that we support both
3959282289Serj		 * symmetric and asymmetric Rx PAUSE, as such we fall
3960282289Serj		 * through to the fc_full statement.  Later, we will
3961282289Serj		 * disable the adapter's ability to send PAUSE frames.
3962282289Serj		 */
3963282289Serj	case ixgbe_fc_full:
3964282289Serj		pause = 1;
3965282289Serj		asm_dir = 1;
3966282289Serj		break;
3967282289Serj	default:
3968282289Serj		ERROR_REPORT1(IXGBE_ERROR_ARGUMENT,
3969282289Serj			"Flow control param set incorrectly\n");
3970282289Serj		ret_val = IXGBE_ERR_CONFIG;
3971282289Serj		goto out;
3972282289Serj	}
3973282289Serj
3974315333Serj	switch (hw->device_id) {
3975315333Serj	case IXGBE_DEV_ID_X550EM_X_KR:
3976315333Serj	case IXGBE_DEV_ID_X550EM_A_KR:
3977315333Serj	case IXGBE_DEV_ID_X550EM_A_KR_L:
3978315333Serj		ret_val = hw->mac.ops.read_iosf_sb_reg(hw,
3979315333Serj					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3980315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
3981282289Serj		if (ret_val != IXGBE_SUCCESS)
3982282289Serj			goto out;
3983282289Serj		reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
3984282289Serj			IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
3985282289Serj		if (pause)
3986282289Serj			reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
3987282289Serj		if (asm_dir)
3988282289Serj			reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
3989315333Serj		ret_val = hw->mac.ops.write_iosf_sb_reg(hw,
3990315333Serj					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
3991315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
3992282289Serj
3993295524Ssbruno		/* This device does not fully support AN. */
3994295524Ssbruno		hw->fc.disable_fc_autoneg = TRUE;
3995315333Serj		break;
3996315333Serj	default:
3997315333Serj		break;
3998282289Serj	}
3999282289Serj
4000282289Serjout:
4001282289Serj	return ret_val;
4002282289Serj}
4003282289Serj
4004282289Serj/**
4005315333Serj *  ixgbe_fc_autoneg_backplane_x550em_a - Enable flow control IEEE clause 37
4006315333Serj *  @hw: pointer to hardware structure
4007315333Serj *
4008315333Serj *  Enable flow control according to IEEE clause 37.
4009315333Serj **/
4010315333Serjvoid ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw)
4011315333Serj{
4012315333Serj	u32 link_s1, lp_an_page_low, an_cntl_1;
4013315333Serj	s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
4014315333Serj	ixgbe_link_speed speed;
4015315333Serj	bool link_up;
4016315333Serj
4017315333Serj	/* AN should have completed when the cable was plugged in.
4018315333Serj	 * Look for reasons to bail out.  Bail out if:
4019315333Serj	 * - FC autoneg is disabled, or if
4020315333Serj	 * - link is not up.
4021315333Serj	 */
4022315333Serj	if (hw->fc.disable_fc_autoneg) {
4023315333Serj		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
4024315333Serj			     "Flow control autoneg is disabled");
4025315333Serj		goto out;
4026315333Serj	}
4027315333Serj
4028315333Serj	hw->mac.ops.check_link(hw, &speed, &link_up, FALSE);
4029315333Serj	if (!link_up) {
4030315333Serj		ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down");
4031315333Serj		goto out;
4032315333Serj	}
4033315333Serj
4034315333Serj	/* Check at auto-negotiation has completed */
4035315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
4036315333Serj					IXGBE_KRM_LINK_S1(hw->bus.lan_id),
4037315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, &link_s1);
4038315333Serj
4039315333Serj	if (status != IXGBE_SUCCESS ||
4040315333Serj	    (link_s1 & IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE) == 0) {
4041315333Serj		DEBUGOUT("Auto-Negotiation did not complete\n");
4042315333Serj		status = IXGBE_ERR_FC_NOT_NEGOTIATED;
4043315333Serj		goto out;
4044315333Serj	}
4045315333Serj
4046315333Serj	/* Read the 10g AN autoc and LP ability registers and resolve
4047315333Serj	 * local flow control settings accordingly
4048315333Serj	 */
4049315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
4050315333Serj				IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
4051315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl_1);
4052315333Serj
4053315333Serj	if (status != IXGBE_SUCCESS) {
4054315333Serj		DEBUGOUT("Auto-Negotiation did not complete\n");
4055315333Serj		goto out;
4056315333Serj	}
4057315333Serj
4058315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
4059315333Serj				IXGBE_KRM_LP_BASE_PAGE_HIGH(hw->bus.lan_id),
4060315333Serj				IXGBE_SB_IOSF_TARGET_KR_PHY, &lp_an_page_low);
4061315333Serj
4062315333Serj	if (status != IXGBE_SUCCESS) {
4063315333Serj		DEBUGOUT("Auto-Negotiation did not complete\n");
4064315333Serj		goto out;
4065315333Serj	}
4066315333Serj
4067315333Serj	status = ixgbe_negotiate_fc(hw, an_cntl_1, lp_an_page_low,
4068315333Serj				    IXGBE_KRM_AN_CNTL_1_SYM_PAUSE,
4069315333Serj				    IXGBE_KRM_AN_CNTL_1_ASM_PAUSE,
4070315333Serj				    IXGBE_KRM_LP_BASE_PAGE_HIGH_SYM_PAUSE,
4071315333Serj				    IXGBE_KRM_LP_BASE_PAGE_HIGH_ASM_PAUSE);
4072315333Serj
4073315333Serjout:
4074315333Serj	if (status == IXGBE_SUCCESS) {
4075315333Serj		hw->fc.fc_was_autonegged = TRUE;
4076315333Serj	} else {
4077315333Serj		hw->fc.fc_was_autonegged = FALSE;
4078315333Serj		hw->fc.current_mode = hw->fc.requested_mode;
4079315333Serj	}
4080315333Serj}
4081315333Serj
4082315333Serj/**
4083315333Serj *  ixgbe_fc_autoneg_fiber_x550em_a - passthrough FC settings
4084315333Serj *  @hw: pointer to hardware structure
4085315333Serj *
4086315333Serj **/
4087315333Serjvoid ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw)
4088315333Serj{
4089315333Serj	hw->fc.fc_was_autonegged = FALSE;
4090315333Serj	hw->fc.current_mode = hw->fc.requested_mode;
4091315333Serj}
4092315333Serj
4093315333Serj/**
4094315333Serj *  ixgbe_fc_autoneg_sgmii_x550em_a - Enable flow control IEEE clause 37
4095315333Serj *  @hw: pointer to hardware structure
4096315333Serj *
4097315333Serj *  Enable flow control according to IEEE clause 37.
4098315333Serj **/
4099315333Serjvoid ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw)
4100315333Serj{
4101315333Serj	s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
4102315333Serj	u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 };
4103315333Serj	ixgbe_link_speed speed;
4104315333Serj	bool link_up;
4105315333Serj
4106315333Serj	/* AN should have completed when the cable was plugged in.
4107315333Serj	 * Look for reasons to bail out.  Bail out if:
4108315333Serj	 * - FC autoneg is disabled, or if
4109315333Serj	 * - link is not up.
4110315333Serj	 */
4111315333Serj	if (hw->fc.disable_fc_autoneg) {
4112315333Serj		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
4113315333Serj			     "Flow control autoneg is disabled");
4114315333Serj		goto out;
4115315333Serj	}
4116315333Serj
4117315333Serj	hw->mac.ops.check_link(hw, &speed, &link_up, FALSE);
4118315333Serj	if (!link_up) {
4119315333Serj		ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down");
4120315333Serj		goto out;
4121315333Serj	}
4122315333Serj
4123315333Serj	/* Check if auto-negotiation has completed */
4124315333Serj	status = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &info);
4125315333Serj	if (status != IXGBE_SUCCESS ||
4126315333Serj	    !(info[0] & FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE)) {
4127315333Serj		DEBUGOUT("Auto-Negotiation did not complete\n");
4128315333Serj		status = IXGBE_ERR_FC_NOT_NEGOTIATED;
4129315333Serj		goto out;
4130315333Serj	}
4131315333Serj
4132315333Serj	/* Negotiate the flow control */
4133315333Serj	status = ixgbe_negotiate_fc(hw, info[0], info[0],
4134315333Serj				    FW_PHY_ACT_GET_LINK_INFO_FC_RX,
4135315333Serj				    FW_PHY_ACT_GET_LINK_INFO_FC_TX,
4136315333Serj				    FW_PHY_ACT_GET_LINK_INFO_LP_FC_RX,
4137315333Serj				    FW_PHY_ACT_GET_LINK_INFO_LP_FC_TX);
4138315333Serj
4139315333Serjout:
4140315333Serj	if (status == IXGBE_SUCCESS) {
4141315333Serj		hw->fc.fc_was_autonegged = TRUE;
4142315333Serj	} else {
4143315333Serj		hw->fc.fc_was_autonegged = FALSE;
4144315333Serj		hw->fc.current_mode = hw->fc.requested_mode;
4145315333Serj	}
4146315333Serj}
4147315333Serj
4148315333Serj/**
4149315333Serj *  ixgbe_setup_fc_backplane_x550em_a - Set up flow control
4150315333Serj *  @hw: pointer to hardware structure
4151315333Serj *
4152315333Serj *  Called at init time to set up flow control.
4153315333Serj **/
4154315333Serjs32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw)
4155315333Serj{
4156315333Serj	s32 status = IXGBE_SUCCESS;
4157315333Serj	u32 an_cntl = 0;
4158315333Serj
4159315333Serj	DEBUGFUNC("ixgbe_setup_fc_backplane_x550em_a");
4160315333Serj
4161315333Serj	/* Validate the requested mode */
4162315333Serj	if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
4163315333Serj		ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
4164315333Serj			      "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
4165315333Serj		return IXGBE_ERR_INVALID_LINK_SETTINGS;
4166315333Serj	}
4167315333Serj
4168315333Serj	if (hw->fc.requested_mode == ixgbe_fc_default)
4169315333Serj		hw->fc.requested_mode = ixgbe_fc_full;
4170315333Serj
4171315333Serj	/* Set up the 1G and 10G flow control advertisement registers so the
4172315333Serj	 * HW will be able to do FC autoneg once the cable is plugged in.  If
4173315333Serj	 * we link at 10G, the 1G advertisement is harmless and vice versa.
4174315333Serj	 */
4175315333Serj	status = hw->mac.ops.read_iosf_sb_reg(hw,
4176315333Serj					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
4177315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl);
4178315333Serj
4179315333Serj	if (status != IXGBE_SUCCESS) {
4180315333Serj		DEBUGOUT("Auto-Negotiation did not complete\n");
4181315333Serj		return status;
4182315333Serj	}
4183315333Serj
4184315333Serj	/* The possible values of fc.requested_mode are:
4185315333Serj	 * 0: Flow control is completely disabled
4186315333Serj	 * 1: Rx flow control is enabled (we can receive pause frames,
4187315333Serj	 *    but not send pause frames).
4188315333Serj	 * 2: Tx flow control is enabled (we can send pause frames but
4189315333Serj	 *    we do not support receiving pause frames).
4190315333Serj	 * 3: Both Rx and Tx flow control (symmetric) are enabled.
4191315333Serj	 * other: Invalid.
4192315333Serj	 */
4193315333Serj	switch (hw->fc.requested_mode) {
4194315333Serj	case ixgbe_fc_none:
4195315333Serj		/* Flow control completely disabled by software override. */
4196315333Serj		an_cntl &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
4197315333Serj			     IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
4198315333Serj		break;
4199315333Serj	case ixgbe_fc_tx_pause:
4200315333Serj		/* Tx Flow control is enabled, and Rx Flow control is
4201315333Serj		 * disabled by software override.
4202315333Serj		 */
4203315333Serj		an_cntl |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
4204315333Serj		an_cntl &= ~IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
4205315333Serj		break;
4206315333Serj	case ixgbe_fc_rx_pause:
4207315333Serj		/* Rx Flow control is enabled and Tx Flow control is
4208315333Serj		 * disabled by software override. Since there really
4209315333Serj		 * isn't a way to advertise that we are capable of RX
4210315333Serj		 * Pause ONLY, we will advertise that we support both
4211315333Serj		 * symmetric and asymmetric Rx PAUSE, as such we fall
4212315333Serj		 * through to the fc_full statement.  Later, we will
4213315333Serj		 * disable the adapter's ability to send PAUSE frames.
4214315333Serj		 */
4215315333Serj	case ixgbe_fc_full:
4216315333Serj		/* Flow control (both Rx and Tx) is enabled by SW override. */
4217315333Serj		an_cntl |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
4218315333Serj			   IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
4219315333Serj		break;
4220315333Serj	default:
4221315333Serj		ERROR_REPORT1(IXGBE_ERROR_ARGUMENT,
4222315333Serj			      "Flow control param set incorrectly\n");
4223315333Serj		return IXGBE_ERR_CONFIG;
4224315333Serj	}
4225315333Serj
4226315333Serj	status = hw->mac.ops.write_iosf_sb_reg(hw,
4227315333Serj					IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
4228315333Serj					IXGBE_SB_IOSF_TARGET_KR_PHY, an_cntl);
4229315333Serj
4230315333Serj	/* Restart auto-negotiation. */
4231315333Serj	status = ixgbe_restart_an_internal_phy_x550em(hw);
4232315333Serj
4233315333Serj	return status;
4234315333Serj}
4235315333Serj
4236315333Serj/**
4237282289Serj * ixgbe_set_mux - Set mux for port 1 access with CS4227
4238282289Serj * @hw: pointer to hardware structure
4239282289Serj * @state: set mux if 1, clear if 0
4240282289Serj */
4241282289Serjstatic void ixgbe_set_mux(struct ixgbe_hw *hw, u8 state)
4242282289Serj{
4243282289Serj	u32 esdp;
4244282289Serj
4245282289Serj	if (!hw->bus.lan_id)
4246282289Serj		return;
4247282289Serj	esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
4248282289Serj	if (state)
4249282289Serj		esdp |= IXGBE_ESDP_SDP1;
4250282289Serj	else
4251282289Serj		esdp &= ~IXGBE_ESDP_SDP1;
4252282289Serj	IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
4253282289Serj	IXGBE_WRITE_FLUSH(hw);
4254282289Serj}
4255282289Serj
4256282289Serj/**
4257282289Serj *  ixgbe_acquire_swfw_sync_X550em - Acquire SWFW semaphore
4258282289Serj *  @hw: pointer to hardware structure
4259282289Serj *  @mask: Mask to specify which semaphore to acquire
4260282289Serj *
4261282289Serj *  Acquires the SWFW semaphore and sets the I2C MUX
4262282289Serj **/
4263282289Serjs32 ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask)
4264282289Serj{
4265282289Serj	s32 status;
4266282289Serj
4267282289Serj	DEBUGFUNC("ixgbe_acquire_swfw_sync_X550em");
4268282289Serj
4269282289Serj	status = ixgbe_acquire_swfw_sync_X540(hw, mask);
4270282289Serj	if (status)
4271282289Serj		return status;
4272282289Serj
4273282289Serj	if (mask & IXGBE_GSSR_I2C_MASK)
4274282289Serj		ixgbe_set_mux(hw, 1);
4275282289Serj
4276282289Serj	return IXGBE_SUCCESS;
4277282289Serj}
4278282289Serj
4279282289Serj/**
4280282289Serj *  ixgbe_release_swfw_sync_X550em - Release SWFW semaphore
4281282289Serj *  @hw: pointer to hardware structure
4282282289Serj *  @mask: Mask to specify which semaphore to release
4283282289Serj *
4284282289Serj *  Releases the SWFW semaphore and sets the I2C MUX
4285282289Serj **/
4286282289Serjvoid ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask)
4287282289Serj{
4288282289Serj	DEBUGFUNC("ixgbe_release_swfw_sync_X550em");
4289282289Serj
4290282289Serj	if (mask & IXGBE_GSSR_I2C_MASK)
4291282289Serj		ixgbe_set_mux(hw, 0);
4292282289Serj
4293282289Serj	ixgbe_release_swfw_sync_X540(hw, mask);
4294282289Serj}
4295282289Serj
4296282289Serj/**
4297315333Serj *  ixgbe_acquire_swfw_sync_X550a - Acquire SWFW semaphore
4298315333Serj *  @hw: pointer to hardware structure
4299315333Serj *  @mask: Mask to specify which semaphore to acquire
4300315333Serj *
4301315333Serj *  Acquires the SWFW semaphore and get the shared phy token as needed
4302315333Serj */
4303315333Serjstatic s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask)
4304315333Serj{
4305315333Serj	u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM;
4306315333Serj	int retries = FW_PHY_TOKEN_RETRIES;
4307315333Serj	s32 status = IXGBE_SUCCESS;
4308315333Serj
4309315333Serj	DEBUGFUNC("ixgbe_acquire_swfw_sync_X550a");
4310315333Serj
4311315333Serj	while (--retries) {
4312315333Serj		status = IXGBE_SUCCESS;
4313315333Serj		if (hmask)
4314315333Serj			status = ixgbe_acquire_swfw_sync_X540(hw, hmask);
4315315333Serj		if (status) {
4316315333Serj			DEBUGOUT1("Could not acquire SWFW semaphore, Status = %d\n",
4317315333Serj				  status);
4318315333Serj			return status;
4319315333Serj		}
4320315333Serj		if (!(mask & IXGBE_GSSR_TOKEN_SM))
4321315333Serj			return IXGBE_SUCCESS;
4322315333Serj
4323315333Serj		status = ixgbe_get_phy_token(hw);
4324315333Serj		if (status == IXGBE_ERR_TOKEN_RETRY)
4325315333Serj			DEBUGOUT1("Could not acquire PHY token, Status = %d\n",
4326315333Serj				  status);
4327315333Serj
4328315333Serj		if (status == IXGBE_SUCCESS)
4329315333Serj			return IXGBE_SUCCESS;
4330315333Serj
4331315333Serj		if (hmask)
4332315333Serj			ixgbe_release_swfw_sync_X540(hw, hmask);
4333315333Serj
4334315333Serj		if (status != IXGBE_ERR_TOKEN_RETRY) {
4335315333Serj			DEBUGOUT1("Unable to retry acquiring the PHY token, Status = %d\n",
4336315333Serj				  status);
4337315333Serj			return status;
4338315333Serj		}
4339315333Serj	}
4340315333Serj
4341315333Serj	DEBUGOUT1("Semaphore acquisition retries failed!: PHY ID = 0x%08X\n",
4342315333Serj		  hw->phy.id);
4343315333Serj	return status;
4344315333Serj}
4345315333Serj
4346315333Serj/**
4347315333Serj *  ixgbe_release_swfw_sync_X550a - Release SWFW semaphore
4348315333Serj *  @hw: pointer to hardware structure
4349315333Serj *  @mask: Mask to specify which semaphore to release
4350315333Serj *
4351315333Serj *  Releases the SWFW semaphore and puts the shared phy token as needed
4352315333Serj */
4353315333Serjstatic void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask)
4354315333Serj{
4355315333Serj	u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM;
4356315333Serj
4357315333Serj	DEBUGFUNC("ixgbe_release_swfw_sync_X550a");
4358315333Serj
4359315333Serj	if (mask & IXGBE_GSSR_TOKEN_SM)
4360315333Serj		ixgbe_put_phy_token(hw);
4361315333Serj
4362315333Serj	if (hmask)
4363315333Serj		ixgbe_release_swfw_sync_X540(hw, hmask);
4364315333Serj}
4365315333Serj
4366315333Serj/**
4367315333Serj *  ixgbe_read_phy_reg_x550a  - Reads specified PHY register
4368315333Serj *  @hw: pointer to hardware structure
4369315333Serj *  @reg_addr: 32 bit address of PHY register to read
4370315333Serj *  @phy_data: Pointer to read data from PHY register
4371315333Serj *
4372315333Serj *  Reads a value from a specified PHY register using the SWFW lock and PHY
4373315333Serj *  Token. The PHY Token is needed since the MDIO is shared between to MAC
4374315333Serj *  instances.
4375315333Serj **/
4376315333Serjs32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
4377315333Serj			       u32 device_type, u16 *phy_data)
4378315333Serj{
4379315333Serj	s32 status;
4380315333Serj	u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM;
4381315333Serj
4382315333Serj	DEBUGFUNC("ixgbe_read_phy_reg_x550a");
4383315333Serj
4384315333Serj	if (hw->mac.ops.acquire_swfw_sync(hw, mask))
4385315333Serj		return IXGBE_ERR_SWFW_SYNC;
4386315333Serj
4387315333Serj	status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data);
4388315333Serj
4389315333Serj	hw->mac.ops.release_swfw_sync(hw, mask);
4390315333Serj
4391315333Serj	return status;
4392315333Serj}
4393315333Serj
4394315333Serj/**
4395315333Serj *  ixgbe_write_phy_reg_x550a - Writes specified PHY register
4396315333Serj *  @hw: pointer to hardware structure
4397315333Serj *  @reg_addr: 32 bit PHY register to write
4398315333Serj *  @device_type: 5 bit device type
4399315333Serj *  @phy_data: Data to write to the PHY register
4400315333Serj *
4401315333Serj *  Writes a value to specified PHY register using the SWFW lock and PHY Token.
4402315333Serj *  The PHY Token is needed since the MDIO is shared between to MAC instances.
4403315333Serj **/
4404315333Serjs32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
4405315333Serj				u32 device_type, u16 phy_data)
4406315333Serj{
4407315333Serj	s32 status;
4408315333Serj	u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM;
4409315333Serj
4410315333Serj	DEBUGFUNC("ixgbe_write_phy_reg_x550a");
4411315333Serj
4412315333Serj	if (hw->mac.ops.acquire_swfw_sync(hw, mask) == IXGBE_SUCCESS) {
4413315333Serj		status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type,
4414315333Serj						 phy_data);
4415315333Serj		hw->mac.ops.release_swfw_sync(hw, mask);
4416315333Serj	} else {
4417315333Serj		status = IXGBE_ERR_SWFW_SYNC;
4418315333Serj	}
4419315333Serj
4420315333Serj	return status;
4421315333Serj}
4422315333Serj
4423315333Serj/**
4424282289Serj * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
4425282289Serj * @hw: pointer to hardware structure
4426282289Serj *
4427282289Serj * Handle external Base T PHY interrupt. If high temperature
4428282289Serj * failure alarm then return error, else if link status change
4429282289Serj * then setup internal/external PHY link
4430282289Serj *
4431282289Serj * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
4432282289Serj * failure alarm, else return PHY access status.
4433282289Serj */
4434282289Serjs32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
4435282289Serj{
4436282289Serj	bool lsc;
4437282289Serj	u32 status;
4438282289Serj
4439282289Serj	status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
4440282289Serj
4441282289Serj	if (status != IXGBE_SUCCESS)
4442282289Serj		return status;
4443282289Serj
4444282289Serj	if (lsc)
4445282289Serj		return ixgbe_setup_internal_phy(hw);
4446282289Serj
4447282289Serj	return IXGBE_SUCCESS;
4448282289Serj}
4449282289Serj
4450282289Serj/**
4451282289Serj * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
4452282289Serj * @hw: pointer to hardware structure
4453282289Serj * @speed: new link speed
4454282289Serj * @autoneg_wait_to_complete: TRUE when waiting for completion is needed
4455282289Serj *
4456282289Serj * Setup internal/external PHY link speed based on link speed, then set
4457282289Serj * external PHY auto advertised link speed.
4458282289Serj *
4459282289Serj * Returns error status for any failure
4460282289Serj **/
4461282289Serjs32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
4462282289Serj				  ixgbe_link_speed speed,
4463282289Serj				  bool autoneg_wait_to_complete)
4464282289Serj{
4465282289Serj	s32 status;
4466282289Serj	ixgbe_link_speed force_speed;
4467282289Serj
4468282289Serj	DEBUGFUNC("ixgbe_setup_mac_link_t_X550em");
4469282289Serj
4470282289Serj	/* Setup internal/external PHY link speed to iXFI (10G), unless
4471282289Serj	 * only 1G is auto advertised then setup KX link.
4472282289Serj	 */
4473282289Serj	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
4474282289Serj		force_speed = IXGBE_LINK_SPEED_10GB_FULL;
4475282289Serj	else
4476282289Serj		force_speed = IXGBE_LINK_SPEED_1GB_FULL;
4477282289Serj
4478315333Serj	/* If X552 and internal link mode is XFI, then setup XFI internal link.
4479315333Serj	 */
4480315333Serj	if (hw->mac.type == ixgbe_mac_X550EM_x &&
4481315333Serj	    !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
4482282289Serj		status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
4483282289Serj
4484282289Serj		if (status != IXGBE_SUCCESS)
4485282289Serj			return status;
4486282289Serj	}
4487282289Serj
4488282289Serj	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete);
4489282289Serj}
4490282289Serj
4491282289Serj/**
4492282289Serj * ixgbe_check_link_t_X550em - Determine link and speed status
4493282289Serj * @hw: pointer to hardware structure
4494282289Serj * @speed: pointer to link speed
4495282289Serj * @link_up: TRUE when link is up
4496282289Serj * @link_up_wait_to_complete: bool used to wait for link up or not
4497282289Serj *
4498282289Serj * Check that both the MAC and X557 external PHY have link.
4499282289Serj **/
4500282289Serjs32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
4501282289Serj			      bool *link_up, bool link_up_wait_to_complete)
4502282289Serj{
4503282289Serj	u32 status;
4504315333Serj	u16 i, autoneg_status = 0;
4505282289Serj
4506282289Serj	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
4507282289Serj		return IXGBE_ERR_CONFIG;
4508282289Serj
4509282289Serj	status = ixgbe_check_mac_link_generic(hw, speed, link_up,
4510282289Serj					      link_up_wait_to_complete);
4511282289Serj
4512282289Serj	/* If check link fails or MAC link is not up, then return */
4513282289Serj	if (status != IXGBE_SUCCESS || !(*link_up))
4514282289Serj		return status;
4515282289Serj
4516282289Serj	/* MAC link is up, so check external PHY link.
4517315333Serj	 * X557 PHY. Link status is latching low, and can only be used to detect
4518315333Serj	 * link drop, and not the current status of the link without performing
4519315333Serj	 * back-to-back reads.
4520282289Serj	 */
4521315333Serj	for (i = 0; i < 2; i++) {
4522315333Serj		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
4523315333Serj					      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
4524315333Serj					      &autoneg_status);
4525282289Serj
4526315333Serj		if (status != IXGBE_SUCCESS)
4527315333Serj			return status;
4528315333Serj	}
4529282289Serj
4530282289Serj	/* If external PHY link is not up, then indicate link not up */
4531282289Serj	if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
4532282289Serj		*link_up = FALSE;
4533282289Serj
4534282289Serj	return IXGBE_SUCCESS;
4535282289Serj}
4536282289Serj
4537282289Serj/**
4538282289Serj *  ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI
4539282289Serj *  @hw: pointer to hardware structure
4540282289Serj **/
4541282289Serjs32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw)
4542282289Serj{
4543282289Serj	s32 status;
4544282289Serj
4545282289Serj	status = ixgbe_reset_phy_generic(hw);
4546282289Serj
4547282289Serj	if (status != IXGBE_SUCCESS)
4548282289Serj		return status;
4549282289Serj
4550282289Serj	/* Configure Link Status Alarm and Temperature Threshold interrupts */
4551282289Serj	return ixgbe_enable_lasi_ext_t_x550em(hw);
4552282289Serj}
4553282289Serj
4554282289Serj/**
4555282289Serj *  ixgbe_led_on_t_X550em - Turns on the software controllable LEDs.
4556282289Serj *  @hw: pointer to hardware structure
4557282289Serj *  @led_idx: led number to turn on
4558282289Serj **/
4559282289Serjs32 ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, u32 led_idx)
4560282289Serj{
4561282289Serj	u16 phy_data;
4562282289Serj
4563282289Serj	DEBUGFUNC("ixgbe_led_on_t_X550em");
4564282289Serj
4565282289Serj	if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
4566282289Serj		return IXGBE_ERR_PARAM;
4567282289Serj
4568282289Serj	/* To turn on the LED, set mode to ON. */
4569282289Serj	ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4570282289Serj			   IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data);
4571282289Serj	phy_data |= IXGBE_X557_LED_MANUAL_SET_MASK;
4572282289Serj	ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4573282289Serj			    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data);
4574282289Serj
4575282289Serj	return IXGBE_SUCCESS;
4576282289Serj}
4577282289Serj
4578282289Serj/**
4579282289Serj *  ixgbe_led_off_t_X550em - Turns off the software controllable LEDs.
4580282289Serj *  @hw: pointer to hardware structure
4581282289Serj *  @led_idx: led number to turn off
4582282289Serj **/
4583282289Serjs32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx)
4584282289Serj{
4585282289Serj	u16 phy_data;
4586282289Serj
4587282289Serj	DEBUGFUNC("ixgbe_led_off_t_X550em");
4588282289Serj
4589282289Serj	if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
4590282289Serj		return IXGBE_ERR_PARAM;
4591282289Serj
4592282289Serj	/* To turn on the LED, set mode to ON. */
4593282289Serj	ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4594282289Serj			   IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data);
4595282289Serj	phy_data &= ~IXGBE_X557_LED_MANUAL_SET_MASK;
4596282289Serj	ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
4597282289Serj			    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data);
4598282289Serj
4599282289Serj	return IXGBE_SUCCESS;
4600282289Serj}
4601282289Serj
4602315333Serj/**
4603315333Serj *  ixgbe_set_fw_drv_ver_x550 - Sends driver version to firmware
4604315333Serj *  @hw: pointer to the HW structure
4605315333Serj *  @maj: driver version major number
4606315333Serj *  @min: driver version minor number
4607315333Serj *  @build: driver version build number
4608315333Serj *  @sub: driver version sub build number
4609315333Serj *  @len: length of driver_ver string
4610315333Serj *  @driver_ver: driver string
4611315333Serj *
4612315333Serj *  Sends driver version number to firmware through the manageability
4613315333Serj *  block.  On success return IXGBE_SUCCESS
4614315333Serj *  else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring
4615315333Serj *  semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
4616315333Serj **/
4617315333Serjs32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
4618315333Serj			      u8 build, u8 sub, u16 len, const char *driver_ver)
4619315333Serj{
4620315333Serj	struct ixgbe_hic_drv_info2 fw_cmd;
4621315333Serj	s32 ret_val = IXGBE_SUCCESS;
4622315333Serj	int i;
4623315333Serj
4624315333Serj	DEBUGFUNC("ixgbe_set_fw_drv_ver_x550");
4625315333Serj
4626315333Serj	if ((len == 0) || (driver_ver == NULL) ||
4627315333Serj	   (len > sizeof(fw_cmd.driver_string)))
4628315333Serj		return IXGBE_ERR_INVALID_ARGUMENT;
4629315333Serj
4630315333Serj	fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO;
4631315333Serj	fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN + len;
4632315333Serj	fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
4633315333Serj	fw_cmd.port_num = (u8)hw->bus.func;
4634315333Serj	fw_cmd.ver_maj = maj;
4635315333Serj	fw_cmd.ver_min = min;
4636315333Serj	fw_cmd.ver_build = build;
4637315333Serj	fw_cmd.ver_sub = sub;
4638315333Serj	fw_cmd.hdr.checksum = 0;
4639315333Serj	memcpy(fw_cmd.driver_string, driver_ver, len);
4640315333Serj	fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd,
4641315333Serj				(FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len));
4642315333Serj
4643315333Serj	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
4644315333Serj		ret_val = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd,
4645315333Serj						       sizeof(fw_cmd),
4646315333Serj						       IXGBE_HI_COMMAND_TIMEOUT,
4647315333Serj						       TRUE);
4648315333Serj		if (ret_val != IXGBE_SUCCESS)
4649315333Serj			continue;
4650315333Serj
4651315333Serj		if (fw_cmd.hdr.cmd_or_resp.ret_status ==
4652315333Serj		    FW_CEM_RESP_STATUS_SUCCESS)
4653315333Serj			ret_val = IXGBE_SUCCESS;
4654315333Serj		else
4655315333Serj			ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND;
4656315333Serj
4657315333Serj		break;
4658315333Serj	}
4659315333Serj
4660315333Serj	return ret_val;
4661315333Serj}
4662