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 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 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 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 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 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