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 #define E1000_FIFO_MULTIPLIER 0x80
28 #define E1000_FIFO_HDR_SIZE 0x10
29 #define E1000_FIFO_GRANULARITY 0x10
30 #define E1000_FIFO_PAD_82547 0x3E0
31 #define E1000_ERR_FIFO_WRAP 8
32
33 #define DSP_RESET_ENABLE 0x0
34 #define DSP_RESET_DISABLE 0x2
35 #define E1000_MAX_DSP_RESETS 10
36
37 #define E1000_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
38
39
40 /*
41 * e1000_ttl_workaround_enabled_82541 - Returns current TTL workaround status
42 * @hw: pointer to the HW structure
43 *
44 * Returns the current status of the TTL workaround, as to whether the
45 * workaround is enabled or disabled.
46 */
47 bool
e1000_ttl_workaround_enabled_82541(struct e1000_hw * hw)48 e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
49 {
50 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
51 bool state = false;
52
53 DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
54
55 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
56 goto out;
57
58 state = dev_spec->ttl_workaround;
59
60 out:
61 return (state);
62 }
63
64 /*
65 * e1000_fifo_workaround_82547 - Workaround for Tx fifo failure
66 * @hw: pointer to the HW structure
67 * @length: length of next outgoing frame
68 *
69 * Returns: E1000_ERR_FIFO_WRAP if the next packet cannot be transmitted yet
70 * E1000_SUCCESS if the next packet can be transmitted
71 *
72 * Workaround for the 82547 Tx fifo failure.
73 */
74 s32
e1000_fifo_workaround_82547(struct e1000_hw * hw,u16 length)75 e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
76 {
77 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
78 u32 tctl;
79 s32 ret_val = E1000_SUCCESS;
80 u16 fifo_pkt_len;
81
82 DEBUGFUNC("e1000_fifo_workaround_82547");
83
84 if (hw->mac.type != e1000_82547)
85 goto out;
86
87 /*
88 * Get the length as seen by the FIFO of the next real
89 * packet to be transmitted.
90 */
91 fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
92 E1000_FIFO_GRANULARITY);
93
94 if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
95 goto out;
96
97 if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
98 (dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
99 goto out;
100
101 if (E1000_READ_REG(hw, E1000_TDT(0)) !=
102 E1000_READ_REG(hw, E1000_TDH(0))) {
103 ret_val = -E1000_ERR_FIFO_WRAP;
104 goto out;
105 }
106
107 if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
108 ret_val = -E1000_ERR_FIFO_WRAP;
109 goto out;
110 }
111
112 if (E1000_READ_REG(hw, E1000_TDFTS) !=
113 E1000_READ_REG(hw, E1000_TDFHS)) {
114 ret_val = -E1000_ERR_FIFO_WRAP;
115 goto out;
116 }
117
118 /* Disable the tx unit to avoid further pointer movement */
119 tctl = E1000_READ_REG(hw, E1000_TCTL);
120 E1000_WRITE_REG(hw, E1000_TCTL, tctl & ~E1000_TCTL_EN);
121
122 /* Reset the fifo pointers. */
123 E1000_WRITE_REG(hw, E1000_TDFT, dev_spec->tx_fifo_start);
124 E1000_WRITE_REG(hw, E1000_TDFH, dev_spec->tx_fifo_start);
125 E1000_WRITE_REG(hw, E1000_TDFTS, dev_spec->tx_fifo_start);
126 E1000_WRITE_REG(hw, E1000_TDFHS, dev_spec->tx_fifo_start);
127
128 /* Re-enabling tx unit */
129 E1000_WRITE_REG(hw, E1000_TCTL, tctl);
130 E1000_WRITE_FLUSH(hw);
131
132 dev_spec->tx_fifo_head = 0;
133
134 out:
135 return (ret_val);
136 }
137
138 /*
139 * e1000_update_tx_fifo_head - Update Tx fifo head pointer
140 * @hw: pointer to the HW structure
141 * @length: length of next outgoing frame
142 *
143 * Updates the SW calculated Tx FIFO head pointer.
144 */
145 void
e1000_update_tx_fifo_head_82547(struct e1000_hw * hw,u32 length)146 e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
147 {
148 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
149
150 DEBUGFUNC("e1000_update_tx_fifo_head_82547");
151
152 if (hw->mac.type != e1000_82547)
153 return;
154
155 dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
156 E1000_FIFO_GRANULARITY);
157
158 if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
159 dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
160 }
161
162 /*
163 * e1000_set_ttl_workaround_state_82541 - Enable/Disables TTL workaround
164 * @hw: pointer to the HW structure
165 * @state: boolean to enable/disable TTL workaround
166 *
167 * For 82541 or 82547 only silicon, allows the driver to enable/disable the
168 * TTL workaround.
169 */
170 void
e1000_set_ttl_workaround_state_82541(struct e1000_hw * hw,bool state)171 e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
172 {
173 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
174
175 DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
176
177 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
178 return;
179
180 dev_spec->ttl_workaround = state;
181 }
182
183 /*
184 * e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
185 * @hw: pointer to the HW structure
186 *
187 * Returns: E1000_ERR_PHY if fail to read/write the PHY
188 * E1000_SUCCESS in any other case
189 *
190 * This function, specific to 82547 hardware only, needs to be called every
191 * second. It checks if a parallel detect fault has occurred. If a fault
192 * occurred, disable/enable the DSP reset mechanism up to 5 times (once per
193 * second). If link is established, stop the workaround and ensure the DSP
194 * reset is enabled.
195 */
196 s32
e1000_igp_ttl_workaround_82547(struct e1000_hw * hw)197 e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
198 {
199 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
200 s32 ret_val = E1000_SUCCESS;
201 u16 phy_data = 0;
202 u16 dsp_value = DSP_RESET_ENABLE;
203 bool link;
204
205 DEBUGFUNC("e1000_igp_ttl_workaround_82547");
206
207 /* The workaround needed only for B-0 silicon HW */
208 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
209 goto out;
210
211 if (!(e1000_ttl_workaround_enabled_82541(hw)))
212 goto out;
213
214 /* Check for link first */
215 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
216 if (ret_val)
217 goto out;
218
219 if (link) {
220 /*
221 * If link is established during the workaround,
222 * the DSP mechanism must be enabled.
223 */
224 if (dev_spec->dsp_reset_counter) {
225 dev_spec->dsp_reset_counter = 0;
226 dsp_value = DSP_RESET_ENABLE;
227 } else {
228 ret_val = E1000_SUCCESS;
229 goto out;
230 }
231 } else {
232 if (dev_spec->dsp_reset_counter == 0) {
233 /*
234 * Workaround not activated,
235 * check if it needs activation
236 */
237 ret_val = hw->phy.ops.read_reg(hw,
238 PHY_AUTONEG_EXP,
239 &phy_data);
240 if (ret_val)
241 goto out;
242 /*
243 * Activate the workaround if there was a
244 * parallel detect fault
245 */
246 if (phy_data & NWAY_ER_PAR_DETECT_FAULT) {
247 dev_spec->dsp_reset_counter++;
248 } else {
249 ret_val = E1000_SUCCESS;
250 goto out;
251 }
252 }
253
254 /* After 5 times, stop the workaround */
255 if (dev_spec->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
256 dev_spec->dsp_reset_counter = 0;
257 dsp_value = DSP_RESET_ENABLE;
258 } else {
259 if (dev_spec->dsp_reset_counter) {
260 dsp_value = (dev_spec->dsp_reset_counter & 1)
261 ? DSP_RESET_DISABLE
262 : DSP_RESET_ENABLE;
263 dev_spec->dsp_reset_counter++;
264 }
265 }
266 }
267
268 ret_val =
269 hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);
270
271 out:
272 return (ret_val);
273 }
274