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