Merge commit '06307114472bd8aad5ff18ccdb8e25f128ae6652'
[unleashed.git] / kernel / drivers / net / e1000g / e1000g_workarounds.c
blob6d2751f9109c5b875444427842581e86bbcc7eab
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.
7 * CDDL LICENSE SUMMARY
9 * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
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").
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.
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms of the CDDLv1.
25 #include "e1000_api.h"
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
33 #define DSP_RESET_ENABLE 0x0
34 #define DSP_RESET_DISABLE 0x2
35 #define E1000_MAX_DSP_RESETS 10
37 #define E1000_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
41 * e1000_ttl_workaround_enabled_82541 - Returns current TTL workaround status
42 * @hw: pointer to the HW structure
44 * Returns the current status of the TTL workaround, as to whether the
45 * workaround is enabled or disabled.
47 bool
48 e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
50 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
51 bool state = false;
53 DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
55 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
56 goto out;
58 state = dev_spec->ttl_workaround;
60 out:
61 return (state);
65 * e1000_fifo_workaround_82547 - Workaround for Tx fifo failure
66 * @hw: pointer to the HW structure
67 * @length: length of next outgoing frame
69 * Returns: E1000_ERR_FIFO_WRAP if the next packet cannot be transmitted yet
70 * E1000_SUCCESS if the next packet can be transmitted
72 * Workaround for the 82547 Tx fifo failure.
74 s32
75 e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
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;
82 DEBUGFUNC("e1000_fifo_workaround_82547");
84 if (hw->mac.type != e1000_82547)
85 goto out;
88 * Get the length as seen by the FIFO of the next real
89 * packet to be transmitted.
91 fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
92 E1000_FIFO_GRANULARITY);
94 if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
95 goto out;
97 if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
98 (dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
99 goto out;
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;
107 if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
108 ret_val = -E1000_ERR_FIFO_WRAP;
109 goto out;
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;
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);
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);
128 /* Re-enabling tx unit */
129 E1000_WRITE_REG(hw, E1000_TCTL, tctl);
130 E1000_WRITE_FLUSH(hw);
132 dev_spec->tx_fifo_head = 0;
134 out:
135 return (ret_val);
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
143 * Updates the SW calculated Tx FIFO head pointer.
145 void
146 e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
148 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
150 DEBUGFUNC("e1000_update_tx_fifo_head_82547");
152 if (hw->mac.type != e1000_82547)
153 return;
155 dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
156 E1000_FIFO_GRANULARITY);
158 if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
159 dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
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
167 * For 82541 or 82547 only silicon, allows the driver to enable/disable the
168 * TTL workaround.
170 void
171 e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
173 struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
175 DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
177 if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
178 return;
180 dev_spec->ttl_workaround = state;
184 * e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
185 * @hw: pointer to the HW structure
187 * Returns: E1000_ERR_PHY if fail to read/write the PHY
188 * E1000_SUCCESS in any other case
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.
197 e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
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;
205 DEBUGFUNC("e1000_igp_ttl_workaround_82547");
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;
211 if (!(e1000_ttl_workaround_enabled_82541(hw)))
212 goto out;
214 /* Check for link first */
215 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
216 if (ret_val)
217 goto out;
219 if (link) {
221 * If link is established during the workaround,
222 * the DSP mechanism must be enabled.
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;
231 } else {
232 if (dev_spec->dsp_reset_counter == 0) {
234 * Workaround not activated,
235 * check if it needs activation
237 ret_val = hw->phy.ops.read_reg(hw,
238 PHY_AUTONEG_EXP,
239 &phy_data);
240 if (ret_val)
241 goto out;
243 * Activate the workaround if there was a
244 * parallel detect fault
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;
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++;
268 ret_val =
269 hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);
271 out:
272 return (ret_val);