xref: /netbsd-src/sys/dev/pci/igc/igc_mac.c (revision fb38d839b48b9b6204dbbee1672454d6e719ba01)
1*fb38d839Srin /*	$NetBSD: igc_mac.c,v 1.2 2023/10/04 07:35:27 rin Exp $	*/
2d0d8f2a5Srin /*	$OpenBSD: igc_mac.c,v 1.1 2021/10/31 14:52:57 patrick Exp $	*/
3d0d8f2a5Srin /*-
4d0d8f2a5Srin  * Copyright 2021 Intel Corp
5d0d8f2a5Srin  * Copyright 2021 Rubicon Communications, LLC (Netgate)
6d0d8f2a5Srin  * SPDX-License-Identifier: BSD-3-Clause
7d0d8f2a5Srin  */
8d0d8f2a5Srin 
9*fb38d839Srin #include <sys/cdefs.h>
10*fb38d839Srin __KERNEL_RCSID(0, "$NetBSD: igc_mac.c,v 1.2 2023/10/04 07:35:27 rin Exp $");
11*fb38d839Srin 
12*fb38d839Srin #include <dev/pci/igc/igc_api.h>
13*fb38d839Srin #include <dev/mii/mii.h>
14d0d8f2a5Srin 
15d0d8f2a5Srin /**
16d0d8f2a5Srin  *  igc_init_mac_ops_generic - Initialize MAC function pointers
17d0d8f2a5Srin  *  @hw: pointer to the HW structure
18d0d8f2a5Srin  *
19d0d8f2a5Srin  *  Setups up the function pointers to no-op functions
20d0d8f2a5Srin  **/
21d0d8f2a5Srin void
igc_init_mac_ops_generic(struct igc_hw * hw)22d0d8f2a5Srin igc_init_mac_ops_generic(struct igc_hw *hw)
23d0d8f2a5Srin {
24d0d8f2a5Srin 	struct igc_mac_info *mac = &hw->mac;
25d0d8f2a5Srin 	DEBUGFUNC("igc_init_mac_ops_generic");
26d0d8f2a5Srin 
27d0d8f2a5Srin 	/* General Setup */
28d0d8f2a5Srin 	mac->ops.init_params = igc_null_ops_generic;
29d0d8f2a5Srin 	mac->ops.config_collision_dist = igc_config_collision_dist_generic;
30d0d8f2a5Srin 	mac->ops.rar_set = igc_rar_set_generic;
31d0d8f2a5Srin }
32d0d8f2a5Srin 
33d0d8f2a5Srin /**
34d0d8f2a5Srin  *  igc_null_ops_generic - No-op function, returns 0
35d0d8f2a5Srin  *  @hw: pointer to the HW structure
36d0d8f2a5Srin  **/
37d0d8f2a5Srin int
igc_null_ops_generic(struct igc_hw IGC_UNUSEDARG * hw)38d0d8f2a5Srin igc_null_ops_generic(struct igc_hw IGC_UNUSEDARG *hw)
39d0d8f2a5Srin {
40d0d8f2a5Srin 	DEBUGFUNC("igc_null_ops_generic");
41d0d8f2a5Srin 	return IGC_SUCCESS;
42d0d8f2a5Srin }
43d0d8f2a5Srin 
44d0d8f2a5Srin /**
45d0d8f2a5Srin  *  igc_write_vfta_generic - Write value to VLAN filter table
46d0d8f2a5Srin  *  @hw: pointer to the HW structure
47d0d8f2a5Srin  *  @offset: register offset in VLAN filter table
48d0d8f2a5Srin  *  @value: register value written to VLAN filter table
49d0d8f2a5Srin  *
50d0d8f2a5Srin  *  Writes value at the given offset in the register array which stores
51d0d8f2a5Srin  *  the VLAN filter table.
52d0d8f2a5Srin  **/
53d0d8f2a5Srin void
igc_write_vfta_generic(struct igc_hw * hw,uint32_t offset,uint32_t value)54d0d8f2a5Srin igc_write_vfta_generic(struct igc_hw *hw, uint32_t offset, uint32_t value)
55d0d8f2a5Srin {
56d0d8f2a5Srin 	DEBUGFUNC("igc_write_vfta_generic");
57d0d8f2a5Srin 
58d0d8f2a5Srin 	IGC_WRITE_REG_ARRAY(hw, IGC_VFTA, offset, value);
59d0d8f2a5Srin 	IGC_WRITE_FLUSH(hw);
60d0d8f2a5Srin }
61d0d8f2a5Srin 
62d0d8f2a5Srin /**
63d0d8f2a5Srin  *  igc_init_rx_addrs_generic - Initialize receive address's
64d0d8f2a5Srin  *  @hw: pointer to the HW structure
65d0d8f2a5Srin  *  @rar_count: receive address registers
66d0d8f2a5Srin  *
67d0d8f2a5Srin  *  Setup the receive address registers by setting the base receive address
68d0d8f2a5Srin  *  register to the devices MAC address and clearing all the other receive
69d0d8f2a5Srin  *  address registers to 0.
70d0d8f2a5Srin  **/
71d0d8f2a5Srin void
igc_init_rx_addrs_generic(struct igc_hw * hw,uint16_t rar_count)72d0d8f2a5Srin igc_init_rx_addrs_generic(struct igc_hw *hw, uint16_t rar_count)
73d0d8f2a5Srin {
74d0d8f2a5Srin 	uint32_t i;
75d0d8f2a5Srin 	uint8_t mac_addr[ETHER_ADDR_LEN] = {0};
76d0d8f2a5Srin 
77d0d8f2a5Srin 	DEBUGFUNC("igc_init_rx_addrs_generic");
78d0d8f2a5Srin 
79d0d8f2a5Srin 	/* Setup the receive address */
80d0d8f2a5Srin 	DEBUGOUT("Programming MAC Address into RAR[0]\n");
81d0d8f2a5Srin 
82d0d8f2a5Srin 	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
83d0d8f2a5Srin 
84d0d8f2a5Srin 	/* Zero out the other (rar_entry_count - 1) receive addresses */
85d0d8f2a5Srin 	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
86d0d8f2a5Srin 	for (i = 1; i < rar_count; i++)
87d0d8f2a5Srin 		hw->mac.ops.rar_set(hw, mac_addr, i);
88d0d8f2a5Srin }
89d0d8f2a5Srin 
90d0d8f2a5Srin /**
91d0d8f2a5Srin  *  igc_check_alt_mac_addr_generic - Check for alternate MAC addr
92d0d8f2a5Srin  *  @hw: pointer to the HW structure
93d0d8f2a5Srin  *
94d0d8f2a5Srin  *  Checks the nvm for an alternate MAC address.  An alternate MAC address
95d0d8f2a5Srin  *  can be setup by pre-boot software and must be treated like a permanent
96d0d8f2a5Srin  *  address and must override the actual permanent MAC address. If an
97d0d8f2a5Srin  *  alternate MAC address is found it is programmed into RAR0, replacing
98d0d8f2a5Srin  *  the permanent address that was installed into RAR0 by the Si on reset.
99d0d8f2a5Srin  *  This function will return SUCCESS unless it encounters an error while
100d0d8f2a5Srin  *  reading the EEPROM.
101d0d8f2a5Srin  **/
102d0d8f2a5Srin int
igc_check_alt_mac_addr_generic(struct igc_hw * hw)103d0d8f2a5Srin igc_check_alt_mac_addr_generic(struct igc_hw *hw)
104d0d8f2a5Srin {
105d0d8f2a5Srin 	uint32_t i;
106d0d8f2a5Srin 	int ret_val;
107d0d8f2a5Srin 	uint16_t offset, nvm_alt_mac_addr_offset, nvm_data;
108d0d8f2a5Srin 	uint8_t alt_mac_addr[ETHER_ADDR_LEN];
109d0d8f2a5Srin 
110d0d8f2a5Srin 	DEBUGFUNC("igc_check_alt_mac_addr_generic");
111d0d8f2a5Srin 
112d0d8f2a5Srin 	ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data);
113d0d8f2a5Srin 	if (ret_val)
114d0d8f2a5Srin 		return ret_val;
115d0d8f2a5Srin 
116d0d8f2a5Srin 	ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
117d0d8f2a5Srin 	    &nvm_alt_mac_addr_offset);
118d0d8f2a5Srin 	if (ret_val) {
119d0d8f2a5Srin 		DEBUGOUT("NVM Read Error\n");
120d0d8f2a5Srin 		return ret_val;
121d0d8f2a5Srin 	}
122d0d8f2a5Srin 
123d0d8f2a5Srin 	if ((nvm_alt_mac_addr_offset == 0xFFFF) ||
124d0d8f2a5Srin 	    (nvm_alt_mac_addr_offset == 0x0000))
125d0d8f2a5Srin 		/* There is no Alternate MAC Address */
126d0d8f2a5Srin 		return IGC_SUCCESS;
127d0d8f2a5Srin 
128d0d8f2a5Srin 	if (hw->bus.func == IGC_FUNC_1)
129d0d8f2a5Srin 		nvm_alt_mac_addr_offset += IGC_ALT_MAC_ADDRESS_OFFSET_LAN1;
130d0d8f2a5Srin 	for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
131d0d8f2a5Srin 		offset = nvm_alt_mac_addr_offset + (i >> 1);
132d0d8f2a5Srin 		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
133d0d8f2a5Srin 		if (ret_val) {
134d0d8f2a5Srin 			DEBUGOUT("NVM Read Error\n");
135d0d8f2a5Srin 			return ret_val;
136d0d8f2a5Srin 		}
137d0d8f2a5Srin 
138d0d8f2a5Srin 		alt_mac_addr[i] = (uint8_t)(nvm_data & 0xFF);
139d0d8f2a5Srin 		alt_mac_addr[i + 1] = (uint8_t)(nvm_data >> 8);
140d0d8f2a5Srin 	}
141d0d8f2a5Srin 
142d0d8f2a5Srin 	/* if multicast bit is set, the alternate address will not be used */
143d0d8f2a5Srin 	if (alt_mac_addr[0] & 0x01) {
144d0d8f2a5Srin 		DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
145d0d8f2a5Srin 		return IGC_SUCCESS;
146d0d8f2a5Srin 	}
147d0d8f2a5Srin 
148d0d8f2a5Srin 	/* We have a valid alternate MAC address, and we want to treat it the
149d0d8f2a5Srin 	 * same as the normal permanent MAC address stored by the HW into the
150d0d8f2a5Srin 	 * RAR. Do this by mapping this address into RAR0.
151d0d8f2a5Srin 	 */
152d0d8f2a5Srin 	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
153d0d8f2a5Srin 
154d0d8f2a5Srin 	return IGC_SUCCESS;
155d0d8f2a5Srin }
156d0d8f2a5Srin 
157d0d8f2a5Srin /**
158d0d8f2a5Srin  *  igc_rar_set_generic - Set receive address register
159d0d8f2a5Srin  *  @hw: pointer to the HW structure
160d0d8f2a5Srin  *  @addr: pointer to the receive address
161d0d8f2a5Srin  *  @index: receive address array register
162d0d8f2a5Srin  *
163d0d8f2a5Srin  *  Sets the receive address array register at index to the address passed
164d0d8f2a5Srin  *  in by addr.
165d0d8f2a5Srin  **/
166d0d8f2a5Srin int
igc_rar_set_generic(struct igc_hw * hw,uint8_t * addr,uint32_t index)167d0d8f2a5Srin igc_rar_set_generic(struct igc_hw *hw, uint8_t *addr, uint32_t index)
168d0d8f2a5Srin {
169d0d8f2a5Srin 	uint32_t rar_low, rar_high;
170d0d8f2a5Srin 
171d0d8f2a5Srin 	DEBUGFUNC("igc_rar_set_generic");
172d0d8f2a5Srin 
173d0d8f2a5Srin 	/* HW expects these in little endian so we reverse the byte order
174d0d8f2a5Srin 	 * from network order (big endian) to little endian
175d0d8f2a5Srin 	 */
176d0d8f2a5Srin 	rar_low = ((uint32_t) addr[0] | ((uint32_t) addr[1] << 8) |
177d0d8f2a5Srin 	    ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
178d0d8f2a5Srin 
179d0d8f2a5Srin 	rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8));
180d0d8f2a5Srin 
181d0d8f2a5Srin 	/* If MAC address zero, no need to set the AV bit */
182d0d8f2a5Srin 	if (rar_low || rar_high)
183d0d8f2a5Srin 		rar_high |= IGC_RAH_AV;
184d0d8f2a5Srin 
185d0d8f2a5Srin 	/* Some bridges will combine consecutive 32-bit writes into
186d0d8f2a5Srin 	 * a single burst write, which will malfunction on some parts.
187d0d8f2a5Srin 	 * The flushes avoid this.
188d0d8f2a5Srin 	 */
189d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_RAL(index), rar_low);
190d0d8f2a5Srin 	IGC_WRITE_FLUSH(hw);
191d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_RAH(index), rar_high);
192d0d8f2a5Srin 	IGC_WRITE_FLUSH(hw);
193d0d8f2a5Srin 
194d0d8f2a5Srin 	return IGC_SUCCESS;
195d0d8f2a5Srin }
196d0d8f2a5Srin 
197d0d8f2a5Srin /**
198d0d8f2a5Srin  *  igc_hash_mc_addr_generic - Generate a multicast hash value
199d0d8f2a5Srin  *  @hw: pointer to the HW structure
200d0d8f2a5Srin  *  @mc_addr: pointer to a multicast address
201d0d8f2a5Srin  *
202d0d8f2a5Srin  *  Generates a multicast address hash value which is used to determine
203d0d8f2a5Srin  *  the multicast filter table array address and new table value.
204d0d8f2a5Srin  **/
205d0d8f2a5Srin int
igc_hash_mc_addr_generic(struct igc_hw * hw,uint8_t * mc_addr)206d0d8f2a5Srin igc_hash_mc_addr_generic(struct igc_hw *hw, uint8_t *mc_addr)
207d0d8f2a5Srin {
208d0d8f2a5Srin 	uint32_t hash_value, hash_mask;
209d0d8f2a5Srin 	uint8_t bit_shift = 0;
210d0d8f2a5Srin 
211d0d8f2a5Srin 	DEBUGFUNC("igc_hash_mc_addr_generic");
212d0d8f2a5Srin 
213d0d8f2a5Srin 	/* Register count multiplied by bits per register */
214d0d8f2a5Srin 	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
215d0d8f2a5Srin 
216d0d8f2a5Srin 	/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
217d0d8f2a5Srin 	 * where 0xFF would still fall within the hash mask.
218d0d8f2a5Srin 	 */
219d0d8f2a5Srin 	while (hash_mask >> bit_shift != 0xFF)
220d0d8f2a5Srin 		bit_shift++;
221d0d8f2a5Srin 
222d0d8f2a5Srin 	/* The portion of the address that is used for the hash table
223d0d8f2a5Srin 	 * is determined by the mc_filter_type setting.
224d0d8f2a5Srin 	 * The algorithm is such that there is a total of 8 bits of shifting.
225d0d8f2a5Srin 	 * The bit_shift for a mc_filter_type of 0 represents the number of
226d0d8f2a5Srin 	 * left-shifts where the MSB of mc_addr[5] would still fall within
227d0d8f2a5Srin 	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
228d0d8f2a5Srin 	 * of 8 bits of shifting, then mc_addr[4] will shift right the
229d0d8f2a5Srin 	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
230d0d8f2a5Srin 	 * cases are a variation of this algorithm...essentially raising the
231d0d8f2a5Srin 	 * number of bits to shift mc_addr[5] left, while still keeping the
232d0d8f2a5Srin 	 * 8-bit shifting total.
233d0d8f2a5Srin 	 *
234d0d8f2a5Srin 	 * For example, given the following Destination MAC Address and an
235d0d8f2a5Srin 	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
236d0d8f2a5Srin 	 * we can see that the bit_shift for case 0 is 4.  These are the hash
237d0d8f2a5Srin 	 * values resulting from each mc_filter_type...
238d0d8f2a5Srin 	 * [0] [1] [2] [3] [4] [5]
239d0d8f2a5Srin 	 * 01  AA  00  12  34  56
240d0d8f2a5Srin 	 * LSB		 MSB
241d0d8f2a5Srin 	 *
242d0d8f2a5Srin 	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
243d0d8f2a5Srin 	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
244d0d8f2a5Srin 	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
245d0d8f2a5Srin 	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
246d0d8f2a5Srin 	 */
247d0d8f2a5Srin 	switch (hw->mac.mc_filter_type) {
248d0d8f2a5Srin 	default:
249d0d8f2a5Srin 	case 0:
250d0d8f2a5Srin 		break;
251d0d8f2a5Srin 	case 1:
252d0d8f2a5Srin 		bit_shift += 1;
253d0d8f2a5Srin 		break;
254d0d8f2a5Srin 	case 2:
255d0d8f2a5Srin 		bit_shift += 2;
256d0d8f2a5Srin 		break;
257d0d8f2a5Srin 	case 3:
258d0d8f2a5Srin 		bit_shift += 4;
259d0d8f2a5Srin 		break;
260d0d8f2a5Srin 	}
261d0d8f2a5Srin 
262d0d8f2a5Srin 	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
263d0d8f2a5Srin 	    (((uint16_t) mc_addr[5]) << bit_shift)));
264d0d8f2a5Srin 
265d0d8f2a5Srin 	return hash_value;
266d0d8f2a5Srin }
267d0d8f2a5Srin 
268d0d8f2a5Srin /**
269d0d8f2a5Srin  *  igc_update_mc_addr_list_generic - Update Multicast addresses
270d0d8f2a5Srin  *  @hw: pointer to the HW structure
271d0d8f2a5Srin  *  @mc_addr_list: array of multicast addresses to program
272d0d8f2a5Srin  *  @mc_addr_count: number of multicast addresses to program
273d0d8f2a5Srin  *
274d0d8f2a5Srin  *  Updates entire Multicast Table Array.
275d0d8f2a5Srin  *  The caller must have a packed mc_addr_list of multicast addresses.
276d0d8f2a5Srin  **/
277d0d8f2a5Srin void
igc_update_mc_addr_list_generic(struct igc_hw * hw,uint8_t * mc_addr_list,uint32_t mc_addr_count)278d0d8f2a5Srin igc_update_mc_addr_list_generic(struct igc_hw *hw, uint8_t *mc_addr_list,
279d0d8f2a5Srin     uint32_t mc_addr_count)
280d0d8f2a5Srin {
281d0d8f2a5Srin 	uint32_t hash_value, hash_bit, hash_reg;
282d0d8f2a5Srin 	int i;
283d0d8f2a5Srin 
284d0d8f2a5Srin 	DEBUGFUNC("igc_update_mc_addr_list_generic");
285d0d8f2a5Srin 
286d0d8f2a5Srin 	/* clear mta_shadow */
287d0d8f2a5Srin 	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
288d0d8f2a5Srin 
289d0d8f2a5Srin 	/* update mta_shadow from mc_addr_list */
290d0d8f2a5Srin 	for (i = 0; (uint32_t)i < mc_addr_count; i++) {
291d0d8f2a5Srin 		hash_value = igc_hash_mc_addr_generic(hw, mc_addr_list);
292d0d8f2a5Srin 
293d0d8f2a5Srin 		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
294d0d8f2a5Srin 		hash_bit = hash_value & 0x1F;
295d0d8f2a5Srin 
296d0d8f2a5Srin 		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
297d0d8f2a5Srin 		mc_addr_list += (ETHER_ADDR_LEN);
298d0d8f2a5Srin 	}
299d0d8f2a5Srin 
300d0d8f2a5Srin 	/* replace the entire MTA table */
301d0d8f2a5Srin 	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
302d0d8f2a5Srin 		IGC_WRITE_REG_ARRAY(hw, IGC_MTA, i, hw->mac.mta_shadow[i]);
303d0d8f2a5Srin 	IGC_WRITE_FLUSH(hw);
304d0d8f2a5Srin }
305d0d8f2a5Srin 
306d0d8f2a5Srin /**
307d0d8f2a5Srin  *  igc_clear_hw_cntrs_base_generic - Clear base hardware counters
308d0d8f2a5Srin  *  @hw: pointer to the HW structure
309d0d8f2a5Srin  *
310d0d8f2a5Srin  *  Clears the base hardware counters by reading the counter registers.
311d0d8f2a5Srin  **/
312d0d8f2a5Srin void
igc_clear_hw_cntrs_base_generic(struct igc_hw * hw)313d0d8f2a5Srin igc_clear_hw_cntrs_base_generic(struct igc_hw *hw)
314d0d8f2a5Srin {
315d0d8f2a5Srin 	DEBUGFUNC("igc_clear_hw_cntrs_base_generic");
316d0d8f2a5Srin 
317d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_CRCERRS);
318*fb38d839Srin 	IGC_READ_REG(hw, IGC_ALGNERRC);
319d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_MPC);
320d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_SCC);
321d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_ECOL);
322d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_MCC);
323d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_LATECOL);
324d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_COLC);
325d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RERC);
326d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_DC);
327*fb38d839Srin 	IGC_READ_REG(hw, IGC_TNCRS);
328*fb38d839Srin 	IGC_READ_REG(hw, IGC_HTDPMC);
329d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RLEC);
330d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_XONRXC);
331d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_XONTXC);
332d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_XOFFRXC);
333d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_XOFFTXC);
334d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_FCRUC);
335*fb38d839Srin 	IGC_READ_REG(hw, IGC_PRC64);
336*fb38d839Srin 	IGC_READ_REG(hw, IGC_PRC127);
337*fb38d839Srin 	IGC_READ_REG(hw, IGC_PRC255);
338*fb38d839Srin 	IGC_READ_REG(hw, IGC_PRC511);
339*fb38d839Srin 	IGC_READ_REG(hw, IGC_PRC1023);
340*fb38d839Srin 	IGC_READ_REG(hw, IGC_PRC1522);
341d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_GPRC);
342d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_BPRC);
343d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_MPRC);
344d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_GPTC);
345d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_GORCL);
346d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_GORCH);
347d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_GOTCL);
348d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_GOTCH);
349d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RNBC);
350d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RUC);
351d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RFC);
352d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_ROC);
353d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RJC);
354*fb38d839Srin 	IGC_READ_REG(hw, IGC_MGTPRC);
355*fb38d839Srin 	IGC_READ_REG(hw, IGC_MGTPDC);
356*fb38d839Srin 	IGC_READ_REG(hw, IGC_MGTPTC);
357d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TORL);
358d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TORH);
359d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TOTL);
360d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TOTH);
361d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TPR);
362d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TPT);
363*fb38d839Srin 	IGC_READ_REG(hw, IGC_PTC64);
364*fb38d839Srin 	IGC_READ_REG(hw, IGC_PTC127);
365*fb38d839Srin 	IGC_READ_REG(hw, IGC_PTC255);
366*fb38d839Srin 	IGC_READ_REG(hw, IGC_PTC511);
367*fb38d839Srin 	IGC_READ_REG(hw, IGC_PTC1023);
368*fb38d839Srin 	IGC_READ_REG(hw, IGC_PTC1522);
369d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_MPTC);
370d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_BPTC);
371*fb38d839Srin 	IGC_READ_REG(hw, IGC_TSCTC);
372*fb38d839Srin 	IGC_READ_REG(hw, IGC_IAC);
373*fb38d839Srin 	IGC_READ_REG(hw, IGC_RXDMTC);
374*fb38d839Srin 	IGC_READ_REG(hw, IGC_HGORCL);
375*fb38d839Srin 	IGC_READ_REG(hw, IGC_HGORCH);
376*fb38d839Srin 	IGC_READ_REG(hw, IGC_HGOTCL);
377*fb38d839Srin 	IGC_READ_REG(hw, IGC_HGOTCH);
378*fb38d839Srin 	IGC_READ_REG(hw, IGC_LENERRS);
379d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_TLPIC);
380d0d8f2a5Srin 	IGC_READ_REG(hw, IGC_RLPIC);
381d0d8f2a5Srin }
382d0d8f2a5Srin 
383d0d8f2a5Srin /**
384d0d8f2a5Srin  *  igc_setup_link_generic - Setup flow control and link settings
385d0d8f2a5Srin  *  @hw: pointer to the HW structure
386d0d8f2a5Srin  *
387d0d8f2a5Srin  *  Determines which flow control settings to use, then configures flow
388d0d8f2a5Srin  *  control.  Calls the appropriate media-specific link configuration
389d0d8f2a5Srin  *  function.  Assuming the adapter has a valid link partner, a valid link
390d0d8f2a5Srin  *  should be established.  Assumes the hardware has previously been reset
391d0d8f2a5Srin  *  and the transmitter and receiver are not enabled.
392d0d8f2a5Srin  **/
393d0d8f2a5Srin int
igc_setup_link_generic(struct igc_hw * hw)394d0d8f2a5Srin igc_setup_link_generic(struct igc_hw *hw)
395d0d8f2a5Srin {
396d0d8f2a5Srin 	int ret_val;
397d0d8f2a5Srin 
398d0d8f2a5Srin 	DEBUGFUNC("igc_setup_link_generic");
399d0d8f2a5Srin 
400d0d8f2a5Srin 	/* In the case of the phy reset being blocked, we already have a link.
401d0d8f2a5Srin 	 * We do not need to set it up again.
402d0d8f2a5Srin 	 */
403d0d8f2a5Srin 	if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw))
404d0d8f2a5Srin 		return IGC_SUCCESS;
405d0d8f2a5Srin 
406d0d8f2a5Srin 	/* If requested flow control is set to default, set flow control
407d0d8f2a5Srin 	 * for both 'rx' and 'tx' pause frames.
408d0d8f2a5Srin 	 */
409d0d8f2a5Srin 	if (hw->fc.requested_mode == igc_fc_default) {
410d0d8f2a5Srin 		hw->fc.requested_mode = igc_fc_full;
411d0d8f2a5Srin 	}
412d0d8f2a5Srin 
413d0d8f2a5Srin 	/* Save off the requested flow control mode for use later.  Depending
414d0d8f2a5Srin 	 * on the link partner's capabilities, we may or may not use this mode.
415d0d8f2a5Srin 	 */
416d0d8f2a5Srin 	hw->fc.current_mode = hw->fc.requested_mode;
417d0d8f2a5Srin 
418d0d8f2a5Srin 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
419d0d8f2a5Srin 	    hw->fc.current_mode);
420d0d8f2a5Srin 
421d0d8f2a5Srin 	/* Call the necessary media_type subroutine to configure the link. */
422d0d8f2a5Srin 	ret_val = hw->mac.ops.setup_physical_interface(hw);
423d0d8f2a5Srin 	if (ret_val)
424d0d8f2a5Srin 		return ret_val;
425d0d8f2a5Srin 
426d0d8f2a5Srin 	/* Initialize the flow control address, type, and PAUSE timer
427d0d8f2a5Srin 	 * registers to their default values.  This is done even if flow
428d0d8f2a5Srin 	 * control is disabled, because it does not hurt anything to
429d0d8f2a5Srin 	 * initialize these registers.
430d0d8f2a5Srin 	 */
431d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_FCT, FLOW_CONTROL_TYPE);
432d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
433d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
434d0d8f2a5Srin 
435d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_FCTTV, hw->fc.pause_time);
436d0d8f2a5Srin 
437d0d8f2a5Srin 	return igc_set_fc_watermarks_generic(hw);
438d0d8f2a5Srin }
439d0d8f2a5Srin 
440d0d8f2a5Srin /**
441d0d8f2a5Srin  *  igc_config_collision_dist_generic - Configure collision distance
442d0d8f2a5Srin  *  @hw: pointer to the HW structure
443d0d8f2a5Srin  *
444d0d8f2a5Srin  *  Configures the collision distance to the default value and is used
445d0d8f2a5Srin  *  during link setup.
446d0d8f2a5Srin  **/
447d0d8f2a5Srin void
igc_config_collision_dist_generic(struct igc_hw * hw)448d0d8f2a5Srin igc_config_collision_dist_generic(struct igc_hw *hw)
449d0d8f2a5Srin {
450d0d8f2a5Srin 	uint32_t tctl;
451d0d8f2a5Srin 
452d0d8f2a5Srin 	DEBUGFUNC("igc_config_collision_dist_generic");
453d0d8f2a5Srin 
454d0d8f2a5Srin 	tctl = IGC_READ_REG(hw, IGC_TCTL);
455d0d8f2a5Srin 
456d0d8f2a5Srin 	tctl &= ~IGC_TCTL_COLD;
457d0d8f2a5Srin 	tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
458d0d8f2a5Srin 
459d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_TCTL, tctl);
460d0d8f2a5Srin 	IGC_WRITE_FLUSH(hw);
461d0d8f2a5Srin }
462d0d8f2a5Srin 
463d0d8f2a5Srin /**
464d0d8f2a5Srin  *  igc_set_fc_watermarks_generic - Set flow control high/low watermarks
465d0d8f2a5Srin  *  @hw: pointer to the HW structure
466d0d8f2a5Srin  *
467d0d8f2a5Srin  *  Sets the flow control high/low threshold (watermark) registers.  If
468d0d8f2a5Srin  *  flow control XON frame transmission is enabled, then set XON frame
469d0d8f2a5Srin  *  transmission as well.
470d0d8f2a5Srin  **/
471d0d8f2a5Srin int
igc_set_fc_watermarks_generic(struct igc_hw * hw)472d0d8f2a5Srin igc_set_fc_watermarks_generic(struct igc_hw *hw)
473d0d8f2a5Srin {
474d0d8f2a5Srin 	uint32_t fcrtl = 0, fcrth = 0;
475d0d8f2a5Srin 
476d0d8f2a5Srin 	DEBUGFUNC("igc_set_fc_watermarks_generic");
477d0d8f2a5Srin 
478d0d8f2a5Srin 	/* Set the flow control receive threshold registers.  Normally,
479d0d8f2a5Srin 	 * these registers will be set to a default threshold that may be
480d0d8f2a5Srin 	 * adjusted later by the driver's runtime code.  However, if the
481d0d8f2a5Srin 	 * ability to transmit pause frames is not enabled, then these
482d0d8f2a5Srin 	 * registers will be set to 0.
483d0d8f2a5Srin 	 */
484d0d8f2a5Srin 	if (hw->fc.current_mode & igc_fc_tx_pause) {
485d0d8f2a5Srin 		/* We need to set up the Receive Threshold high and low water
486d0d8f2a5Srin 		 * marks as well as (optionally) enabling the transmission of
487d0d8f2a5Srin 		 * XON frames.
488d0d8f2a5Srin 		 */
489d0d8f2a5Srin 		fcrtl = hw->fc.low_water;
490d0d8f2a5Srin 		if (hw->fc.send_xon)
491d0d8f2a5Srin 			fcrtl |= IGC_FCRTL_XONE;
492d0d8f2a5Srin 
493d0d8f2a5Srin 		fcrth = hw->fc.high_water;
494d0d8f2a5Srin 	}
495d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_FCRTL, fcrtl);
496d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_FCRTH, fcrth);
497d0d8f2a5Srin 
498d0d8f2a5Srin 	return IGC_SUCCESS;
499d0d8f2a5Srin }
500d0d8f2a5Srin 
501d0d8f2a5Srin /**
502d0d8f2a5Srin  *  igc_force_mac_fc_generic - Force the MAC's flow control settings
503d0d8f2a5Srin  *  @hw: pointer to the HW structure
504d0d8f2a5Srin  *
505d0d8f2a5Srin  *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
506d0d8f2a5Srin  *  device control register to reflect the adapter settings.  TFCE and RFCE
507d0d8f2a5Srin  *  need to be explicitly set by software when a copper PHY is used because
508d0d8f2a5Srin  *  autonegotiation is managed by the PHY rather than the MAC.  Software must
509d0d8f2a5Srin  *  also configure these bits when link is forced on a fiber connection.
510d0d8f2a5Srin  **/
511d0d8f2a5Srin int
igc_force_mac_fc_generic(struct igc_hw * hw)512d0d8f2a5Srin igc_force_mac_fc_generic(struct igc_hw *hw)
513d0d8f2a5Srin {
514d0d8f2a5Srin 	uint32_t ctrl;
515d0d8f2a5Srin 
516d0d8f2a5Srin 	DEBUGFUNC("igc_force_mac_fc_generic");
517d0d8f2a5Srin 
518d0d8f2a5Srin 	ctrl = IGC_READ_REG(hw, IGC_CTRL);
519d0d8f2a5Srin 
520d0d8f2a5Srin 	/* Because we didn't get link via the internal auto-negotiation
521d0d8f2a5Srin 	 * mechanism (we either forced link or we got link via PHY
522d0d8f2a5Srin 	 * auto-neg), we have to manually enable/disable transmit an
523d0d8f2a5Srin 	 * receive flow control.
524d0d8f2a5Srin 	 *
525d0d8f2a5Srin 	 * The "Case" statement below enables/disable flow control
526d0d8f2a5Srin 	 * according to the "hw->fc.current_mode" parameter.
527d0d8f2a5Srin 	 *
528d0d8f2a5Srin 	 * The possible values of the "fc" parameter are:
529d0d8f2a5Srin 	 *      0:  Flow control is completely disabled
530d0d8f2a5Srin 	 *      1:  Rx flow control is enabled (we can receive pause
531d0d8f2a5Srin 	 *          frames but not send pause frames).
532d0d8f2a5Srin 	 *      2:  Tx flow control is enabled (we can send pause frames
533d0d8f2a5Srin 	 *          frames but we do not receive pause frames).
534d0d8f2a5Srin 	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
535d0d8f2a5Srin 	 *  other:  No other values should be possible at this point.
536d0d8f2a5Srin 	 */
537d0d8f2a5Srin 	DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
538d0d8f2a5Srin 
539d0d8f2a5Srin 	switch (hw->fc.current_mode) {
540d0d8f2a5Srin 	case igc_fc_none:
541d0d8f2a5Srin 		ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
542d0d8f2a5Srin 		break;
543d0d8f2a5Srin 	case igc_fc_rx_pause:
544d0d8f2a5Srin 		ctrl &= (~IGC_CTRL_TFCE);
545d0d8f2a5Srin 		ctrl |= IGC_CTRL_RFCE;
546d0d8f2a5Srin 		break;
547d0d8f2a5Srin 	case igc_fc_tx_pause:
548d0d8f2a5Srin 		ctrl &= (~IGC_CTRL_RFCE);
549d0d8f2a5Srin 		ctrl |= IGC_CTRL_TFCE;
550d0d8f2a5Srin 		break;
551d0d8f2a5Srin 	case igc_fc_full:
552d0d8f2a5Srin 		ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
553d0d8f2a5Srin 		break;
554d0d8f2a5Srin 	default:
555d0d8f2a5Srin 		DEBUGOUT("Flow control param set incorrectly\n");
556d0d8f2a5Srin 		return -IGC_ERR_CONFIG;
557d0d8f2a5Srin 	}
558d0d8f2a5Srin 
559d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_CTRL, ctrl);
560d0d8f2a5Srin 
561d0d8f2a5Srin 	return IGC_SUCCESS;
562d0d8f2a5Srin }
563d0d8f2a5Srin 
564d0d8f2a5Srin /**
565d0d8f2a5Srin  *  igc_config_fc_after_link_up_generic - Configures flow control after link
566d0d8f2a5Srin  *  @hw: pointer to the HW structure
567d0d8f2a5Srin  *
568d0d8f2a5Srin  *  Checks the status of auto-negotiation after link up to ensure that the
569d0d8f2a5Srin  *  speed and duplex were not forced.  If the link needed to be forced, then
570d0d8f2a5Srin  *  flow control needs to be forced also.  If auto-negotiation is enabled
571d0d8f2a5Srin  *  and did not fail, then we configure flow control based on our link
572d0d8f2a5Srin  *  partner.
573d0d8f2a5Srin  **/
574d0d8f2a5Srin int
igc_config_fc_after_link_up_generic(struct igc_hw * hw)575d0d8f2a5Srin igc_config_fc_after_link_up_generic(struct igc_hw *hw)
576d0d8f2a5Srin {
577d0d8f2a5Srin 	struct igc_mac_info *mac = &hw->mac;
578d0d8f2a5Srin 	uint16_t mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
579d0d8f2a5Srin 	uint16_t speed, duplex;
580d0d8f2a5Srin 	int ret_val = IGC_SUCCESS;
581d0d8f2a5Srin 
582d0d8f2a5Srin 	DEBUGFUNC("igc_config_fc_after_link_up_generic");
583d0d8f2a5Srin 
584d0d8f2a5Srin 	if (ret_val) {
585d0d8f2a5Srin 		DEBUGOUT("Error forcing flow control settings\n");
586d0d8f2a5Srin 		return ret_val;
587d0d8f2a5Srin 	}
588d0d8f2a5Srin 
589d0d8f2a5Srin 	/* Check for the case where we have copper media and auto-neg is
590d0d8f2a5Srin 	 * enabled.  In this case, we need to check and see if Auto-Neg
591d0d8f2a5Srin 	 * has completed, and if so, how the PHY and link partner has
592d0d8f2a5Srin 	 * flow control configured.
593d0d8f2a5Srin 	 */
594d0d8f2a5Srin 	if (mac->autoneg) {
595d0d8f2a5Srin 		/* Read the MII Status Register and check to see if AutoNeg
596d0d8f2a5Srin 		 * has completed.  We read this twice because this reg has
597d0d8f2a5Srin 		 * some "sticky" (latched) bits.
598d0d8f2a5Srin 		 */
599*fb38d839Srin 		ret_val = hw->phy.ops.read_reg(hw, MII_BMSR, &mii_status_reg);
600d0d8f2a5Srin 		if (ret_val)
601d0d8f2a5Srin 			return ret_val;
602*fb38d839Srin 		ret_val = hw->phy.ops.read_reg(hw, MII_BMSR, &mii_status_reg);
603d0d8f2a5Srin 		if (ret_val)
604d0d8f2a5Srin 			return ret_val;
605d0d8f2a5Srin 
606d0d8f2a5Srin 		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE))
607d0d8f2a5Srin 			return ret_val;
608d0d8f2a5Srin 
609d0d8f2a5Srin 		/* The AutoNeg process has completed, so we now need to
610d0d8f2a5Srin 		 * read both the Auto Negotiation Advertisement
611d0d8f2a5Srin 		 * Register (Address 4) and the Auto_Negotiation Base
612d0d8f2a5Srin 		 * Page Ability Register (Address 5) to determine how
613d0d8f2a5Srin 		 * flow control was negotiated.
614d0d8f2a5Srin 		 */
615d0d8f2a5Srin 		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
616d0d8f2a5Srin 		    &mii_nway_adv_reg);
617d0d8f2a5Srin 		if (ret_val)
618d0d8f2a5Srin 			return ret_val;
619d0d8f2a5Srin 		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
620d0d8f2a5Srin 		    &mii_nway_lp_ability_reg);
621d0d8f2a5Srin 		if (ret_val)
622d0d8f2a5Srin 			return ret_val;
623d0d8f2a5Srin 
624d0d8f2a5Srin 		/* Two bits in the Auto Negotiation Advertisement Register
625d0d8f2a5Srin 		 * (Address 4) and two bits in the Auto Negotiation Base
626d0d8f2a5Srin 		 * Page Ability Register (Address 5) determine flow control
627d0d8f2a5Srin 		 * for both the PHY and the link partner.  The following
628d0d8f2a5Srin 		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
629d0d8f2a5Srin 		 * 1999, describes these PAUSE resolution bits and how flow
630d0d8f2a5Srin 		 * control is determined based upon these settings.
631d0d8f2a5Srin 		 * NOTE:  DC = Don't Care
632d0d8f2a5Srin 		 *
633d0d8f2a5Srin 		 *   LOCAL DEVICE  |   LINK PARTNER
634d0d8f2a5Srin 		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
635d0d8f2a5Srin 		 *-------|---------|-------|---------|--------------------
636d0d8f2a5Srin 		 *   0   |    0    |  DC   |   DC    | igc_fc_none
637d0d8f2a5Srin 		 *   0   |    1    |   0   |   DC    | igc_fc_none
638d0d8f2a5Srin 		 *   0   |    1    |   1   |    0    | igc_fc_none
639d0d8f2a5Srin 		 *   0   |    1    |   1   |    1    | igc_fc_tx_pause
640d0d8f2a5Srin 		 *   1   |    0    |   0   |   DC    | igc_fc_none
641d0d8f2a5Srin 		 *   1   |   DC    |   1   |   DC    | igc_fc_full
642d0d8f2a5Srin 		 *   1   |    1    |   0   |    0    | igc_fc_none
643d0d8f2a5Srin 		 *   1   |    1    |   0   |    1    | igc_fc_rx_pause
644d0d8f2a5Srin 		 *
645d0d8f2a5Srin 		 * Are both PAUSE bits set to 1?  If so, this implies
646d0d8f2a5Srin 		 * Symmetric Flow Control is enabled at both ends.  The
647d0d8f2a5Srin 		 * ASM_DIR bits are irrelevant per the spec.
648d0d8f2a5Srin 		 *
649d0d8f2a5Srin 		 * For Symmetric Flow Control:
650d0d8f2a5Srin 		 *
651d0d8f2a5Srin 		 *   LOCAL DEVICE  |   LINK PARTNER
652d0d8f2a5Srin 		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
653d0d8f2a5Srin 		 *-------|---------|-------|---------|--------------------
654d0d8f2a5Srin 		 *   1   |   DC    |   1   |   DC    | IGC_fc_full
655d0d8f2a5Srin 		 *
656d0d8f2a5Srin 		 */
657d0d8f2a5Srin 		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
658d0d8f2a5Srin 		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
659d0d8f2a5Srin 			/* Now we need to check if the user selected Rx ONLY
660d0d8f2a5Srin 			 * of pause frames.  In this case, we had to advertise
661d0d8f2a5Srin 			 * FULL flow control because we could not advertise Rx
662d0d8f2a5Srin 			 * ONLY. Hence, we must now check to see if we need to
663d0d8f2a5Srin 			 * turn OFF the TRANSMISSION of PAUSE frames.
664d0d8f2a5Srin 			 */
665d0d8f2a5Srin 			if (hw->fc.requested_mode == igc_fc_full)
666d0d8f2a5Srin 				hw->fc.current_mode = igc_fc_full;
667d0d8f2a5Srin 			else
668d0d8f2a5Srin 				hw->fc.current_mode = igc_fc_rx_pause;
669d0d8f2a5Srin 		}
670d0d8f2a5Srin 		/* For receiving PAUSE frames ONLY.
671d0d8f2a5Srin 		 *
672d0d8f2a5Srin 		 *   LOCAL DEVICE  |   LINK PARTNER
673d0d8f2a5Srin 		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
674d0d8f2a5Srin 		 *-------|---------|-------|---------|--------------------
675d0d8f2a5Srin 		 *   0   |    1    |   1   |    1    | igc_fc_tx_pause
676d0d8f2a5Srin 		 */
677d0d8f2a5Srin 		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
678d0d8f2a5Srin 			  (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
679d0d8f2a5Srin 			  (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
680d0d8f2a5Srin 			  (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
681d0d8f2a5Srin 				hw->fc.current_mode = igc_fc_tx_pause;
682d0d8f2a5Srin 		}
683d0d8f2a5Srin 		/* For transmitting PAUSE frames ONLY.
684d0d8f2a5Srin 		 *
685d0d8f2a5Srin 		 *   LOCAL DEVICE  |   LINK PARTNER
686d0d8f2a5Srin 		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
687d0d8f2a5Srin 		 *-------|---------|-------|---------|--------------------
688d0d8f2a5Srin 		 *   1   |    1    |   0   |    1    | igc_fc_rx_pause
689d0d8f2a5Srin 		 */
690d0d8f2a5Srin 		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
691d0d8f2a5Srin 			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
692d0d8f2a5Srin 			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
693d0d8f2a5Srin 			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
694d0d8f2a5Srin 				hw->fc.current_mode = igc_fc_rx_pause;
695d0d8f2a5Srin 		} else {
696d0d8f2a5Srin 			/* Per the IEEE spec, at this point flow control
697d0d8f2a5Srin 			 * should be disabled.
698d0d8f2a5Srin 			 */
699d0d8f2a5Srin 			hw->fc.current_mode = igc_fc_none;
700d0d8f2a5Srin 			DEBUGOUT("Flow Control = NONE.\n");
701d0d8f2a5Srin 		}
702d0d8f2a5Srin 
703d0d8f2a5Srin 		/* Now we need to do one last check...  If we auto-
704d0d8f2a5Srin 		 * negotiated to HALF DUPLEX, flow control should not be
705d0d8f2a5Srin 		 * enabled per IEEE 802.3 spec.
706d0d8f2a5Srin 		 */
707d0d8f2a5Srin 		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
708d0d8f2a5Srin 		if (ret_val) {
709d0d8f2a5Srin 			DEBUGOUT("Error getting link speed and duplex\n");
710d0d8f2a5Srin 			return ret_val;
711d0d8f2a5Srin 		}
712d0d8f2a5Srin 
713d0d8f2a5Srin 		if (duplex == HALF_DUPLEX)
714d0d8f2a5Srin 			hw->fc.current_mode = igc_fc_none;
715d0d8f2a5Srin 
716d0d8f2a5Srin 		/* Now we call a subroutine to actually force the MAC
717d0d8f2a5Srin 		 * controller to use the correct flow control settings.
718d0d8f2a5Srin 		 */
719d0d8f2a5Srin 		ret_val = igc_force_mac_fc_generic(hw);
720d0d8f2a5Srin 		if (ret_val) {
721d0d8f2a5Srin 			DEBUGOUT("Error forcing flow control settings\n");
722d0d8f2a5Srin 			return ret_val;
723d0d8f2a5Srin 		}
724d0d8f2a5Srin 	}
725d0d8f2a5Srin 
726d0d8f2a5Srin 	return IGC_SUCCESS;
727d0d8f2a5Srin }
728d0d8f2a5Srin 
729d0d8f2a5Srin /**
730d0d8f2a5Srin  *  igc_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
731d0d8f2a5Srin  *  @hw: pointer to the HW structure
732d0d8f2a5Srin  *  @speed: stores the current speed
733d0d8f2a5Srin  *  @duplex: stores the current duplex
734d0d8f2a5Srin  *
735d0d8f2a5Srin  *  Read the status register for the current speed/duplex and store the current
736d0d8f2a5Srin  *  speed and duplex for copper connections.
737d0d8f2a5Srin  **/
738d0d8f2a5Srin int
igc_get_speed_and_duplex_copper_generic(struct igc_hw * hw,uint16_t * speed,uint16_t * duplex)739d0d8f2a5Srin igc_get_speed_and_duplex_copper_generic(struct igc_hw *hw, uint16_t *speed,
740d0d8f2a5Srin     uint16_t *duplex)
741d0d8f2a5Srin {
742d0d8f2a5Srin 	uint32_t status;
743d0d8f2a5Srin 
744d0d8f2a5Srin 	DEBUGFUNC("igc_get_speed_and_duplex_copper_generic");
745d0d8f2a5Srin 
746d0d8f2a5Srin 	status = IGC_READ_REG(hw, IGC_STATUS);
747d0d8f2a5Srin 	if (status & IGC_STATUS_SPEED_1000) {
748d0d8f2a5Srin 		/* For I225, STATUS will indicate 1G speed in both 1 Gbps
749d0d8f2a5Srin 		 * and 2.5 Gbps link modes. An additional bit is used
750d0d8f2a5Srin 		 * to differentiate between 1 Gbps and 2.5 Gbps.
751d0d8f2a5Srin 		 */
752d0d8f2a5Srin 		if ((hw->mac.type == igc_i225) &&
753d0d8f2a5Srin 		    (status & IGC_STATUS_SPEED_2500)) {
754d0d8f2a5Srin 			*speed = SPEED_2500;
755d0d8f2a5Srin 			DEBUGOUT("2500 Mbs, ");
756d0d8f2a5Srin 		} else {
757d0d8f2a5Srin 			*speed = SPEED_1000;
758d0d8f2a5Srin 			DEBUGOUT("1000 Mbs, ");
759d0d8f2a5Srin 		}
760d0d8f2a5Srin 	} else if (status & IGC_STATUS_SPEED_100) {
761d0d8f2a5Srin 		*speed = SPEED_100;
762d0d8f2a5Srin 		DEBUGOUT("100 Mbs, ");
763d0d8f2a5Srin 	} else {
764d0d8f2a5Srin 		*speed = SPEED_10;
765d0d8f2a5Srin 		DEBUGOUT("10 Mbs, ");
766d0d8f2a5Srin 	}
767d0d8f2a5Srin 
768d0d8f2a5Srin 	if (status & IGC_STATUS_FD) {
769d0d8f2a5Srin 		*duplex = FULL_DUPLEX;
770d0d8f2a5Srin 		DEBUGOUT("Full Duplex\n");
771d0d8f2a5Srin 	} else {
772d0d8f2a5Srin 		*duplex = HALF_DUPLEX;
773d0d8f2a5Srin 		DEBUGOUT("Half Duplex\n");
774d0d8f2a5Srin 	}
775d0d8f2a5Srin 
776d0d8f2a5Srin 	return IGC_SUCCESS;
777d0d8f2a5Srin }
778d0d8f2a5Srin 
779d0d8f2a5Srin /**
780d0d8f2a5Srin  *  igc_put_hw_semaphore_generic - Release hardware semaphore
781d0d8f2a5Srin  *  @hw: pointer to the HW structure
782d0d8f2a5Srin  *
783d0d8f2a5Srin  *  Release hardware semaphore used to access the PHY or NVM
784d0d8f2a5Srin  **/
785d0d8f2a5Srin void
igc_put_hw_semaphore_generic(struct igc_hw * hw)786d0d8f2a5Srin igc_put_hw_semaphore_generic(struct igc_hw *hw)
787d0d8f2a5Srin {
788d0d8f2a5Srin 	uint32_t swsm;
789d0d8f2a5Srin 
790d0d8f2a5Srin         DEBUGFUNC("igc_put_hw_semaphore_generic");
791d0d8f2a5Srin 
792d0d8f2a5Srin 	swsm = IGC_READ_REG(hw, IGC_SWSM);
793d0d8f2a5Srin 	swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
794d0d8f2a5Srin 
795d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_SWSM, swsm);
796d0d8f2a5Srin }
797d0d8f2a5Srin 
798d0d8f2a5Srin /**
799d0d8f2a5Srin  *  igc_get_auto_rd_done_generic - Check for auto read completion
800d0d8f2a5Srin  *  @hw: pointer to the HW structure
801d0d8f2a5Srin  *
802d0d8f2a5Srin  *  Check EEPROM for Auto Read done bit.
803d0d8f2a5Srin  **/
804d0d8f2a5Srin int
igc_get_auto_rd_done_generic(struct igc_hw * hw)805d0d8f2a5Srin igc_get_auto_rd_done_generic(struct igc_hw *hw)
806d0d8f2a5Srin {
807d0d8f2a5Srin 	int i = 0;
808d0d8f2a5Srin 
809d0d8f2a5Srin 	DEBUGFUNC("igc_get_auto_rd_done_generic");
810d0d8f2a5Srin 
811d0d8f2a5Srin 	while (i < AUTO_READ_DONE_TIMEOUT) {
812d0d8f2a5Srin 		if (IGC_READ_REG(hw, IGC_EECD) & IGC_EECD_AUTO_RD)
813d0d8f2a5Srin 			break;
814d0d8f2a5Srin 		msec_delay(1);
815d0d8f2a5Srin 		i++;
816d0d8f2a5Srin 	}
817d0d8f2a5Srin 
818d0d8f2a5Srin 	if (i == AUTO_READ_DONE_TIMEOUT) {
819d0d8f2a5Srin 		DEBUGOUT("Auto read by HW from NVM has not completed.\n");
820d0d8f2a5Srin 		return -IGC_ERR_RESET;
821d0d8f2a5Srin 	}
822d0d8f2a5Srin 
823d0d8f2a5Srin 	return IGC_SUCCESS;
824d0d8f2a5Srin }
825d0d8f2a5Srin 
826d0d8f2a5Srin /**
827d0d8f2a5Srin  *  igc_disable_pcie_master_generic - Disables PCI-express master access
828d0d8f2a5Srin  *  @hw: pointer to the HW structure
829d0d8f2a5Srin  *
830d0d8f2a5Srin  *  Returns IGC_SUCCESS if successful, else returns -10
831d0d8f2a5Srin  *  (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
832d0d8f2a5Srin  *  the master requests to be disabled.
833d0d8f2a5Srin  *
834d0d8f2a5Srin  *  Disables PCI-Express master access and verifies there are no pending
835d0d8f2a5Srin  *  requests.
836d0d8f2a5Srin  **/
837d0d8f2a5Srin int
igc_disable_pcie_master_generic(struct igc_hw * hw)838d0d8f2a5Srin igc_disable_pcie_master_generic(struct igc_hw *hw)
839d0d8f2a5Srin {
840d0d8f2a5Srin 	uint32_t ctrl;
841d0d8f2a5Srin 	int timeout = MASTER_DISABLE_TIMEOUT;
842d0d8f2a5Srin 
843d0d8f2a5Srin 	DEBUGFUNC("igc_disable_pcie_master_generic");
844d0d8f2a5Srin 
845d0d8f2a5Srin 	ctrl = IGC_READ_REG(hw, IGC_CTRL);
846d0d8f2a5Srin 	ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
847d0d8f2a5Srin 	IGC_WRITE_REG(hw, IGC_CTRL, ctrl);
848d0d8f2a5Srin 
849d0d8f2a5Srin 	while (timeout) {
850d0d8f2a5Srin 		if (!(IGC_READ_REG(hw, IGC_STATUS) &
851d0d8f2a5Srin 		    IGC_STATUS_GIO_MASTER_ENABLE))
852d0d8f2a5Srin 			break;
853d0d8f2a5Srin 		DELAY(100);
854d0d8f2a5Srin 		timeout--;
855d0d8f2a5Srin 	}
856d0d8f2a5Srin 
857d0d8f2a5Srin 	if (!timeout) {
858d0d8f2a5Srin 		DEBUGOUT("Master requests are pending.\n");
859d0d8f2a5Srin 		return -IGC_ERR_MASTER_REQUESTS_PENDING;
860d0d8f2a5Srin 	}
861d0d8f2a5Srin 
862d0d8f2a5Srin 	return IGC_SUCCESS;
863d0d8f2a5Srin }
864