1 /*
2 * This file is provided under a CDDLv1 license. When using or
3 * redistributing this file, you may do so under this license.
4 * In redistributing this file this license must be included
5 * and no other modification of this header file is permitted.
6 *
7 * CDDL LICENSE SUMMARY
8 *
9 * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
10 *
11 * The contents of this file are subject to the terms of Version
12 * 1.0 of the Common Development and Distribution License (the "License").
13 *
14 * You should have received a copy of the License with this software.
15 * You can obtain a copy of the License at
16 * http://www.opensolaris.org/os/licensing.
17 * See the License for the specific language governing permissions
18 * and limitations under the License.
19 */
20
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms of the CDDLv1.
24 */
25 #include "e1000_api.h"
26
27 /*
28 * e1000_ttl_workaround_enabled_82541 - Returns current TTL workaround status
29 * @hw: pointer to the HW structure
30 *
31 * Returns the current status of the TTL workaround, as to whether the
32 * workaround is enabled or disabled.
33 */
34 bool
e1000_ttl_workaround_enabled_82541(struct e1000_hw * hw)35 e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
36 {
37 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
38 bool state = false;
39
40 DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
41
42 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
43 goto out;
44
45 state = dev_spec->ttl_workaround;
46
47 out:
48 return (state);
49 }
50
51 /*
52 * e1000_fifo_workaround_82547 - Workaround for Tx fifo failure
53 * @hw: pointer to the HW structure
54 * @length: length of next outgoing frame
55 *
56 * Returns: E1000_ERR_FIFO_WRAP if the next packet cannot be transmitted yet
57 * E1000_SUCCESS if the next packet can be transmitted
58 *
59 * Workaround for the 82547 Tx fifo failure.
60 */
61 s32
e1000_fifo_workaround_82547(struct e1000_hw * hw,u16 length)62 e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
63 {
64 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
65 u32 tctl;
66 s32 ret_val = E1000_SUCCESS;
67 u16 fifo_pkt_len;
68
69 DEBUGFUNC("e1000_fifo_workaround_82547");
70
71 if (hw->mac.type != e1000_82547)
72 goto out;
73
74 /*
75 * Get the length as seen by the FIFO of the next real
76 * packet to be transmitted.
77 */
78 fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
79 E1000_FIFO_GRANULARITY);
80
81 if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
82 goto out;
83
84 if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
85 (dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
86 goto out;
87
88 if (E1000_READ_REG(hw, E1000_TDT(0)) !=
89 E1000_READ_REG(hw, E1000_TDH(0))) {
90 ret_val = -E1000_ERR_FIFO_WRAP;
91 goto out;
92 }
93
94 if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
95 ret_val = -E1000_ERR_FIFO_WRAP;
96 goto out;
97 }
98
99 if (E1000_READ_REG(hw, E1000_TDFTS) !=
100 E1000_READ_REG(hw, E1000_TDFHS)) {
101 ret_val = -E1000_ERR_FIFO_WRAP;
102 goto out;
103 }
104
105 /* Disable the tx unit to avoid further pointer movement */
106 tctl = E1000_READ_REG(hw, E1000_TCTL);
107 E1000_WRITE_REG(hw, E1000_TCTL, tctl & ~E1000_TCTL_EN);
108
109 /* Reset the fifo pointers. */
110 E1000_WRITE_REG(hw, E1000_TDFT, dev_spec->tx_fifo_start);
111 E1000_WRITE_REG(hw, E1000_TDFH, dev_spec->tx_fifo_start);
112 E1000_WRITE_REG(hw, E1000_TDFTS, dev_spec->tx_fifo_start);
113 E1000_WRITE_REG(hw, E1000_TDFHS, dev_spec->tx_fifo_start);
114
115 /* Re-enabling tx unit */
116 E1000_WRITE_REG(hw, E1000_TCTL, tctl);
117 E1000_WRITE_FLUSH(hw);
118
119 dev_spec->tx_fifo_head = 0;
120
121 out:
122 return (ret_val);
123 }
124
125 /*
126 * e1000_update_tx_fifo_head - Update Tx fifo head pointer
127 * @hw: pointer to the HW structure
128 * @length: length of next outgoing frame
129 *
130 * Updates the SW calculated Tx FIFO head pointer.
131 */
132 void
e1000_update_tx_fifo_head_82547(struct e1000_hw * hw,u32 length)133 e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
134 {
135 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
136
137 DEBUGFUNC("e1000_update_tx_fifo_head_82547");
138
139 if (hw->mac.type != e1000_82547)
140 return;
141
142 dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
143 E1000_FIFO_GRANULARITY);
144
145 if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
146 dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
147 }
148
149 /*
150 * e1000_set_ttl_workaround_state_82541 - Enable/Disables TTL workaround
151 * @hw: pointer to the HW structure
152 * @state: boolean to enable/disable TTL workaround
153 *
154 * For 82541 or 82547 only silicon, allows the driver to enable/disable the
155 * TTL workaround.
156 */
157 void
e1000_set_ttl_workaround_state_82541(struct e1000_hw * hw,bool state)158 e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
159 {
160 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
161
162 DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
163
164 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
165 return;
166
167 dev_spec->ttl_workaround = state;
168 }
169
170 /*
171 * e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
172 * @hw: pointer to the HW structure
173 *
174 * Returns: E1000_ERR_PHY if fail to read/write the PHY
175 * E1000_SUCCESS in any other case
176 *
177 * This function, specific to 82547 hardware only, needs to be called every
178 * second. It checks if a parallel detect fault has occurred. If a fault
179 * occurred, disable/enable the DSP reset mechanism up to 5 times (once per
180 * second). If link is established, stop the workaround and ensure the DSP
181 * reset is enabled.
182 */
183 s32
e1000_igp_ttl_workaround_82547(struct e1000_hw * hw)184 e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
185 {
186 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
187 s32 ret_val = E1000_SUCCESS;
188 u16 phy_data = 0;
189 u16 dsp_value = DSP_RESET_ENABLE;
190 bool link;
191
192 DEBUGFUNC("e1000_igp_ttl_workaround_82547");
193
194 /* The workaround needed only for B-0 silicon HW */
195 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
196 goto out;
197
198 if (!(e1000_ttl_workaround_enabled_82541(hw)))
199 goto out;
200
201 /* Check for link first */
202 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
203 if (ret_val)
204 goto out;
205
206 if (link) {
207 /*
208 * If link is established during the workaround,
209 * the DSP mechanism must be enabled.
210 */
211 if (dev_spec->dsp_reset_counter) {
212 dev_spec->dsp_reset_counter = 0;
213 dsp_value = DSP_RESET_ENABLE;
214 } else {
215 ret_val = E1000_SUCCESS;
216 goto out;
217 }
218 } else {
219 if (dev_spec->dsp_reset_counter == 0) {
220 /*
221 * Workaround not activated,
222 * check if it needs activation
223 */
224 ret_val = hw->phy.ops.read_reg(hw,
225 PHY_AUTONEG_EXP,
226 &phy_data);
227 if (ret_val)
228 goto out;
229 /*
230 * Activate the workaround if there was a
231 * parallel detect fault
232 */
233 if (phy_data & NWAY_ER_PAR_DETECT_FAULT) {
234 dev_spec->dsp_reset_counter++;
235 } else {
236 ret_val = E1000_SUCCESS;
237 goto out;
238 }
239 }
240
241 /* After 5 times, stop the workaround */
242 if (dev_spec->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
243 dev_spec->dsp_reset_counter = 0;
244 dsp_value = DSP_RESET_ENABLE;
245 } else {
246 if (dev_spec->dsp_reset_counter) {
247 dsp_value = (dev_spec->dsp_reset_counter & 1)
248 ? DSP_RESET_DISABLE
249 : DSP_RESET_ENABLE;
250 dev_spec->dsp_reset_counter++;
251 }
252 }
253 }
254
255 ret_val =
256 hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);
257
258 out:
259 return (ret_val);
260 }
261