162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c)  2018 Intel Corporation */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/pci.h>
562306a36Sopenharmony_ci#include <linux/delay.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "igc_mac.h"
862306a36Sopenharmony_ci#include "igc_hw.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/**
1162306a36Sopenharmony_ci * igc_disable_pcie_master - Disables PCI-express master access
1262306a36Sopenharmony_ci * @hw: pointer to the HW structure
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Returns 0 (0) if successful, else returns -10
1562306a36Sopenharmony_ci * (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
1662306a36Sopenharmony_ci * the master requests to be disabled.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * Disables PCI-Express master access and verifies there are no pending
1962306a36Sopenharmony_ci * requests.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cis32 igc_disable_pcie_master(struct igc_hw *hw)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	s32 timeout = MASTER_DISABLE_TIMEOUT;
2462306a36Sopenharmony_ci	s32 ret_val = 0;
2562306a36Sopenharmony_ci	u32 ctrl;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
2862306a36Sopenharmony_ci	ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
2962306a36Sopenharmony_ci	wr32(IGC_CTRL, ctrl);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	while (timeout) {
3262306a36Sopenharmony_ci		if (!(rd32(IGC_STATUS) &
3362306a36Sopenharmony_ci		    IGC_STATUS_GIO_MASTER_ENABLE))
3462306a36Sopenharmony_ci			break;
3562306a36Sopenharmony_ci		usleep_range(2000, 3000);
3662306a36Sopenharmony_ci		timeout--;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (!timeout) {
4062306a36Sopenharmony_ci		hw_dbg("Master requests are pending.\n");
4162306a36Sopenharmony_ci		ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
4262306a36Sopenharmony_ci		goto out;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciout:
4662306a36Sopenharmony_ci	return ret_val;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/**
5062306a36Sopenharmony_ci * igc_init_rx_addrs - Initialize receive addresses
5162306a36Sopenharmony_ci * @hw: pointer to the HW structure
5262306a36Sopenharmony_ci * @rar_count: receive address registers
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * Setup the receive address registers by setting the base receive address
5562306a36Sopenharmony_ci * register to the devices MAC address and clearing all the other receive
5662306a36Sopenharmony_ci * address registers to 0.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_civoid igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN] = {0};
6162306a36Sopenharmony_ci	u32 i;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Setup the receive address */
6462306a36Sopenharmony_ci	hw_dbg("Programming MAC Address into RAR[0]\n");
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* Zero out the other (rar_entry_count - 1) receive addresses */
6962306a36Sopenharmony_ci	hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
7062306a36Sopenharmony_ci	for (i = 1; i < rar_count; i++)
7162306a36Sopenharmony_ci		hw->mac.ops.rar_set(hw, mac_addr, i);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/**
7562306a36Sopenharmony_ci * igc_set_fc_watermarks - Set flow control high/low watermarks
7662306a36Sopenharmony_ci * @hw: pointer to the HW structure
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * Sets the flow control high/low threshold (watermark) registers.  If
7962306a36Sopenharmony_ci * flow control XON frame transmission is enabled, then set XON frame
8062306a36Sopenharmony_ci * transmission as well.
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_cistatic s32 igc_set_fc_watermarks(struct igc_hw *hw)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	u32 fcrtl = 0, fcrth = 0;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Set the flow control receive threshold registers.  Normally,
8762306a36Sopenharmony_ci	 * these registers will be set to a default threshold that may be
8862306a36Sopenharmony_ci	 * adjusted later by the driver's runtime code.  However, if the
8962306a36Sopenharmony_ci	 * ability to transmit pause frames is not enabled, then these
9062306a36Sopenharmony_ci	 * registers will be set to 0.
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	if (hw->fc.current_mode & igc_fc_tx_pause) {
9362306a36Sopenharmony_ci		/* We need to set up the Receive Threshold high and low water
9462306a36Sopenharmony_ci		 * marks as well as (optionally) enabling the transmission of
9562306a36Sopenharmony_ci		 * XON frames.
9662306a36Sopenharmony_ci		 */
9762306a36Sopenharmony_ci		fcrtl = hw->fc.low_water;
9862306a36Sopenharmony_ci		if (hw->fc.send_xon)
9962306a36Sopenharmony_ci			fcrtl |= IGC_FCRTL_XONE;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		fcrth = hw->fc.high_water;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	wr32(IGC_FCRTL, fcrtl);
10462306a36Sopenharmony_ci	wr32(IGC_FCRTH, fcrth);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * igc_setup_link - Setup flow control and link settings
11162306a36Sopenharmony_ci * @hw: pointer to the HW structure
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci * Determines which flow control settings to use, then configures flow
11462306a36Sopenharmony_ci * control.  Calls the appropriate media-specific link configuration
11562306a36Sopenharmony_ci * function.  Assuming the adapter has a valid link partner, a valid link
11662306a36Sopenharmony_ci * should be established.  Assumes the hardware has previously been reset
11762306a36Sopenharmony_ci * and the transmitter and receiver are not enabled.
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_cis32 igc_setup_link(struct igc_hw *hw)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	s32 ret_val = 0;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* In the case of the phy reset being blocked, we already have a link.
12462306a36Sopenharmony_ci	 * We do not need to set it up again.
12562306a36Sopenharmony_ci	 */
12662306a36Sopenharmony_ci	if (igc_check_reset_block(hw))
12762306a36Sopenharmony_ci		goto out;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* If requested flow control is set to default, set flow control
13062306a36Sopenharmony_ci	 * to the both 'rx' and 'tx' pause frames.
13162306a36Sopenharmony_ci	 */
13262306a36Sopenharmony_ci	if (hw->fc.requested_mode == igc_fc_default)
13362306a36Sopenharmony_ci		hw->fc.requested_mode = igc_fc_full;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* We want to save off the original Flow Control configuration just
13662306a36Sopenharmony_ci	 * in case we get disconnected and then reconnected into a different
13762306a36Sopenharmony_ci	 * hub or switch with different Flow Control capabilities.
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	hw->fc.current_mode = hw->fc.requested_mode;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Call the necessary media_type subroutine to configure the link. */
14462306a36Sopenharmony_ci	ret_val = hw->mac.ops.setup_physical_interface(hw);
14562306a36Sopenharmony_ci	if (ret_val)
14662306a36Sopenharmony_ci		goto out;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* Initialize the flow control address, type, and PAUSE timer
14962306a36Sopenharmony_ci	 * registers to their default values.  This is done even if flow
15062306a36Sopenharmony_ci	 * control is disabled, because it does not hurt anything to
15162306a36Sopenharmony_ci	 * initialize these registers.
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci	hw_dbg("Initializing the Flow Control address, type and timer regs\n");
15462306a36Sopenharmony_ci	wr32(IGC_FCT, FLOW_CONTROL_TYPE);
15562306a36Sopenharmony_ci	wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
15662306a36Sopenharmony_ci	wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	wr32(IGC_FCTTV, hw->fc.pause_time);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ret_val = igc_set_fc_watermarks(hw);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciout:
16362306a36Sopenharmony_ci	return ret_val;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * igc_force_mac_fc - Force the MAC's flow control settings
16862306a36Sopenharmony_ci * @hw: pointer to the HW structure
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
17162306a36Sopenharmony_ci * device control register to reflect the adapter settings.  TFCE and RFCE
17262306a36Sopenharmony_ci * need to be explicitly set by software when a copper PHY is used because
17362306a36Sopenharmony_ci * autonegotiation is managed by the PHY rather than the MAC.  Software must
17462306a36Sopenharmony_ci * also configure these bits when link is forced on a fiber connection.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_cis32 igc_force_mac_fc(struct igc_hw *hw)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	s32 ret_val = 0;
17962306a36Sopenharmony_ci	u32 ctrl;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Because we didn't get link via the internal auto-negotiation
18462306a36Sopenharmony_ci	 * mechanism (we either forced link or we got link via PHY
18562306a36Sopenharmony_ci	 * auto-neg), we have to manually enable/disable transmit an
18662306a36Sopenharmony_ci	 * receive flow control.
18762306a36Sopenharmony_ci	 *
18862306a36Sopenharmony_ci	 * The "Case" statement below enables/disable flow control
18962306a36Sopenharmony_ci	 * according to the "hw->fc.current_mode" parameter.
19062306a36Sopenharmony_ci	 *
19162306a36Sopenharmony_ci	 * The possible values of the "fc" parameter are:
19262306a36Sopenharmony_ci	 *      0:  Flow control is completely disabled
19362306a36Sopenharmony_ci	 *      1:  Rx flow control is enabled (we can receive pause
19462306a36Sopenharmony_ci	 *          frames but not send pause frames).
19562306a36Sopenharmony_ci	 *      2:  Tx flow control is enabled (we can send pause frames
19662306a36Sopenharmony_ci	 *          but we do not receive pause frames).
19762306a36Sopenharmony_ci	 *      3:  Both Rx and TX flow control (symmetric) is enabled.
19862306a36Sopenharmony_ci	 *  other:  No other values should be possible at this point.
19962306a36Sopenharmony_ci	 */
20062306a36Sopenharmony_ci	hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	switch (hw->fc.current_mode) {
20362306a36Sopenharmony_ci	case igc_fc_none:
20462306a36Sopenharmony_ci		ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
20562306a36Sopenharmony_ci		break;
20662306a36Sopenharmony_ci	case igc_fc_rx_pause:
20762306a36Sopenharmony_ci		ctrl &= (~IGC_CTRL_TFCE);
20862306a36Sopenharmony_ci		ctrl |= IGC_CTRL_RFCE;
20962306a36Sopenharmony_ci		break;
21062306a36Sopenharmony_ci	case igc_fc_tx_pause:
21162306a36Sopenharmony_ci		ctrl &= (~IGC_CTRL_RFCE);
21262306a36Sopenharmony_ci		ctrl |= IGC_CTRL_TFCE;
21362306a36Sopenharmony_ci		break;
21462306a36Sopenharmony_ci	case igc_fc_full:
21562306a36Sopenharmony_ci		ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
21662306a36Sopenharmony_ci		break;
21762306a36Sopenharmony_ci	default:
21862306a36Sopenharmony_ci		hw_dbg("Flow control param set incorrectly\n");
21962306a36Sopenharmony_ci		ret_val = -IGC_ERR_CONFIG;
22062306a36Sopenharmony_ci		goto out;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	wr32(IGC_CTRL, ctrl);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciout:
22662306a36Sopenharmony_ci	return ret_val;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/**
23062306a36Sopenharmony_ci * igc_clear_hw_cntrs_base - Clear base hardware counters
23162306a36Sopenharmony_ci * @hw: pointer to the HW structure
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * Clears the base hardware counters by reading the counter registers.
23462306a36Sopenharmony_ci */
23562306a36Sopenharmony_civoid igc_clear_hw_cntrs_base(struct igc_hw *hw)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	rd32(IGC_CRCERRS);
23862306a36Sopenharmony_ci	rd32(IGC_MPC);
23962306a36Sopenharmony_ci	rd32(IGC_SCC);
24062306a36Sopenharmony_ci	rd32(IGC_ECOL);
24162306a36Sopenharmony_ci	rd32(IGC_MCC);
24262306a36Sopenharmony_ci	rd32(IGC_LATECOL);
24362306a36Sopenharmony_ci	rd32(IGC_COLC);
24462306a36Sopenharmony_ci	rd32(IGC_RERC);
24562306a36Sopenharmony_ci	rd32(IGC_DC);
24662306a36Sopenharmony_ci	rd32(IGC_RLEC);
24762306a36Sopenharmony_ci	rd32(IGC_XONRXC);
24862306a36Sopenharmony_ci	rd32(IGC_XONTXC);
24962306a36Sopenharmony_ci	rd32(IGC_XOFFRXC);
25062306a36Sopenharmony_ci	rd32(IGC_XOFFTXC);
25162306a36Sopenharmony_ci	rd32(IGC_FCRUC);
25262306a36Sopenharmony_ci	rd32(IGC_GPRC);
25362306a36Sopenharmony_ci	rd32(IGC_BPRC);
25462306a36Sopenharmony_ci	rd32(IGC_MPRC);
25562306a36Sopenharmony_ci	rd32(IGC_GPTC);
25662306a36Sopenharmony_ci	rd32(IGC_GORCL);
25762306a36Sopenharmony_ci	rd32(IGC_GORCH);
25862306a36Sopenharmony_ci	rd32(IGC_GOTCL);
25962306a36Sopenharmony_ci	rd32(IGC_GOTCH);
26062306a36Sopenharmony_ci	rd32(IGC_RNBC);
26162306a36Sopenharmony_ci	rd32(IGC_RUC);
26262306a36Sopenharmony_ci	rd32(IGC_RFC);
26362306a36Sopenharmony_ci	rd32(IGC_ROC);
26462306a36Sopenharmony_ci	rd32(IGC_RJC);
26562306a36Sopenharmony_ci	rd32(IGC_TORL);
26662306a36Sopenharmony_ci	rd32(IGC_TORH);
26762306a36Sopenharmony_ci	rd32(IGC_TOTL);
26862306a36Sopenharmony_ci	rd32(IGC_TOTH);
26962306a36Sopenharmony_ci	rd32(IGC_TPR);
27062306a36Sopenharmony_ci	rd32(IGC_TPT);
27162306a36Sopenharmony_ci	rd32(IGC_MPTC);
27262306a36Sopenharmony_ci	rd32(IGC_BPTC);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	rd32(IGC_PRC64);
27562306a36Sopenharmony_ci	rd32(IGC_PRC127);
27662306a36Sopenharmony_ci	rd32(IGC_PRC255);
27762306a36Sopenharmony_ci	rd32(IGC_PRC511);
27862306a36Sopenharmony_ci	rd32(IGC_PRC1023);
27962306a36Sopenharmony_ci	rd32(IGC_PRC1522);
28062306a36Sopenharmony_ci	rd32(IGC_PTC64);
28162306a36Sopenharmony_ci	rd32(IGC_PTC127);
28262306a36Sopenharmony_ci	rd32(IGC_PTC255);
28362306a36Sopenharmony_ci	rd32(IGC_PTC511);
28462306a36Sopenharmony_ci	rd32(IGC_PTC1023);
28562306a36Sopenharmony_ci	rd32(IGC_PTC1522);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	rd32(IGC_ALGNERRC);
28862306a36Sopenharmony_ci	rd32(IGC_RXERRC);
28962306a36Sopenharmony_ci	rd32(IGC_TNCRS);
29062306a36Sopenharmony_ci	rd32(IGC_HTDPMC);
29162306a36Sopenharmony_ci	rd32(IGC_TSCTC);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	rd32(IGC_MGTPRC);
29462306a36Sopenharmony_ci	rd32(IGC_MGTPDC);
29562306a36Sopenharmony_ci	rd32(IGC_MGTPTC);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	rd32(IGC_IAC);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	rd32(IGC_RPTHC);
30062306a36Sopenharmony_ci	rd32(IGC_TLPIC);
30162306a36Sopenharmony_ci	rd32(IGC_RLPIC);
30262306a36Sopenharmony_ci	rd32(IGC_HGPTC);
30362306a36Sopenharmony_ci	rd32(IGC_RXDMTC);
30462306a36Sopenharmony_ci	rd32(IGC_HGORCL);
30562306a36Sopenharmony_ci	rd32(IGC_HGORCH);
30662306a36Sopenharmony_ci	rd32(IGC_HGOTCL);
30762306a36Sopenharmony_ci	rd32(IGC_HGOTCH);
30862306a36Sopenharmony_ci	rd32(IGC_LENERRS);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/**
31262306a36Sopenharmony_ci * igc_rar_set - Set receive address register
31362306a36Sopenharmony_ci * @hw: pointer to the HW structure
31462306a36Sopenharmony_ci * @addr: pointer to the receive address
31562306a36Sopenharmony_ci * @index: receive address array register
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * Sets the receive address array register at index to the address passed
31862306a36Sopenharmony_ci * in by addr.
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_civoid igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	u32 rar_low, rar_high;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* HW expects these in little endian so we reverse the byte order
32562306a36Sopenharmony_ci	 * from network order (big endian) to little endian
32662306a36Sopenharmony_ci	 */
32762306a36Sopenharmony_ci	rar_low = ((u32)addr[0] |
32862306a36Sopenharmony_ci		   ((u32)addr[1] << 8) |
32962306a36Sopenharmony_ci		   ((u32)addr[2] << 16) | ((u32)addr[3] << 24));
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* If MAC address zero, no need to set the AV bit */
33462306a36Sopenharmony_ci	if (rar_low || rar_high)
33562306a36Sopenharmony_ci		rar_high |= IGC_RAH_AV;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* Some bridges will combine consecutive 32-bit writes into
33862306a36Sopenharmony_ci	 * a single burst write, which will malfunction on some parts.
33962306a36Sopenharmony_ci	 * The flushes avoid this.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	wr32(IGC_RAL(index), rar_low);
34262306a36Sopenharmony_ci	wrfl();
34362306a36Sopenharmony_ci	wr32(IGC_RAH(index), rar_high);
34462306a36Sopenharmony_ci	wrfl();
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci/**
34862306a36Sopenharmony_ci * igc_check_for_copper_link - Check for link (Copper)
34962306a36Sopenharmony_ci * @hw: pointer to the HW structure
35062306a36Sopenharmony_ci *
35162306a36Sopenharmony_ci * Checks to see of the link status of the hardware has changed.  If a
35262306a36Sopenharmony_ci * change in link status has been detected, then we read the PHY registers
35362306a36Sopenharmony_ci * to get the current speed/duplex if link exists.
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_cis32 igc_check_for_copper_link(struct igc_hw *hw)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
35862306a36Sopenharmony_ci	bool link = false;
35962306a36Sopenharmony_ci	s32 ret_val;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* We only want to go out to the PHY registers to see if Auto-Neg
36262306a36Sopenharmony_ci	 * has completed and/or if our link status has changed.  The
36362306a36Sopenharmony_ci	 * get_link_status flag is set upon receiving a Link Status
36462306a36Sopenharmony_ci	 * Change or Rx Sequence Error interrupt.
36562306a36Sopenharmony_ci	 */
36662306a36Sopenharmony_ci	if (!mac->get_link_status) {
36762306a36Sopenharmony_ci		ret_val = 0;
36862306a36Sopenharmony_ci		goto out;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* First we want to see if the MII Status Register reports
37262306a36Sopenharmony_ci	 * link.  If so, then we want to get the current speed/duplex
37362306a36Sopenharmony_ci	 * of the PHY.
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	ret_val = igc_phy_has_link(hw, 1, 0, &link);
37662306a36Sopenharmony_ci	if (ret_val)
37762306a36Sopenharmony_ci		goto out;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (!link)
38062306a36Sopenharmony_ci		goto out; /* No link detected */
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	mac->get_link_status = false;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* Check if there was DownShift, must be checked
38562306a36Sopenharmony_ci	 * immediately after link-up
38662306a36Sopenharmony_ci	 */
38762306a36Sopenharmony_ci	igc_check_downshift(hw);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* If we are forcing speed/duplex, then we simply return since
39062306a36Sopenharmony_ci	 * we have already determined whether we have link or not.
39162306a36Sopenharmony_ci	 */
39262306a36Sopenharmony_ci	if (!mac->autoneg) {
39362306a36Sopenharmony_ci		ret_val = -IGC_ERR_CONFIG;
39462306a36Sopenharmony_ci		goto out;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Auto-Neg is enabled.  Auto Speed Detection takes care
39862306a36Sopenharmony_ci	 * of MAC speed/duplex configuration.  So we only need to
39962306a36Sopenharmony_ci	 * configure Collision Distance in the MAC.
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci	igc_config_collision_dist(hw);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* Configure Flow Control now that Auto-Neg has completed.
40462306a36Sopenharmony_ci	 * First, we need to restore the desired flow control
40562306a36Sopenharmony_ci	 * settings because we may have had to re-autoneg with a
40662306a36Sopenharmony_ci	 * different link partner.
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci	ret_val = igc_config_fc_after_link_up(hw);
40962306a36Sopenharmony_ci	if (ret_val)
41062306a36Sopenharmony_ci		hw_dbg("Error configuring flow control\n");
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ciout:
41362306a36Sopenharmony_ci	/* Now that we are aware of our link settings, we can set the LTR
41462306a36Sopenharmony_ci	 * thresholds.
41562306a36Sopenharmony_ci	 */
41662306a36Sopenharmony_ci	ret_val = igc_set_ltr_i225(hw, link);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return ret_val;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/**
42262306a36Sopenharmony_ci * igc_config_collision_dist - Configure collision distance
42362306a36Sopenharmony_ci * @hw: pointer to the HW structure
42462306a36Sopenharmony_ci *
42562306a36Sopenharmony_ci * Configures the collision distance to the default value and is used
42662306a36Sopenharmony_ci * during link setup. Currently no func pointer exists and all
42762306a36Sopenharmony_ci * implementations are handled in the generic version of this function.
42862306a36Sopenharmony_ci */
42962306a36Sopenharmony_civoid igc_config_collision_dist(struct igc_hw *hw)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	u32 tctl;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	tctl = rd32(IGC_TCTL);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	tctl &= ~IGC_TCTL_COLD;
43662306a36Sopenharmony_ci	tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	wr32(IGC_TCTL, tctl);
43962306a36Sopenharmony_ci	wrfl();
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci/**
44362306a36Sopenharmony_ci * igc_config_fc_after_link_up - Configures flow control after link
44462306a36Sopenharmony_ci * @hw: pointer to the HW structure
44562306a36Sopenharmony_ci *
44662306a36Sopenharmony_ci * Checks the status of auto-negotiation after link up to ensure that the
44762306a36Sopenharmony_ci * speed and duplex were not forced.  If the link needed to be forced, then
44862306a36Sopenharmony_ci * flow control needs to be forced also.  If auto-negotiation is enabled
44962306a36Sopenharmony_ci * and did not fail, then we configure flow control based on our link
45062306a36Sopenharmony_ci * partner.
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_cis32 igc_config_fc_after_link_up(struct igc_hw *hw)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
45562306a36Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
45662306a36Sopenharmony_ci	u16 speed, duplex;
45762306a36Sopenharmony_ci	s32 ret_val = 0;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* Check for the case where we have fiber media and auto-neg failed
46062306a36Sopenharmony_ci	 * so we had to force link.  In this case, we need to force the
46162306a36Sopenharmony_ci	 * configuration of the MAC to match the "fc" parameter.
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci	if (mac->autoneg_failed)
46462306a36Sopenharmony_ci		ret_val = igc_force_mac_fc(hw);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (ret_val) {
46762306a36Sopenharmony_ci		hw_dbg("Error forcing flow control settings\n");
46862306a36Sopenharmony_ci		goto out;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Check for the case where we have copper media and auto-neg is
47262306a36Sopenharmony_ci	 * enabled.  In this case, we need to check and see if Auto-Neg
47362306a36Sopenharmony_ci	 * has completed, and if so, how the PHY and link partner has
47462306a36Sopenharmony_ci	 * flow control configured.
47562306a36Sopenharmony_ci	 */
47662306a36Sopenharmony_ci	if (mac->autoneg) {
47762306a36Sopenharmony_ci		/* Read the MII Status Register and check to see if AutoNeg
47862306a36Sopenharmony_ci		 * has completed.  We read this twice because this reg has
47962306a36Sopenharmony_ci		 * some "sticky" (latched) bits.
48062306a36Sopenharmony_ci		 */
48162306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
48262306a36Sopenharmony_ci					       &mii_status_reg);
48362306a36Sopenharmony_ci		if (ret_val)
48462306a36Sopenharmony_ci			goto out;
48562306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
48662306a36Sopenharmony_ci					       &mii_status_reg);
48762306a36Sopenharmony_ci		if (ret_val)
48862306a36Sopenharmony_ci			goto out;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
49162306a36Sopenharmony_ci			hw_dbg("Copper PHY and Auto Neg has not completed.\n");
49262306a36Sopenharmony_ci			goto out;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		/* The AutoNeg process has completed, so we now need to
49662306a36Sopenharmony_ci		 * read both the Auto Negotiation Advertisement
49762306a36Sopenharmony_ci		 * Register (Address 4) and the Auto_Negotiation Base
49862306a36Sopenharmony_ci		 * Page Ability Register (Address 5) to determine how
49962306a36Sopenharmony_ci		 * flow control was negotiated.
50062306a36Sopenharmony_ci		 */
50162306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
50262306a36Sopenharmony_ci					       &mii_nway_adv_reg);
50362306a36Sopenharmony_ci		if (ret_val)
50462306a36Sopenharmony_ci			goto out;
50562306a36Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
50662306a36Sopenharmony_ci					       &mii_nway_lp_ability_reg);
50762306a36Sopenharmony_ci		if (ret_val)
50862306a36Sopenharmony_ci			goto out;
50962306a36Sopenharmony_ci		/* Two bits in the Auto Negotiation Advertisement Register
51062306a36Sopenharmony_ci		 * (Address 4) and two bits in the Auto Negotiation Base
51162306a36Sopenharmony_ci		 * Page Ability Register (Address 5) determine flow control
51262306a36Sopenharmony_ci		 * for both the PHY and the link partner.  The following
51362306a36Sopenharmony_ci		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
51462306a36Sopenharmony_ci		 * 1999, describes these PAUSE resolution bits and how flow
51562306a36Sopenharmony_ci		 * control is determined based upon these settings.
51662306a36Sopenharmony_ci		 * NOTE:  DC = Don't Care
51762306a36Sopenharmony_ci		 *
51862306a36Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
51962306a36Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
52062306a36Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
52162306a36Sopenharmony_ci		 *   0   |    0    |  DC   |   DC    | igc_fc_none
52262306a36Sopenharmony_ci		 *   0   |    1    |   0   |   DC    | igc_fc_none
52362306a36Sopenharmony_ci		 *   0   |    1    |   1   |    0    | igc_fc_none
52462306a36Sopenharmony_ci		 *   0   |    1    |   1   |    1    | igc_fc_tx_pause
52562306a36Sopenharmony_ci		 *   1   |    0    |   0   |   DC    | igc_fc_none
52662306a36Sopenharmony_ci		 *   1   |   DC    |   1   |   DC    | igc_fc_full
52762306a36Sopenharmony_ci		 *   1   |    1    |   0   |    0    | igc_fc_none
52862306a36Sopenharmony_ci		 *   1   |    1    |   0   |    1    | igc_fc_rx_pause
52962306a36Sopenharmony_ci		 *
53062306a36Sopenharmony_ci		 * Are both PAUSE bits set to 1?  If so, this implies
53162306a36Sopenharmony_ci		 * Symmetric Flow Control is enabled at both ends.  The
53262306a36Sopenharmony_ci		 * ASM_DIR bits are irrelevant per the spec.
53362306a36Sopenharmony_ci		 *
53462306a36Sopenharmony_ci		 * For Symmetric Flow Control:
53562306a36Sopenharmony_ci		 *
53662306a36Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
53762306a36Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
53862306a36Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
53962306a36Sopenharmony_ci		 *   1   |   DC    |   1   |   DC    | IGC_fc_full
54062306a36Sopenharmony_ci		 *
54162306a36Sopenharmony_ci		 */
54262306a36Sopenharmony_ci		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
54362306a36Sopenharmony_ci		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
54462306a36Sopenharmony_ci			/* Now we need to check if the user selected RX ONLY
54562306a36Sopenharmony_ci			 * of pause frames.  In this case, we had to advertise
54662306a36Sopenharmony_ci			 * FULL flow control because we could not advertise RX
54762306a36Sopenharmony_ci			 * ONLY. Hence, we must now check to see if we need to
54862306a36Sopenharmony_ci			 * turn OFF  the TRANSMISSION of PAUSE frames.
54962306a36Sopenharmony_ci			 */
55062306a36Sopenharmony_ci			if (hw->fc.requested_mode == igc_fc_full) {
55162306a36Sopenharmony_ci				hw->fc.current_mode = igc_fc_full;
55262306a36Sopenharmony_ci				hw_dbg("Flow Control = FULL.\n");
55362306a36Sopenharmony_ci			} else {
55462306a36Sopenharmony_ci				hw->fc.current_mode = igc_fc_rx_pause;
55562306a36Sopenharmony_ci				hw_dbg("Flow Control = RX PAUSE frames only.\n");
55662306a36Sopenharmony_ci			}
55762306a36Sopenharmony_ci		}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		/* For receiving PAUSE frames ONLY.
56062306a36Sopenharmony_ci		 *
56162306a36Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
56262306a36Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
56362306a36Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
56462306a36Sopenharmony_ci		 *   0   |    1    |   1   |    1    | igc_fc_tx_pause
56562306a36Sopenharmony_ci		 */
56662306a36Sopenharmony_ci		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
56762306a36Sopenharmony_ci			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
56862306a36Sopenharmony_ci			 (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
56962306a36Sopenharmony_ci			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
57062306a36Sopenharmony_ci			hw->fc.current_mode = igc_fc_tx_pause;
57162306a36Sopenharmony_ci			hw_dbg("Flow Control = TX PAUSE frames only.\n");
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci		/* For transmitting PAUSE frames ONLY.
57462306a36Sopenharmony_ci		 *
57562306a36Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
57662306a36Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
57762306a36Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
57862306a36Sopenharmony_ci		 *   1   |    1    |   0   |    1    | igc_fc_rx_pause
57962306a36Sopenharmony_ci		 */
58062306a36Sopenharmony_ci		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
58162306a36Sopenharmony_ci			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
58262306a36Sopenharmony_ci			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
58362306a36Sopenharmony_ci			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
58462306a36Sopenharmony_ci			hw->fc.current_mode = igc_fc_rx_pause;
58562306a36Sopenharmony_ci			hw_dbg("Flow Control = RX PAUSE frames only.\n");
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci		/* Per the IEEE spec, at this point flow control should be
58862306a36Sopenharmony_ci		 * disabled.  However, we want to consider that we could
58962306a36Sopenharmony_ci		 * be connected to a legacy switch that doesn't advertise
59062306a36Sopenharmony_ci		 * desired flow control, but can be forced on the link
59162306a36Sopenharmony_ci		 * partner.  So if we advertised no flow control, that is
59262306a36Sopenharmony_ci		 * what we will resolve to.  If we advertised some kind of
59362306a36Sopenharmony_ci		 * receive capability (Rx Pause Only or Full Flow Control)
59462306a36Sopenharmony_ci		 * and the link partner advertised none, we will configure
59562306a36Sopenharmony_ci		 * ourselves to enable Rx Flow Control only.  We can do
59662306a36Sopenharmony_ci		 * this safely for two reasons:  If the link partner really
59762306a36Sopenharmony_ci		 * didn't want flow control enabled, and we enable Rx, no
59862306a36Sopenharmony_ci		 * harm done since we won't be receiving any PAUSE frames
59962306a36Sopenharmony_ci		 * anyway.  If the intent on the link partner was to have
60062306a36Sopenharmony_ci		 * flow control enabled, then by us enabling RX only, we
60162306a36Sopenharmony_ci		 * can at least receive pause frames and process them.
60262306a36Sopenharmony_ci		 * This is a good idea because in most cases, since we are
60362306a36Sopenharmony_ci		 * predominantly a server NIC, more times than not we will
60462306a36Sopenharmony_ci		 * be asked to delay transmission of packets than asking
60562306a36Sopenharmony_ci		 * our link partner to pause transmission of frames.
60662306a36Sopenharmony_ci		 */
60762306a36Sopenharmony_ci		else if ((hw->fc.requested_mode == igc_fc_none) ||
60862306a36Sopenharmony_ci			 (hw->fc.requested_mode == igc_fc_tx_pause) ||
60962306a36Sopenharmony_ci			 (hw->fc.strict_ieee)) {
61062306a36Sopenharmony_ci			hw->fc.current_mode = igc_fc_none;
61162306a36Sopenharmony_ci			hw_dbg("Flow Control = NONE.\n");
61262306a36Sopenharmony_ci		} else {
61362306a36Sopenharmony_ci			hw->fc.current_mode = igc_fc_rx_pause;
61462306a36Sopenharmony_ci			hw_dbg("Flow Control = RX PAUSE frames only.\n");
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		/* Now we need to do one last check...  If we auto-
61862306a36Sopenharmony_ci		 * negotiated to HALF DUPLEX, flow control should not be
61962306a36Sopenharmony_ci		 * enabled per IEEE 802.3 spec.
62062306a36Sopenharmony_ci		 */
62162306a36Sopenharmony_ci		ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
62262306a36Sopenharmony_ci		if (ret_val) {
62362306a36Sopenharmony_ci			hw_dbg("Error getting link speed and duplex\n");
62462306a36Sopenharmony_ci			goto out;
62562306a36Sopenharmony_ci		}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		if (duplex == HALF_DUPLEX)
62862306a36Sopenharmony_ci			hw->fc.current_mode = igc_fc_none;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		/* Now we call a subroutine to actually force the MAC
63162306a36Sopenharmony_ci		 * controller to use the correct flow control settings.
63262306a36Sopenharmony_ci		 */
63362306a36Sopenharmony_ci		ret_val = igc_force_mac_fc(hw);
63462306a36Sopenharmony_ci		if (ret_val) {
63562306a36Sopenharmony_ci			hw_dbg("Error forcing flow control settings\n");
63662306a36Sopenharmony_ci			goto out;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ciout:
64162306a36Sopenharmony_ci	return ret_val;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci/**
64562306a36Sopenharmony_ci * igc_get_auto_rd_done - Check for auto read completion
64662306a36Sopenharmony_ci * @hw: pointer to the HW structure
64762306a36Sopenharmony_ci *
64862306a36Sopenharmony_ci * Check EEPROM for Auto Read done bit.
64962306a36Sopenharmony_ci */
65062306a36Sopenharmony_cis32 igc_get_auto_rd_done(struct igc_hw *hw)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	s32 ret_val = 0;
65362306a36Sopenharmony_ci	s32 i = 0;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	while (i < AUTO_READ_DONE_TIMEOUT) {
65662306a36Sopenharmony_ci		if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
65762306a36Sopenharmony_ci			break;
65862306a36Sopenharmony_ci		usleep_range(1000, 2000);
65962306a36Sopenharmony_ci		i++;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (i == AUTO_READ_DONE_TIMEOUT) {
66362306a36Sopenharmony_ci		hw_dbg("Auto read by HW from NVM has not completed.\n");
66462306a36Sopenharmony_ci		ret_val = -IGC_ERR_RESET;
66562306a36Sopenharmony_ci		goto out;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ciout:
66962306a36Sopenharmony_ci	return ret_val;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci/**
67362306a36Sopenharmony_ci * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
67462306a36Sopenharmony_ci * @hw: pointer to the HW structure
67562306a36Sopenharmony_ci * @speed: stores the current speed
67662306a36Sopenharmony_ci * @duplex: stores the current duplex
67762306a36Sopenharmony_ci *
67862306a36Sopenharmony_ci * Read the status register for the current speed/duplex and store the current
67962306a36Sopenharmony_ci * speed and duplex for copper connections.
68062306a36Sopenharmony_ci */
68162306a36Sopenharmony_cis32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
68262306a36Sopenharmony_ci				    u16 *duplex)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	u32 status;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	status = rd32(IGC_STATUS);
68762306a36Sopenharmony_ci	if (status & IGC_STATUS_SPEED_1000) {
68862306a36Sopenharmony_ci		/* For I225, STATUS will indicate 1G speed in both 1 Gbps
68962306a36Sopenharmony_ci		 * and 2.5 Gbps link modes. An additional bit is used
69062306a36Sopenharmony_ci		 * to differentiate between 1 Gbps and 2.5 Gbps.
69162306a36Sopenharmony_ci		 */
69262306a36Sopenharmony_ci		if (hw->mac.type == igc_i225 &&
69362306a36Sopenharmony_ci		    (status & IGC_STATUS_SPEED_2500)) {
69462306a36Sopenharmony_ci			*speed = SPEED_2500;
69562306a36Sopenharmony_ci			hw_dbg("2500 Mbs, ");
69662306a36Sopenharmony_ci		} else {
69762306a36Sopenharmony_ci			*speed = SPEED_1000;
69862306a36Sopenharmony_ci			hw_dbg("1000 Mbs, ");
69962306a36Sopenharmony_ci		}
70062306a36Sopenharmony_ci	} else if (status & IGC_STATUS_SPEED_100) {
70162306a36Sopenharmony_ci		*speed = SPEED_100;
70262306a36Sopenharmony_ci		hw_dbg("100 Mbs, ");
70362306a36Sopenharmony_ci	} else {
70462306a36Sopenharmony_ci		*speed = SPEED_10;
70562306a36Sopenharmony_ci		hw_dbg("10 Mbs, ");
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (status & IGC_STATUS_FD) {
70962306a36Sopenharmony_ci		*duplex = FULL_DUPLEX;
71062306a36Sopenharmony_ci		hw_dbg("Full Duplex\n");
71162306a36Sopenharmony_ci	} else {
71262306a36Sopenharmony_ci		*duplex = HALF_DUPLEX;
71362306a36Sopenharmony_ci		hw_dbg("Half Duplex\n");
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return 0;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/**
72062306a36Sopenharmony_ci * igc_put_hw_semaphore - Release hardware semaphore
72162306a36Sopenharmony_ci * @hw: pointer to the HW structure
72262306a36Sopenharmony_ci *
72362306a36Sopenharmony_ci * Release hardware semaphore used to access the PHY or NVM
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_civoid igc_put_hw_semaphore(struct igc_hw *hw)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	u32 swsm;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	swsm = rd32(IGC_SWSM);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	wr32(IGC_SWSM, swsm);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci/**
73762306a36Sopenharmony_ci * igc_enable_mng_pass_thru - Enable processing of ARP's
73862306a36Sopenharmony_ci * @hw: pointer to the HW structure
73962306a36Sopenharmony_ci *
74062306a36Sopenharmony_ci * Verifies the hardware needs to leave interface enabled so that frames can
74162306a36Sopenharmony_ci * be directed to and from the management interface.
74262306a36Sopenharmony_ci */
74362306a36Sopenharmony_cibool igc_enable_mng_pass_thru(struct igc_hw *hw)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	bool ret_val = false;
74662306a36Sopenharmony_ci	u32 fwsm, factps;
74762306a36Sopenharmony_ci	u32 manc;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (!hw->mac.asf_firmware_present)
75062306a36Sopenharmony_ci		goto out;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	manc = rd32(IGC_MANC);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (!(manc & IGC_MANC_RCV_TCO_EN))
75562306a36Sopenharmony_ci		goto out;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (hw->mac.arc_subsystem_valid) {
75862306a36Sopenharmony_ci		fwsm = rd32(IGC_FWSM);
75962306a36Sopenharmony_ci		factps = rd32(IGC_FACTPS);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		if (!(factps & IGC_FACTPS_MNGCG) &&
76262306a36Sopenharmony_ci		    ((fwsm & IGC_FWSM_MODE_MASK) ==
76362306a36Sopenharmony_ci		    (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
76462306a36Sopenharmony_ci			ret_val = true;
76562306a36Sopenharmony_ci			goto out;
76662306a36Sopenharmony_ci		}
76762306a36Sopenharmony_ci	} else {
76862306a36Sopenharmony_ci		if ((manc & IGC_MANC_SMBUS_EN) &&
76962306a36Sopenharmony_ci		    !(manc & IGC_MANC_ASF_EN)) {
77062306a36Sopenharmony_ci			ret_val = true;
77162306a36Sopenharmony_ci			goto out;
77262306a36Sopenharmony_ci		}
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ciout:
77662306a36Sopenharmony_ci	return ret_val;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci/**
78062306a36Sopenharmony_ci *  igc_hash_mc_addr - Generate a multicast hash value
78162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
78262306a36Sopenharmony_ci *  @mc_addr: pointer to a multicast address
78362306a36Sopenharmony_ci *
78462306a36Sopenharmony_ci *  Generates a multicast address hash value which is used to determine
78562306a36Sopenharmony_ci *  the multicast filter table array address and new table value.  See
78662306a36Sopenharmony_ci *  igc_mta_set()
78762306a36Sopenharmony_ci **/
78862306a36Sopenharmony_cistatic u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	u32 hash_value, hash_mask;
79162306a36Sopenharmony_ci	u8 bit_shift = 0;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/* Register count multiplied by bits per register */
79462306a36Sopenharmony_ci	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
79762306a36Sopenharmony_ci	 * where 0xFF would still fall within the hash mask.
79862306a36Sopenharmony_ci	 */
79962306a36Sopenharmony_ci	while (hash_mask >> bit_shift != 0xFF)
80062306a36Sopenharmony_ci		bit_shift++;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* The portion of the address that is used for the hash table
80362306a36Sopenharmony_ci	 * is determined by the mc_filter_type setting.
80462306a36Sopenharmony_ci	 * The algorithm is such that there is a total of 8 bits of shifting.
80562306a36Sopenharmony_ci	 * The bit_shift for a mc_filter_type of 0 represents the number of
80662306a36Sopenharmony_ci	 * left-shifts where the MSB of mc_addr[5] would still fall within
80762306a36Sopenharmony_ci	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
80862306a36Sopenharmony_ci	 * of 8 bits of shifting, then mc_addr[4] will shift right the
80962306a36Sopenharmony_ci	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
81062306a36Sopenharmony_ci	 * cases are a variation of this algorithm...essentially raising the
81162306a36Sopenharmony_ci	 * number of bits to shift mc_addr[5] left, while still keeping the
81262306a36Sopenharmony_ci	 * 8-bit shifting total.
81362306a36Sopenharmony_ci	 *
81462306a36Sopenharmony_ci	 * For example, given the following Destination MAC Address and an
81562306a36Sopenharmony_ci	 * MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask),
81662306a36Sopenharmony_ci	 * we can see that the bit_shift for case 0 is 4.  These are the hash
81762306a36Sopenharmony_ci	 * values resulting from each mc_filter_type...
81862306a36Sopenharmony_ci	 * [0] [1] [2] [3] [4] [5]
81962306a36Sopenharmony_ci	 * 01  AA  00  12  34  56
82062306a36Sopenharmony_ci	 * LSB                 MSB
82162306a36Sopenharmony_ci	 *
82262306a36Sopenharmony_ci	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
82362306a36Sopenharmony_ci	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
82462306a36Sopenharmony_ci	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
82562306a36Sopenharmony_ci	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
82662306a36Sopenharmony_ci	 */
82762306a36Sopenharmony_ci	switch (hw->mac.mc_filter_type) {
82862306a36Sopenharmony_ci	default:
82962306a36Sopenharmony_ci	case 0:
83062306a36Sopenharmony_ci		break;
83162306a36Sopenharmony_ci	case 1:
83262306a36Sopenharmony_ci		bit_shift += 1;
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci	case 2:
83562306a36Sopenharmony_ci		bit_shift += 2;
83662306a36Sopenharmony_ci		break;
83762306a36Sopenharmony_ci	case 3:
83862306a36Sopenharmony_ci		bit_shift += 4;
83962306a36Sopenharmony_ci		break;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
84362306a36Sopenharmony_ci				  (((u16)mc_addr[5]) << bit_shift)));
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return hash_value;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci/**
84962306a36Sopenharmony_ci *  igc_update_mc_addr_list - Update Multicast addresses
85062306a36Sopenharmony_ci *  @hw: pointer to the HW structure
85162306a36Sopenharmony_ci *  @mc_addr_list: array of multicast addresses to program
85262306a36Sopenharmony_ci *  @mc_addr_count: number of multicast addresses to program
85362306a36Sopenharmony_ci *
85462306a36Sopenharmony_ci *  Updates entire Multicast Table Array.
85562306a36Sopenharmony_ci *  The caller must have a packed mc_addr_list of multicast addresses.
85662306a36Sopenharmony_ci **/
85762306a36Sopenharmony_civoid igc_update_mc_addr_list(struct igc_hw *hw,
85862306a36Sopenharmony_ci			     u8 *mc_addr_list, u32 mc_addr_count)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	u32 hash_value, hash_bit, hash_reg;
86162306a36Sopenharmony_ci	int i;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* clear mta_shadow */
86462306a36Sopenharmony_ci	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* update mta_shadow from mc_addr_list */
86762306a36Sopenharmony_ci	for (i = 0; (u32)i < mc_addr_count; i++) {
86862306a36Sopenharmony_ci		hash_value = igc_hash_mc_addr(hw, mc_addr_list);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
87162306a36Sopenharmony_ci		hash_bit = hash_value & 0x1F;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci		hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);
87462306a36Sopenharmony_ci		mc_addr_list += ETH_ALEN;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* replace the entire MTA table */
87862306a36Sopenharmony_ci	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
87962306a36Sopenharmony_ci		array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);
88062306a36Sopenharmony_ci	wrfl();
88162306a36Sopenharmony_ci}
882