18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c)  2018 Intel Corporation */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/pci.h>
58c2ecf20Sopenharmony_ci#include <linux/delay.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "igc_mac.h"
88c2ecf20Sopenharmony_ci#include "igc_hw.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/**
118c2ecf20Sopenharmony_ci * igc_disable_pcie_master - Disables PCI-express master access
128c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Returns 0 (0) if successful, else returns -10
158c2ecf20Sopenharmony_ci * (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
168c2ecf20Sopenharmony_ci * the master requests to be disabled.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Disables PCI-Express master access and verifies there are no pending
198c2ecf20Sopenharmony_ci * requests.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_cis32 igc_disable_pcie_master(struct igc_hw *hw)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	s32 timeout = MASTER_DISABLE_TIMEOUT;
248c2ecf20Sopenharmony_ci	s32 ret_val = 0;
258c2ecf20Sopenharmony_ci	u32 ctrl;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
288c2ecf20Sopenharmony_ci	ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
298c2ecf20Sopenharmony_ci	wr32(IGC_CTRL, ctrl);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	while (timeout) {
328c2ecf20Sopenharmony_ci		if (!(rd32(IGC_STATUS) &
338c2ecf20Sopenharmony_ci		    IGC_STATUS_GIO_MASTER_ENABLE))
348c2ecf20Sopenharmony_ci			break;
358c2ecf20Sopenharmony_ci		usleep_range(2000, 3000);
368c2ecf20Sopenharmony_ci		timeout--;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!timeout) {
408c2ecf20Sopenharmony_ci		hw_dbg("Master requests are pending.\n");
418c2ecf20Sopenharmony_ci		ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
428c2ecf20Sopenharmony_ci		goto out;
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciout:
468c2ecf20Sopenharmony_ci	return ret_val;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/**
508c2ecf20Sopenharmony_ci * igc_init_rx_addrs - Initialize receive addresses
518c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
528c2ecf20Sopenharmony_ci * @rar_count: receive address registers
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * Setup the receive address registers by setting the base receive address
558c2ecf20Sopenharmony_ci * register to the devices MAC address and clearing all the other receive
568c2ecf20Sopenharmony_ci * address registers to 0.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_civoid igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	u8 mac_addr[ETH_ALEN] = {0};
618c2ecf20Sopenharmony_ci	u32 i;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* Setup the receive address */
648c2ecf20Sopenharmony_ci	hw_dbg("Programming MAC Address into RAR[0]\n");
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* Zero out the other (rar_entry_count - 1) receive addresses */
698c2ecf20Sopenharmony_ci	hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
708c2ecf20Sopenharmony_ci	for (i = 1; i < rar_count; i++)
718c2ecf20Sopenharmony_ci		hw->mac.ops.rar_set(hw, mac_addr, i);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/**
758c2ecf20Sopenharmony_ci * igc_set_fc_watermarks - Set flow control high/low watermarks
768c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * Sets the flow control high/low threshold (watermark) registers.  If
798c2ecf20Sopenharmony_ci * flow control XON frame transmission is enabled, then set XON frame
808c2ecf20Sopenharmony_ci * transmission as well.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_cistatic s32 igc_set_fc_watermarks(struct igc_hw *hw)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	u32 fcrtl = 0, fcrth = 0;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* Set the flow control receive threshold registers.  Normally,
878c2ecf20Sopenharmony_ci	 * these registers will be set to a default threshold that may be
888c2ecf20Sopenharmony_ci	 * adjusted later by the driver's runtime code.  However, if the
898c2ecf20Sopenharmony_ci	 * ability to transmit pause frames is not enabled, then these
908c2ecf20Sopenharmony_ci	 * registers will be set to 0.
918c2ecf20Sopenharmony_ci	 */
928c2ecf20Sopenharmony_ci	if (hw->fc.current_mode & igc_fc_tx_pause) {
938c2ecf20Sopenharmony_ci		/* We need to set up the Receive Threshold high and low water
948c2ecf20Sopenharmony_ci		 * marks as well as (optionally) enabling the transmission of
958c2ecf20Sopenharmony_ci		 * XON frames.
968c2ecf20Sopenharmony_ci		 */
978c2ecf20Sopenharmony_ci		fcrtl = hw->fc.low_water;
988c2ecf20Sopenharmony_ci		if (hw->fc.send_xon)
998c2ecf20Sopenharmony_ci			fcrtl |= IGC_FCRTL_XONE;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		fcrth = hw->fc.high_water;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	wr32(IGC_FCRTL, fcrtl);
1048c2ecf20Sopenharmony_ci	wr32(IGC_FCRTH, fcrth);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/**
1108c2ecf20Sopenharmony_ci * igc_setup_link - Setup flow control and link settings
1118c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci * Determines which flow control settings to use, then configures flow
1148c2ecf20Sopenharmony_ci * control.  Calls the appropriate media-specific link configuration
1158c2ecf20Sopenharmony_ci * function.  Assuming the adapter has a valid link partner, a valid link
1168c2ecf20Sopenharmony_ci * should be established.  Assumes the hardware has previously been reset
1178c2ecf20Sopenharmony_ci * and the transmitter and receiver are not enabled.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cis32 igc_setup_link(struct igc_hw *hw)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	s32 ret_val = 0;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* In the case of the phy reset being blocked, we already have a link.
1248c2ecf20Sopenharmony_ci	 * We do not need to set it up again.
1258c2ecf20Sopenharmony_ci	 */
1268c2ecf20Sopenharmony_ci	if (igc_check_reset_block(hw))
1278c2ecf20Sopenharmony_ci		goto out;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* If requested flow control is set to default, set flow control
1308c2ecf20Sopenharmony_ci	 * to the both 'rx' and 'tx' pause frames.
1318c2ecf20Sopenharmony_ci	 */
1328c2ecf20Sopenharmony_ci	if (hw->fc.requested_mode == igc_fc_default)
1338c2ecf20Sopenharmony_ci		hw->fc.requested_mode = igc_fc_full;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* We want to save off the original Flow Control configuration just
1368c2ecf20Sopenharmony_ci	 * in case we get disconnected and then reconnected into a different
1378c2ecf20Sopenharmony_ci	 * hub or switch with different Flow Control capabilities.
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	hw->fc.current_mode = hw->fc.requested_mode;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* Call the necessary media_type subroutine to configure the link. */
1448c2ecf20Sopenharmony_ci	ret_val = hw->mac.ops.setup_physical_interface(hw);
1458c2ecf20Sopenharmony_ci	if (ret_val)
1468c2ecf20Sopenharmony_ci		goto out;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/* Initialize the flow control address, type, and PAUSE timer
1498c2ecf20Sopenharmony_ci	 * registers to their default values.  This is done even if flow
1508c2ecf20Sopenharmony_ci	 * control is disabled, because it does not hurt anything to
1518c2ecf20Sopenharmony_ci	 * initialize these registers.
1528c2ecf20Sopenharmony_ci	 */
1538c2ecf20Sopenharmony_ci	hw_dbg("Initializing the Flow Control address, type and timer regs\n");
1548c2ecf20Sopenharmony_ci	wr32(IGC_FCT, FLOW_CONTROL_TYPE);
1558c2ecf20Sopenharmony_ci	wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
1568c2ecf20Sopenharmony_ci	wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	wr32(IGC_FCTTV, hw->fc.pause_time);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	ret_val = igc_set_fc_watermarks(hw);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciout:
1638c2ecf20Sopenharmony_ci	return ret_val;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/**
1678c2ecf20Sopenharmony_ci * igc_force_mac_fc - Force the MAC's flow control settings
1688c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
1718c2ecf20Sopenharmony_ci * device control register to reflect the adapter settings.  TFCE and RFCE
1728c2ecf20Sopenharmony_ci * need to be explicitly set by software when a copper PHY is used because
1738c2ecf20Sopenharmony_ci * autonegotiation is managed by the PHY rather than the MAC.  Software must
1748c2ecf20Sopenharmony_ci * also configure these bits when link is forced on a fiber connection.
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_cis32 igc_force_mac_fc(struct igc_hw *hw)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	s32 ret_val = 0;
1798c2ecf20Sopenharmony_ci	u32 ctrl;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Because we didn't get link via the internal auto-negotiation
1848c2ecf20Sopenharmony_ci	 * mechanism (we either forced link or we got link via PHY
1858c2ecf20Sopenharmony_ci	 * auto-neg), we have to manually enable/disable transmit an
1868c2ecf20Sopenharmony_ci	 * receive flow control.
1878c2ecf20Sopenharmony_ci	 *
1888c2ecf20Sopenharmony_ci	 * The "Case" statement below enables/disable flow control
1898c2ecf20Sopenharmony_ci	 * according to the "hw->fc.current_mode" parameter.
1908c2ecf20Sopenharmony_ci	 *
1918c2ecf20Sopenharmony_ci	 * The possible values of the "fc" parameter are:
1928c2ecf20Sopenharmony_ci	 *      0:  Flow control is completely disabled
1938c2ecf20Sopenharmony_ci	 *      1:  Rx flow control is enabled (we can receive pause
1948c2ecf20Sopenharmony_ci	 *          frames but not send pause frames).
1958c2ecf20Sopenharmony_ci	 *      2:  Tx flow control is enabled (we can send pause frames
1968c2ecf20Sopenharmony_ci	 *          frames but we do not receive pause frames).
1978c2ecf20Sopenharmony_ci	 *      3:  Both Rx and TX flow control (symmetric) is enabled.
1988c2ecf20Sopenharmony_ci	 *  other:  No other values should be possible at this point.
1998c2ecf20Sopenharmony_ci	 */
2008c2ecf20Sopenharmony_ci	hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	switch (hw->fc.current_mode) {
2038c2ecf20Sopenharmony_ci	case igc_fc_none:
2048c2ecf20Sopenharmony_ci		ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
2058c2ecf20Sopenharmony_ci		break;
2068c2ecf20Sopenharmony_ci	case igc_fc_rx_pause:
2078c2ecf20Sopenharmony_ci		ctrl &= (~IGC_CTRL_TFCE);
2088c2ecf20Sopenharmony_ci		ctrl |= IGC_CTRL_RFCE;
2098c2ecf20Sopenharmony_ci		break;
2108c2ecf20Sopenharmony_ci	case igc_fc_tx_pause:
2118c2ecf20Sopenharmony_ci		ctrl &= (~IGC_CTRL_RFCE);
2128c2ecf20Sopenharmony_ci		ctrl |= IGC_CTRL_TFCE;
2138c2ecf20Sopenharmony_ci		break;
2148c2ecf20Sopenharmony_ci	case igc_fc_full:
2158c2ecf20Sopenharmony_ci		ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
2168c2ecf20Sopenharmony_ci		break;
2178c2ecf20Sopenharmony_ci	default:
2188c2ecf20Sopenharmony_ci		hw_dbg("Flow control param set incorrectly\n");
2198c2ecf20Sopenharmony_ci		ret_val = -IGC_ERR_CONFIG;
2208c2ecf20Sopenharmony_ci		goto out;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	wr32(IGC_CTRL, ctrl);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ciout:
2268c2ecf20Sopenharmony_ci	return ret_val;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/**
2308c2ecf20Sopenharmony_ci * igc_clear_hw_cntrs_base - Clear base hardware counters
2318c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * Clears the base hardware counters by reading the counter registers.
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_civoid igc_clear_hw_cntrs_base(struct igc_hw *hw)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	rd32(IGC_CRCERRS);
2388c2ecf20Sopenharmony_ci	rd32(IGC_MPC);
2398c2ecf20Sopenharmony_ci	rd32(IGC_SCC);
2408c2ecf20Sopenharmony_ci	rd32(IGC_ECOL);
2418c2ecf20Sopenharmony_ci	rd32(IGC_MCC);
2428c2ecf20Sopenharmony_ci	rd32(IGC_LATECOL);
2438c2ecf20Sopenharmony_ci	rd32(IGC_COLC);
2448c2ecf20Sopenharmony_ci	rd32(IGC_RERC);
2458c2ecf20Sopenharmony_ci	rd32(IGC_DC);
2468c2ecf20Sopenharmony_ci	rd32(IGC_RLEC);
2478c2ecf20Sopenharmony_ci	rd32(IGC_XONRXC);
2488c2ecf20Sopenharmony_ci	rd32(IGC_XONTXC);
2498c2ecf20Sopenharmony_ci	rd32(IGC_XOFFRXC);
2508c2ecf20Sopenharmony_ci	rd32(IGC_XOFFTXC);
2518c2ecf20Sopenharmony_ci	rd32(IGC_FCRUC);
2528c2ecf20Sopenharmony_ci	rd32(IGC_GPRC);
2538c2ecf20Sopenharmony_ci	rd32(IGC_BPRC);
2548c2ecf20Sopenharmony_ci	rd32(IGC_MPRC);
2558c2ecf20Sopenharmony_ci	rd32(IGC_GPTC);
2568c2ecf20Sopenharmony_ci	rd32(IGC_GORCL);
2578c2ecf20Sopenharmony_ci	rd32(IGC_GORCH);
2588c2ecf20Sopenharmony_ci	rd32(IGC_GOTCL);
2598c2ecf20Sopenharmony_ci	rd32(IGC_GOTCH);
2608c2ecf20Sopenharmony_ci	rd32(IGC_RNBC);
2618c2ecf20Sopenharmony_ci	rd32(IGC_RUC);
2628c2ecf20Sopenharmony_ci	rd32(IGC_RFC);
2638c2ecf20Sopenharmony_ci	rd32(IGC_ROC);
2648c2ecf20Sopenharmony_ci	rd32(IGC_RJC);
2658c2ecf20Sopenharmony_ci	rd32(IGC_TORL);
2668c2ecf20Sopenharmony_ci	rd32(IGC_TORH);
2678c2ecf20Sopenharmony_ci	rd32(IGC_TOTL);
2688c2ecf20Sopenharmony_ci	rd32(IGC_TOTH);
2698c2ecf20Sopenharmony_ci	rd32(IGC_TPR);
2708c2ecf20Sopenharmony_ci	rd32(IGC_TPT);
2718c2ecf20Sopenharmony_ci	rd32(IGC_MPTC);
2728c2ecf20Sopenharmony_ci	rd32(IGC_BPTC);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	rd32(IGC_PRC64);
2758c2ecf20Sopenharmony_ci	rd32(IGC_PRC127);
2768c2ecf20Sopenharmony_ci	rd32(IGC_PRC255);
2778c2ecf20Sopenharmony_ci	rd32(IGC_PRC511);
2788c2ecf20Sopenharmony_ci	rd32(IGC_PRC1023);
2798c2ecf20Sopenharmony_ci	rd32(IGC_PRC1522);
2808c2ecf20Sopenharmony_ci	rd32(IGC_PTC64);
2818c2ecf20Sopenharmony_ci	rd32(IGC_PTC127);
2828c2ecf20Sopenharmony_ci	rd32(IGC_PTC255);
2838c2ecf20Sopenharmony_ci	rd32(IGC_PTC511);
2848c2ecf20Sopenharmony_ci	rd32(IGC_PTC1023);
2858c2ecf20Sopenharmony_ci	rd32(IGC_PTC1522);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	rd32(IGC_ALGNERRC);
2888c2ecf20Sopenharmony_ci	rd32(IGC_RXERRC);
2898c2ecf20Sopenharmony_ci	rd32(IGC_TNCRS);
2908c2ecf20Sopenharmony_ci	rd32(IGC_HTDPMC);
2918c2ecf20Sopenharmony_ci	rd32(IGC_TSCTC);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	rd32(IGC_MGTPRC);
2948c2ecf20Sopenharmony_ci	rd32(IGC_MGTPDC);
2958c2ecf20Sopenharmony_ci	rd32(IGC_MGTPTC);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	rd32(IGC_IAC);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	rd32(IGC_RPTHC);
3008c2ecf20Sopenharmony_ci	rd32(IGC_TLPIC);
3018c2ecf20Sopenharmony_ci	rd32(IGC_RLPIC);
3028c2ecf20Sopenharmony_ci	rd32(IGC_HGPTC);
3038c2ecf20Sopenharmony_ci	rd32(IGC_RXDMTC);
3048c2ecf20Sopenharmony_ci	rd32(IGC_HGORCL);
3058c2ecf20Sopenharmony_ci	rd32(IGC_HGORCH);
3068c2ecf20Sopenharmony_ci	rd32(IGC_HGOTCL);
3078c2ecf20Sopenharmony_ci	rd32(IGC_HGOTCH);
3088c2ecf20Sopenharmony_ci	rd32(IGC_LENERRS);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/**
3128c2ecf20Sopenharmony_ci * igc_rar_set - Set receive address register
3138c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
3148c2ecf20Sopenharmony_ci * @addr: pointer to the receive address
3158c2ecf20Sopenharmony_ci * @index: receive address array register
3168c2ecf20Sopenharmony_ci *
3178c2ecf20Sopenharmony_ci * Sets the receive address array register at index to the address passed
3188c2ecf20Sopenharmony_ci * in by addr.
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_civoid igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u32 rar_low, rar_high;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* HW expects these in little endian so we reverse the byte order
3258c2ecf20Sopenharmony_ci	 * from network order (big endian) to little endian
3268c2ecf20Sopenharmony_ci	 */
3278c2ecf20Sopenharmony_ci	rar_low = ((u32)addr[0] |
3288c2ecf20Sopenharmony_ci		   ((u32)addr[1] << 8) |
3298c2ecf20Sopenharmony_ci		   ((u32)addr[2] << 16) | ((u32)addr[3] << 24));
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* If MAC address zero, no need to set the AV bit */
3348c2ecf20Sopenharmony_ci	if (rar_low || rar_high)
3358c2ecf20Sopenharmony_ci		rar_high |= IGC_RAH_AV;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* Some bridges will combine consecutive 32-bit writes into
3388c2ecf20Sopenharmony_ci	 * a single burst write, which will malfunction on some parts.
3398c2ecf20Sopenharmony_ci	 * The flushes avoid this.
3408c2ecf20Sopenharmony_ci	 */
3418c2ecf20Sopenharmony_ci	wr32(IGC_RAL(index), rar_low);
3428c2ecf20Sopenharmony_ci	wrfl();
3438c2ecf20Sopenharmony_ci	wr32(IGC_RAH(index), rar_high);
3448c2ecf20Sopenharmony_ci	wrfl();
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci/**
3488c2ecf20Sopenharmony_ci * igc_check_for_copper_link - Check for link (Copper)
3498c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
3508c2ecf20Sopenharmony_ci *
3518c2ecf20Sopenharmony_ci * Checks to see of the link status of the hardware has changed.  If a
3528c2ecf20Sopenharmony_ci * change in link status has been detected, then we read the PHY registers
3538c2ecf20Sopenharmony_ci * to get the current speed/duplex if link exists.
3548c2ecf20Sopenharmony_ci */
3558c2ecf20Sopenharmony_cis32 igc_check_for_copper_link(struct igc_hw *hw)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
3588c2ecf20Sopenharmony_ci	bool link = false;
3598c2ecf20Sopenharmony_ci	s32 ret_val;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* We only want to go out to the PHY registers to see if Auto-Neg
3628c2ecf20Sopenharmony_ci	 * has completed and/or if our link status has changed.  The
3638c2ecf20Sopenharmony_ci	 * get_link_status flag is set upon receiving a Link Status
3648c2ecf20Sopenharmony_ci	 * Change or Rx Sequence Error interrupt.
3658c2ecf20Sopenharmony_ci	 */
3668c2ecf20Sopenharmony_ci	if (!mac->get_link_status) {
3678c2ecf20Sopenharmony_ci		ret_val = 0;
3688c2ecf20Sopenharmony_ci		goto out;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* First we want to see if the MII Status Register reports
3728c2ecf20Sopenharmony_ci	 * link.  If so, then we want to get the current speed/duplex
3738c2ecf20Sopenharmony_ci	 * of the PHY.
3748c2ecf20Sopenharmony_ci	 */
3758c2ecf20Sopenharmony_ci	ret_val = igc_phy_has_link(hw, 1, 0, &link);
3768c2ecf20Sopenharmony_ci	if (ret_val)
3778c2ecf20Sopenharmony_ci		goto out;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (!link)
3808c2ecf20Sopenharmony_ci		goto out; /* No link detected */
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	mac->get_link_status = false;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* Check if there was DownShift, must be checked
3858c2ecf20Sopenharmony_ci	 * immediately after link-up
3868c2ecf20Sopenharmony_ci	 */
3878c2ecf20Sopenharmony_ci	igc_check_downshift(hw);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* If we are forcing speed/duplex, then we simply return since
3908c2ecf20Sopenharmony_ci	 * we have already determined whether we have link or not.
3918c2ecf20Sopenharmony_ci	 */
3928c2ecf20Sopenharmony_ci	if (!mac->autoneg) {
3938c2ecf20Sopenharmony_ci		ret_val = -IGC_ERR_CONFIG;
3948c2ecf20Sopenharmony_ci		goto out;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* Auto-Neg is enabled.  Auto Speed Detection takes care
3988c2ecf20Sopenharmony_ci	 * of MAC speed/duplex configuration.  So we only need to
3998c2ecf20Sopenharmony_ci	 * configure Collision Distance in the MAC.
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	igc_config_collision_dist(hw);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Configure Flow Control now that Auto-Neg has completed.
4048c2ecf20Sopenharmony_ci	 * First, we need to restore the desired flow control
4058c2ecf20Sopenharmony_ci	 * settings because we may have had to re-autoneg with a
4068c2ecf20Sopenharmony_ci	 * different link partner.
4078c2ecf20Sopenharmony_ci	 */
4088c2ecf20Sopenharmony_ci	ret_val = igc_config_fc_after_link_up(hw);
4098c2ecf20Sopenharmony_ci	if (ret_val)
4108c2ecf20Sopenharmony_ci		hw_dbg("Error configuring flow control\n");
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ciout:
4138c2ecf20Sopenharmony_ci	/* Now that we are aware of our link settings, we can set the LTR
4148c2ecf20Sopenharmony_ci	 * thresholds.
4158c2ecf20Sopenharmony_ci	 */
4168c2ecf20Sopenharmony_ci	ret_val = igc_set_ltr_i225(hw, link);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return ret_val;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/**
4228c2ecf20Sopenharmony_ci * igc_config_collision_dist - Configure collision distance
4238c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Configures the collision distance to the default value and is used
4268c2ecf20Sopenharmony_ci * during link setup. Currently no func pointer exists and all
4278c2ecf20Sopenharmony_ci * implementations are handled in the generic version of this function.
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_civoid igc_config_collision_dist(struct igc_hw *hw)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	u32 tctl;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	tctl = rd32(IGC_TCTL);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	tctl &= ~IGC_TCTL_COLD;
4368c2ecf20Sopenharmony_ci	tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	wr32(IGC_TCTL, tctl);
4398c2ecf20Sopenharmony_ci	wrfl();
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/**
4438c2ecf20Sopenharmony_ci * igc_config_fc_after_link_up - Configures flow control after link
4448c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
4458c2ecf20Sopenharmony_ci *
4468c2ecf20Sopenharmony_ci * Checks the status of auto-negotiation after link up to ensure that the
4478c2ecf20Sopenharmony_ci * speed and duplex were not forced.  If the link needed to be forced, then
4488c2ecf20Sopenharmony_ci * flow control needs to be forced also.  If auto-negotiation is enabled
4498c2ecf20Sopenharmony_ci * and did not fail, then we configure flow control based on our link
4508c2ecf20Sopenharmony_ci * partner.
4518c2ecf20Sopenharmony_ci */
4528c2ecf20Sopenharmony_cis32 igc_config_fc_after_link_up(struct igc_hw *hw)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
4558c2ecf20Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
4568c2ecf20Sopenharmony_ci	u16 speed, duplex;
4578c2ecf20Sopenharmony_ci	s32 ret_val = 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* Check for the case where we have fiber media and auto-neg failed
4608c2ecf20Sopenharmony_ci	 * so we had to force link.  In this case, we need to force the
4618c2ecf20Sopenharmony_ci	 * configuration of the MAC to match the "fc" parameter.
4628c2ecf20Sopenharmony_ci	 */
4638c2ecf20Sopenharmony_ci	if (mac->autoneg_failed)
4648c2ecf20Sopenharmony_ci		ret_val = igc_force_mac_fc(hw);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (ret_val) {
4678c2ecf20Sopenharmony_ci		hw_dbg("Error forcing flow control settings\n");
4688c2ecf20Sopenharmony_ci		goto out;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* Check for the case where we have copper media and auto-neg is
4728c2ecf20Sopenharmony_ci	 * enabled.  In this case, we need to check and see if Auto-Neg
4738c2ecf20Sopenharmony_ci	 * has completed, and if so, how the PHY and link partner has
4748c2ecf20Sopenharmony_ci	 * flow control configured.
4758c2ecf20Sopenharmony_ci	 */
4768c2ecf20Sopenharmony_ci	if (mac->autoneg) {
4778c2ecf20Sopenharmony_ci		/* Read the MII Status Register and check to see if AutoNeg
4788c2ecf20Sopenharmony_ci		 * has completed.  We read this twice because this reg has
4798c2ecf20Sopenharmony_ci		 * some "sticky" (latched) bits.
4808c2ecf20Sopenharmony_ci		 */
4818c2ecf20Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
4828c2ecf20Sopenharmony_ci					       &mii_status_reg);
4838c2ecf20Sopenharmony_ci		if (ret_val)
4848c2ecf20Sopenharmony_ci			goto out;
4858c2ecf20Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
4868c2ecf20Sopenharmony_ci					       &mii_status_reg);
4878c2ecf20Sopenharmony_ci		if (ret_val)
4888c2ecf20Sopenharmony_ci			goto out;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
4918c2ecf20Sopenharmony_ci			hw_dbg("Copper PHY and Auto Neg has not completed.\n");
4928c2ecf20Sopenharmony_ci			goto out;
4938c2ecf20Sopenharmony_ci		}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		/* The AutoNeg process has completed, so we now need to
4968c2ecf20Sopenharmony_ci		 * read both the Auto Negotiation Advertisement
4978c2ecf20Sopenharmony_ci		 * Register (Address 4) and the Auto_Negotiation Base
4988c2ecf20Sopenharmony_ci		 * Page Ability Register (Address 5) to determine how
4998c2ecf20Sopenharmony_ci		 * flow control was negotiated.
5008c2ecf20Sopenharmony_ci		 */
5018c2ecf20Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
5028c2ecf20Sopenharmony_ci					       &mii_nway_adv_reg);
5038c2ecf20Sopenharmony_ci		if (ret_val)
5048c2ecf20Sopenharmony_ci			goto out;
5058c2ecf20Sopenharmony_ci		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
5068c2ecf20Sopenharmony_ci					       &mii_nway_lp_ability_reg);
5078c2ecf20Sopenharmony_ci		if (ret_val)
5088c2ecf20Sopenharmony_ci			goto out;
5098c2ecf20Sopenharmony_ci		/* Two bits in the Auto Negotiation Advertisement Register
5108c2ecf20Sopenharmony_ci		 * (Address 4) and two bits in the Auto Negotiation Base
5118c2ecf20Sopenharmony_ci		 * Page Ability Register (Address 5) determine flow control
5128c2ecf20Sopenharmony_ci		 * for both the PHY and the link partner.  The following
5138c2ecf20Sopenharmony_ci		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
5148c2ecf20Sopenharmony_ci		 * 1999, describes these PAUSE resolution bits and how flow
5158c2ecf20Sopenharmony_ci		 * control is determined based upon these settings.
5168c2ecf20Sopenharmony_ci		 * NOTE:  DC = Don't Care
5178c2ecf20Sopenharmony_ci		 *
5188c2ecf20Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
5198c2ecf20Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
5208c2ecf20Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
5218c2ecf20Sopenharmony_ci		 *   0   |    0    |  DC   |   DC    | igc_fc_none
5228c2ecf20Sopenharmony_ci		 *   0   |    1    |   0   |   DC    | igc_fc_none
5238c2ecf20Sopenharmony_ci		 *   0   |    1    |   1   |    0    | igc_fc_none
5248c2ecf20Sopenharmony_ci		 *   0   |    1    |   1   |    1    | igc_fc_tx_pause
5258c2ecf20Sopenharmony_ci		 *   1   |    0    |   0   |   DC    | igc_fc_none
5268c2ecf20Sopenharmony_ci		 *   1   |   DC    |   1   |   DC    | igc_fc_full
5278c2ecf20Sopenharmony_ci		 *   1   |    1    |   0   |    0    | igc_fc_none
5288c2ecf20Sopenharmony_ci		 *   1   |    1    |   0   |    1    | igc_fc_rx_pause
5298c2ecf20Sopenharmony_ci		 *
5308c2ecf20Sopenharmony_ci		 * Are both PAUSE bits set to 1?  If so, this implies
5318c2ecf20Sopenharmony_ci		 * Symmetric Flow Control is enabled at both ends.  The
5328c2ecf20Sopenharmony_ci		 * ASM_DIR bits are irrelevant per the spec.
5338c2ecf20Sopenharmony_ci		 *
5348c2ecf20Sopenharmony_ci		 * For Symmetric Flow Control:
5358c2ecf20Sopenharmony_ci		 *
5368c2ecf20Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
5378c2ecf20Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
5388c2ecf20Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
5398c2ecf20Sopenharmony_ci		 *   1   |   DC    |   1   |   DC    | IGC_fc_full
5408c2ecf20Sopenharmony_ci		 *
5418c2ecf20Sopenharmony_ci		 */
5428c2ecf20Sopenharmony_ci		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
5438c2ecf20Sopenharmony_ci		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
5448c2ecf20Sopenharmony_ci			/* Now we need to check if the user selected RX ONLY
5458c2ecf20Sopenharmony_ci			 * of pause frames.  In this case, we had to advertise
5468c2ecf20Sopenharmony_ci			 * FULL flow control because we could not advertise RX
5478c2ecf20Sopenharmony_ci			 * ONLY. Hence, we must now check to see if we need to
5488c2ecf20Sopenharmony_ci			 * turn OFF  the TRANSMISSION of PAUSE frames.
5498c2ecf20Sopenharmony_ci			 */
5508c2ecf20Sopenharmony_ci			if (hw->fc.requested_mode == igc_fc_full) {
5518c2ecf20Sopenharmony_ci				hw->fc.current_mode = igc_fc_full;
5528c2ecf20Sopenharmony_ci				hw_dbg("Flow Control = FULL.\n");
5538c2ecf20Sopenharmony_ci			} else {
5548c2ecf20Sopenharmony_ci				hw->fc.current_mode = igc_fc_rx_pause;
5558c2ecf20Sopenharmony_ci				hw_dbg("Flow Control = RX PAUSE frames only.\n");
5568c2ecf20Sopenharmony_ci			}
5578c2ecf20Sopenharmony_ci		}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci		/* For receiving PAUSE frames ONLY.
5608c2ecf20Sopenharmony_ci		 *
5618c2ecf20Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
5628c2ecf20Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
5638c2ecf20Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
5648c2ecf20Sopenharmony_ci		 *   0   |    1    |   1   |    1    | igc_fc_tx_pause
5658c2ecf20Sopenharmony_ci		 */
5668c2ecf20Sopenharmony_ci		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
5678c2ecf20Sopenharmony_ci			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
5688c2ecf20Sopenharmony_ci			 (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
5698c2ecf20Sopenharmony_ci			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
5708c2ecf20Sopenharmony_ci			hw->fc.current_mode = igc_fc_tx_pause;
5718c2ecf20Sopenharmony_ci			hw_dbg("Flow Control = TX PAUSE frames only.\n");
5728c2ecf20Sopenharmony_ci		}
5738c2ecf20Sopenharmony_ci		/* For transmitting PAUSE frames ONLY.
5748c2ecf20Sopenharmony_ci		 *
5758c2ecf20Sopenharmony_ci		 *   LOCAL DEVICE  |   LINK PARTNER
5768c2ecf20Sopenharmony_ci		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
5778c2ecf20Sopenharmony_ci		 *-------|---------|-------|---------|--------------------
5788c2ecf20Sopenharmony_ci		 *   1   |    1    |   0   |    1    | igc_fc_rx_pause
5798c2ecf20Sopenharmony_ci		 */
5808c2ecf20Sopenharmony_ci		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
5818c2ecf20Sopenharmony_ci			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
5828c2ecf20Sopenharmony_ci			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
5838c2ecf20Sopenharmony_ci			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
5848c2ecf20Sopenharmony_ci			hw->fc.current_mode = igc_fc_rx_pause;
5858c2ecf20Sopenharmony_ci			hw_dbg("Flow Control = RX PAUSE frames only.\n");
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci		/* Per the IEEE spec, at this point flow control should be
5888c2ecf20Sopenharmony_ci		 * disabled.  However, we want to consider that we could
5898c2ecf20Sopenharmony_ci		 * be connected to a legacy switch that doesn't advertise
5908c2ecf20Sopenharmony_ci		 * desired flow control, but can be forced on the link
5918c2ecf20Sopenharmony_ci		 * partner.  So if we advertised no flow control, that is
5928c2ecf20Sopenharmony_ci		 * what we will resolve to.  If we advertised some kind of
5938c2ecf20Sopenharmony_ci		 * receive capability (Rx Pause Only or Full Flow Control)
5948c2ecf20Sopenharmony_ci		 * and the link partner advertised none, we will configure
5958c2ecf20Sopenharmony_ci		 * ourselves to enable Rx Flow Control only.  We can do
5968c2ecf20Sopenharmony_ci		 * this safely for two reasons:  If the link partner really
5978c2ecf20Sopenharmony_ci		 * didn't want flow control enabled, and we enable Rx, no
5988c2ecf20Sopenharmony_ci		 * harm done since we won't be receiving any PAUSE frames
5998c2ecf20Sopenharmony_ci		 * anyway.  If the intent on the link partner was to have
6008c2ecf20Sopenharmony_ci		 * flow control enabled, then by us enabling RX only, we
6018c2ecf20Sopenharmony_ci		 * can at least receive pause frames and process them.
6028c2ecf20Sopenharmony_ci		 * This is a good idea because in most cases, since we are
6038c2ecf20Sopenharmony_ci		 * predominantly a server NIC, more times than not we will
6048c2ecf20Sopenharmony_ci		 * be asked to delay transmission of packets than asking
6058c2ecf20Sopenharmony_ci		 * our link partner to pause transmission of frames.
6068c2ecf20Sopenharmony_ci		 */
6078c2ecf20Sopenharmony_ci		else if ((hw->fc.requested_mode == igc_fc_none) ||
6088c2ecf20Sopenharmony_ci			 (hw->fc.requested_mode == igc_fc_tx_pause) ||
6098c2ecf20Sopenharmony_ci			 (hw->fc.strict_ieee)) {
6108c2ecf20Sopenharmony_ci			hw->fc.current_mode = igc_fc_none;
6118c2ecf20Sopenharmony_ci			hw_dbg("Flow Control = NONE.\n");
6128c2ecf20Sopenharmony_ci		} else {
6138c2ecf20Sopenharmony_ci			hw->fc.current_mode = igc_fc_rx_pause;
6148c2ecf20Sopenharmony_ci			hw_dbg("Flow Control = RX PAUSE frames only.\n");
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci		/* Now we need to do one last check...  If we auto-
6188c2ecf20Sopenharmony_ci		 * negotiated to HALF DUPLEX, flow control should not be
6198c2ecf20Sopenharmony_ci		 * enabled per IEEE 802.3 spec.
6208c2ecf20Sopenharmony_ci		 */
6218c2ecf20Sopenharmony_ci		ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
6228c2ecf20Sopenharmony_ci		if (ret_val) {
6238c2ecf20Sopenharmony_ci			hw_dbg("Error getting link speed and duplex\n");
6248c2ecf20Sopenharmony_ci			goto out;
6258c2ecf20Sopenharmony_ci		}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		if (duplex == HALF_DUPLEX)
6288c2ecf20Sopenharmony_ci			hw->fc.current_mode = igc_fc_none;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		/* Now we call a subroutine to actually force the MAC
6318c2ecf20Sopenharmony_ci		 * controller to use the correct flow control settings.
6328c2ecf20Sopenharmony_ci		 */
6338c2ecf20Sopenharmony_ci		ret_val = igc_force_mac_fc(hw);
6348c2ecf20Sopenharmony_ci		if (ret_val) {
6358c2ecf20Sopenharmony_ci			hw_dbg("Error forcing flow control settings\n");
6368c2ecf20Sopenharmony_ci			goto out;
6378c2ecf20Sopenharmony_ci		}
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ciout:
6418c2ecf20Sopenharmony_ci	return ret_val;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci/**
6458c2ecf20Sopenharmony_ci * igc_get_auto_rd_done - Check for auto read completion
6468c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
6478c2ecf20Sopenharmony_ci *
6488c2ecf20Sopenharmony_ci * Check EEPROM for Auto Read done bit.
6498c2ecf20Sopenharmony_ci */
6508c2ecf20Sopenharmony_cis32 igc_get_auto_rd_done(struct igc_hw *hw)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	s32 ret_val = 0;
6538c2ecf20Sopenharmony_ci	s32 i = 0;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	while (i < AUTO_READ_DONE_TIMEOUT) {
6568c2ecf20Sopenharmony_ci		if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
6578c2ecf20Sopenharmony_ci			break;
6588c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
6598c2ecf20Sopenharmony_ci		i++;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	if (i == AUTO_READ_DONE_TIMEOUT) {
6638c2ecf20Sopenharmony_ci		hw_dbg("Auto read by HW from NVM has not completed.\n");
6648c2ecf20Sopenharmony_ci		ret_val = -IGC_ERR_RESET;
6658c2ecf20Sopenharmony_ci		goto out;
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ciout:
6698c2ecf20Sopenharmony_ci	return ret_val;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci/**
6738c2ecf20Sopenharmony_ci * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
6748c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
6758c2ecf20Sopenharmony_ci * @speed: stores the current speed
6768c2ecf20Sopenharmony_ci * @duplex: stores the current duplex
6778c2ecf20Sopenharmony_ci *
6788c2ecf20Sopenharmony_ci * Read the status register for the current speed/duplex and store the current
6798c2ecf20Sopenharmony_ci * speed and duplex for copper connections.
6808c2ecf20Sopenharmony_ci */
6818c2ecf20Sopenharmony_cis32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
6828c2ecf20Sopenharmony_ci				    u16 *duplex)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	u32 status;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	status = rd32(IGC_STATUS);
6878c2ecf20Sopenharmony_ci	if (status & IGC_STATUS_SPEED_1000) {
6888c2ecf20Sopenharmony_ci		/* For I225, STATUS will indicate 1G speed in both 1 Gbps
6898c2ecf20Sopenharmony_ci		 * and 2.5 Gbps link modes. An additional bit is used
6908c2ecf20Sopenharmony_ci		 * to differentiate between 1 Gbps and 2.5 Gbps.
6918c2ecf20Sopenharmony_ci		 */
6928c2ecf20Sopenharmony_ci		if (hw->mac.type == igc_i225 &&
6938c2ecf20Sopenharmony_ci		    (status & IGC_STATUS_SPEED_2500)) {
6948c2ecf20Sopenharmony_ci			*speed = SPEED_2500;
6958c2ecf20Sopenharmony_ci			hw_dbg("2500 Mbs, ");
6968c2ecf20Sopenharmony_ci		} else {
6978c2ecf20Sopenharmony_ci			*speed = SPEED_1000;
6988c2ecf20Sopenharmony_ci			hw_dbg("1000 Mbs, ");
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci	} else if (status & IGC_STATUS_SPEED_100) {
7018c2ecf20Sopenharmony_ci		*speed = SPEED_100;
7028c2ecf20Sopenharmony_ci		hw_dbg("100 Mbs, ");
7038c2ecf20Sopenharmony_ci	} else {
7048c2ecf20Sopenharmony_ci		*speed = SPEED_10;
7058c2ecf20Sopenharmony_ci		hw_dbg("10 Mbs, ");
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (status & IGC_STATUS_FD) {
7098c2ecf20Sopenharmony_ci		*duplex = FULL_DUPLEX;
7108c2ecf20Sopenharmony_ci		hw_dbg("Full Duplex\n");
7118c2ecf20Sopenharmony_ci	} else {
7128c2ecf20Sopenharmony_ci		*duplex = HALF_DUPLEX;
7138c2ecf20Sopenharmony_ci		hw_dbg("Half Duplex\n");
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	return 0;
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/**
7208c2ecf20Sopenharmony_ci * igc_put_hw_semaphore - Release hardware semaphore
7218c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
7228c2ecf20Sopenharmony_ci *
7238c2ecf20Sopenharmony_ci * Release hardware semaphore used to access the PHY or NVM
7248c2ecf20Sopenharmony_ci */
7258c2ecf20Sopenharmony_civoid igc_put_hw_semaphore(struct igc_hw *hw)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	u32 swsm;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	swsm = rd32(IGC_SWSM);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	wr32(IGC_SWSM, swsm);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci/**
7378c2ecf20Sopenharmony_ci * igc_enable_mng_pass_thru - Enable processing of ARP's
7388c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
7398c2ecf20Sopenharmony_ci *
7408c2ecf20Sopenharmony_ci * Verifies the hardware needs to leave interface enabled so that frames can
7418c2ecf20Sopenharmony_ci * be directed to and from the management interface.
7428c2ecf20Sopenharmony_ci */
7438c2ecf20Sopenharmony_cibool igc_enable_mng_pass_thru(struct igc_hw *hw)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	bool ret_val = false;
7468c2ecf20Sopenharmony_ci	u32 fwsm, factps;
7478c2ecf20Sopenharmony_ci	u32 manc;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if (!hw->mac.asf_firmware_present)
7508c2ecf20Sopenharmony_ci		goto out;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	manc = rd32(IGC_MANC);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	if (!(manc & IGC_MANC_RCV_TCO_EN))
7558c2ecf20Sopenharmony_ci		goto out;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (hw->mac.arc_subsystem_valid) {
7588c2ecf20Sopenharmony_ci		fwsm = rd32(IGC_FWSM);
7598c2ecf20Sopenharmony_ci		factps = rd32(IGC_FACTPS);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		if (!(factps & IGC_FACTPS_MNGCG) &&
7628c2ecf20Sopenharmony_ci		    ((fwsm & IGC_FWSM_MODE_MASK) ==
7638c2ecf20Sopenharmony_ci		    (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
7648c2ecf20Sopenharmony_ci			ret_val = true;
7658c2ecf20Sopenharmony_ci			goto out;
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci	} else {
7688c2ecf20Sopenharmony_ci		if ((manc & IGC_MANC_SMBUS_EN) &&
7698c2ecf20Sopenharmony_ci		    !(manc & IGC_MANC_ASF_EN)) {
7708c2ecf20Sopenharmony_ci			ret_val = true;
7718c2ecf20Sopenharmony_ci			goto out;
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ciout:
7768c2ecf20Sopenharmony_ci	return ret_val;
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci/**
7808c2ecf20Sopenharmony_ci *  igc_hash_mc_addr - Generate a multicast hash value
7818c2ecf20Sopenharmony_ci *  @hw: pointer to the HW structure
7828c2ecf20Sopenharmony_ci *  @mc_addr: pointer to a multicast address
7838c2ecf20Sopenharmony_ci *
7848c2ecf20Sopenharmony_ci *  Generates a multicast address hash value which is used to determine
7858c2ecf20Sopenharmony_ci *  the multicast filter table array address and new table value.  See
7868c2ecf20Sopenharmony_ci *  igc_mta_set()
7878c2ecf20Sopenharmony_ci **/
7888c2ecf20Sopenharmony_cistatic u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	u32 hash_value, hash_mask;
7918c2ecf20Sopenharmony_ci	u8 bit_shift = 0;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	/* Register count multiplied by bits per register */
7948c2ecf20Sopenharmony_ci	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
7978c2ecf20Sopenharmony_ci	 * where 0xFF would still fall within the hash mask.
7988c2ecf20Sopenharmony_ci	 */
7998c2ecf20Sopenharmony_ci	while (hash_mask >> bit_shift != 0xFF)
8008c2ecf20Sopenharmony_ci		bit_shift++;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/* The portion of the address that is used for the hash table
8038c2ecf20Sopenharmony_ci	 * is determined by the mc_filter_type setting.
8048c2ecf20Sopenharmony_ci	 * The algorithm is such that there is a total of 8 bits of shifting.
8058c2ecf20Sopenharmony_ci	 * The bit_shift for a mc_filter_type of 0 represents the number of
8068c2ecf20Sopenharmony_ci	 * left-shifts where the MSB of mc_addr[5] would still fall within
8078c2ecf20Sopenharmony_ci	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
8088c2ecf20Sopenharmony_ci	 * of 8 bits of shifting, then mc_addr[4] will shift right the
8098c2ecf20Sopenharmony_ci	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
8108c2ecf20Sopenharmony_ci	 * cases are a variation of this algorithm...essentially raising the
8118c2ecf20Sopenharmony_ci	 * number of bits to shift mc_addr[5] left, while still keeping the
8128c2ecf20Sopenharmony_ci	 * 8-bit shifting total.
8138c2ecf20Sopenharmony_ci	 *
8148c2ecf20Sopenharmony_ci	 * For example, given the following Destination MAC Address and an
8158c2ecf20Sopenharmony_ci	 * MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask),
8168c2ecf20Sopenharmony_ci	 * we can see that the bit_shift for case 0 is 4.  These are the hash
8178c2ecf20Sopenharmony_ci	 * values resulting from each mc_filter_type...
8188c2ecf20Sopenharmony_ci	 * [0] [1] [2] [3] [4] [5]
8198c2ecf20Sopenharmony_ci	 * 01  AA  00  12  34  56
8208c2ecf20Sopenharmony_ci	 * LSB                 MSB
8218c2ecf20Sopenharmony_ci	 *
8228c2ecf20Sopenharmony_ci	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
8238c2ecf20Sopenharmony_ci	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
8248c2ecf20Sopenharmony_ci	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
8258c2ecf20Sopenharmony_ci	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
8268c2ecf20Sopenharmony_ci	 */
8278c2ecf20Sopenharmony_ci	switch (hw->mac.mc_filter_type) {
8288c2ecf20Sopenharmony_ci	default:
8298c2ecf20Sopenharmony_ci	case 0:
8308c2ecf20Sopenharmony_ci		break;
8318c2ecf20Sopenharmony_ci	case 1:
8328c2ecf20Sopenharmony_ci		bit_shift += 1;
8338c2ecf20Sopenharmony_ci		break;
8348c2ecf20Sopenharmony_ci	case 2:
8358c2ecf20Sopenharmony_ci		bit_shift += 2;
8368c2ecf20Sopenharmony_ci		break;
8378c2ecf20Sopenharmony_ci	case 3:
8388c2ecf20Sopenharmony_ci		bit_shift += 4;
8398c2ecf20Sopenharmony_ci		break;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
8438c2ecf20Sopenharmony_ci				  (((u16)mc_addr[5]) << bit_shift)));
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	return hash_value;
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci/**
8498c2ecf20Sopenharmony_ci *  igc_update_mc_addr_list - Update Multicast addresses
8508c2ecf20Sopenharmony_ci *  @hw: pointer to the HW structure
8518c2ecf20Sopenharmony_ci *  @mc_addr_list: array of multicast addresses to program
8528c2ecf20Sopenharmony_ci *  @mc_addr_count: number of multicast addresses to program
8538c2ecf20Sopenharmony_ci *
8548c2ecf20Sopenharmony_ci *  Updates entire Multicast Table Array.
8558c2ecf20Sopenharmony_ci *  The caller must have a packed mc_addr_list of multicast addresses.
8568c2ecf20Sopenharmony_ci **/
8578c2ecf20Sopenharmony_civoid igc_update_mc_addr_list(struct igc_hw *hw,
8588c2ecf20Sopenharmony_ci			     u8 *mc_addr_list, u32 mc_addr_count)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	u32 hash_value, hash_bit, hash_reg;
8618c2ecf20Sopenharmony_ci	int i;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	/* clear mta_shadow */
8648c2ecf20Sopenharmony_ci	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* update mta_shadow from mc_addr_list */
8678c2ecf20Sopenharmony_ci	for (i = 0; (u32)i < mc_addr_count; i++) {
8688c2ecf20Sopenharmony_ci		hash_value = igc_hash_mc_addr(hw, mc_addr_list);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
8718c2ecf20Sopenharmony_ci		hash_bit = hash_value & 0x1F;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci		hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);
8748c2ecf20Sopenharmony_ci		mc_addr_list += ETH_ALEN;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* replace the entire MTA table */
8788c2ecf20Sopenharmony_ci	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
8798c2ecf20Sopenharmony_ci		array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);
8808c2ecf20Sopenharmony_ci	wrfl();
8818c2ecf20Sopenharmony_ci}
882