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.
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.
48 e1000_ttl_workaround_enabled_82541(struct e1000_hw
*hw
)
50 struct e1000_dev_spec_82541
*dev_spec
= &hw
->dev_spec
._82541
;
53 DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
55 if ((hw
->mac
.type
!= e1000_82541
) && (hw
->mac
.type
!= e1000_82547
))
58 state
= dev_spec
->ttl_workaround
;
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.
75 e1000_fifo_workaround_82547(struct e1000_hw
*hw
, u16 length
)
77 struct e1000_dev_spec_82541
*dev_spec
= &hw
->dev_spec
._82541
;
79 s32 ret_val
= E1000_SUCCESS
;
82 DEBUGFUNC("e1000_fifo_workaround_82547");
84 if (hw
->mac
.type
!= e1000_82547
)
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
))
97 if ((dev_spec
->tx_fifo_head
+ fifo_pkt_len
) <
98 (dev_spec
->tx_fifo_size
+ E1000_FIFO_PAD_82547
))
101 if (E1000_READ_REG(hw
, E1000_TDT(0)) !=
102 E1000_READ_REG(hw
, E1000_TDH(0))) {
103 ret_val
= -E1000_ERR_FIFO_WRAP
;
107 if (E1000_READ_REG(hw
, E1000_TDFT
) != E1000_READ_REG(hw
, E1000_TDFH
)) {
108 ret_val
= -E1000_ERR_FIFO_WRAP
;
112 if (E1000_READ_REG(hw
, E1000_TDFTS
) !=
113 E1000_READ_REG(hw
, E1000_TDFHS
)) {
114 ret_val
= -E1000_ERR_FIFO_WRAP
;
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;
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.
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
)
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
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
))
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
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
;
202 u16 dsp_value
= DSP_RESET_ENABLE
;
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
))
211 if (!(e1000_ttl_workaround_enabled_82541(hw
)))
214 /* Check for link first */
215 ret_val
= e1000_phy_has_link_generic(hw
, 1, 0, &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
;
228 ret_val
= E1000_SUCCESS
;
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
,
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
++;
249 ret_val
= E1000_SUCCESS
;
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
;
259 if (dev_spec
->dsp_reset_counter
) {
260 dsp_value
= (dev_spec
->dsp_reset_counter
& 1)
263 dev_spec
->dsp_reset_counter
++;
269 hw
->phy
.ops
.write_reg(hw
, IGP01E1000_PHY_DSP_RESET
, dsp_value
);