1 /* 2 * Copyright 2006-2013 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include "efsys.h" 27 #include "efx.h" 28 #include "efx_types.h" 29 #include "efx_regs.h" 30 #include "efx_impl.h" 31 #include "xphy.h" 32 33 #if EFSYS_OPT_FALCON 34 35 static __checkReturn int 36 xphy_mmd_reset_wait( 37 __in efx_nic_t *enp, 38 __in uint8_t port, 39 __in uint8_t mmd) 40 { 41 unsigned int count; 42 int rc; 43 44 /* The Clause 22 extenion MMD does not implement IEEE registers */ 45 if (mmd == CL22EXT_MMD) { 46 rc = ENOTSUP; 47 goto fail1; 48 } 49 50 count = 0; 51 do { 52 efx_word_t word; 53 54 EFSYS_PROBE1(wait, unsigned int, count); 55 56 /* Sleep for 100 ms */ 57 EFSYS_SLEEP(100000); 58 59 /* Read control 1 register and check reset state */ 60 if ((rc = falcon_mdio_read(enp, port, mmd, 61 MMD_CONTROL1_REG, &word)) != 0) 62 goto fail2; 63 64 if (EFX_WORD_FIELD(word, MMD_RESET) == 0) 65 goto done; 66 67 } while (++count < 100); 68 69 rc = ETIMEDOUT; 70 goto fail3; 71 72 done: 73 return (0); 74 75 fail3: 76 EFSYS_PROBE(fail3); 77 fail2: 78 EFSYS_PROBE(fail2); 79 fail1: 80 EFSYS_PROBE1(fail1, int, rc); 81 82 return (rc); 83 } 84 85 __checkReturn int 86 xphy_pkg_wait( 87 __in efx_nic_t *enp, 88 __in uint8_t port, 89 __in uint32_t mask) 90 { 91 uint8_t mmd; 92 int rc; 93 94 for (mmd = 0; mmd <= MAXMMD; mmd++) { 95 /* Only check MMDs in the mask */ 96 if (((1 << mmd) & mask) == 0) 97 continue; 98 99 /* 100 * The Clause 22 extenion MMD does not implement IEEE 101 * registers. 102 */ 103 if (mmd == CL22EXT_MMD) 104 continue; 105 106 /* Wait for the MMD to come out of reset */ 107 if ((rc = xphy_mmd_reset_wait(enp, port, mmd)) != 0) 108 goto fail1; 109 } 110 111 return (0); 112 113 fail1: 114 EFSYS_PROBE1(fail1, int, rc); 115 116 return (rc); 117 } 118 119 __checkReturn int 120 xphy_pkg_verify( 121 __in efx_nic_t *enp, 122 __in uint8_t port, 123 __in uint32_t mask) 124 { 125 uint8_t mmd; 126 efx_word_t word; 127 int rc; 128 129 /* Find the first MMD */ 130 for (mmd = 0; mmd <= MAXMMD; mmd++) { 131 uint32_t devices; 132 133 if (((1 << mmd) & mask) == 0) 134 continue; 135 136 /* 137 * The Clause 22 extenion MMD does not implement IEEE 138 * registers. 139 */ 140 if (mmd == CL22EXT_MMD) 141 continue; 142 143 if ((rc = falcon_mdio_read(enp, port, mmd, 144 MMD_DEVICES2_REG, &word)) != 0) 145 goto fail1; 146 147 devices = (uint32_t)EFX_WORD_FIELD(word, EFX_WORD_0) << 16; 148 149 if ((rc = falcon_mdio_read(enp, port, mmd, 150 MMD_DEVICES1_REG, &word)) != 0) 151 goto fail2; 152 153 devices |= (uint32_t)EFX_WORD_FIELD(word, EFX_WORD_0); 154 155 EFSYS_PROBE1(devices, uint32_t, devices); 156 157 /* Check that all the specified MMDs are present */ 158 if ((devices & mask) != mask) { 159 rc = EFAULT; 160 goto fail3; 161 } 162 163 goto done; 164 } 165 166 rc = ENODEV; 167 goto fail4; 168 169 done: 170 for (mmd = 0; mmd <= MAXMMD; mmd++) { 171 /* Only check MMDs in the mask */ 172 if (((1 << mmd) & mask) == 0) 173 continue; 174 175 /* 176 * The Clause 22 extenion MMD does not implement IEEE 177 * registers. 178 */ 179 if (mmd == CL22EXT_MMD) 180 continue; 181 182 /* Check the MMD is responding */ 183 if ((rc = falcon_mdio_read(enp, port, mmd, 184 MMD_STATUS2_REG, &word)) != 0) 185 goto fail5; 186 187 if (EFX_WORD_FIELD(word, MMD_RESPONDING) != 188 MMD_RESPONDING_DECODE) 189 goto fail6; 190 191 } 192 193 return (0); 194 195 fail6: 196 EFSYS_PROBE(fail6); 197 fail5: 198 EFSYS_PROBE(fail5); 199 fail4: 200 EFSYS_PROBE(fail4); 201 fail3: 202 EFSYS_PROBE(fail3); 203 fail2: 204 EFSYS_PROBE(fail2); 205 fail1: 206 EFSYS_PROBE1(fail1, int, rc); 207 208 return (rc); 209 } 210 211 __checkReturn int 212 xphy_mmd_oui_get( 213 __in efx_nic_t *enp, 214 __in uint8_t port, 215 __in uint8_t mmd, 216 __out uint32_t *ouip) 217 { 218 efx_word_t word; 219 int rc; 220 221 /* The Clause 22 extenion MMD does not implement IEEE registers */ 222 if (mmd == CL22EXT_MMD) { 223 rc = ENOTSUP; 224 goto fail1; 225 } 226 227 if ((rc = falcon_mdio_read(enp, port, mmd, MMD_IDH_REG, 228 &word)) != 0) 229 goto fail2; 230 231 *ouip = (uint32_t)EFX_WORD_FIELD(word, MMD_IDH) << 16; 232 233 if ((rc = falcon_mdio_read(enp, port, mmd, MMD_IDL_REG, 234 &word)) != 0) 235 goto fail3; 236 237 *ouip |= (uint32_t)EFX_WORD_FIELD(word, MMD_IDL) & 0x0000ffff; 238 239 return (0); 240 241 fail3: 242 EFSYS_PROBE(fail3); 243 fail2: 244 EFSYS_PROBE(fail2); 245 fail1: 246 EFSYS_PROBE1(fail1, int, rc); 247 248 return (rc); 249 } 250 251 __checkReturn int 252 xphy_mmd_check( 253 __in efx_nic_t *enp, 254 __in uint8_t port, 255 __in uint8_t mmd, 256 __out boolean_t *upp) 257 { 258 efx_word_t word; 259 int rc; 260 261 /* Reset the latched status and fault flags */ 262 if ((rc = falcon_mdio_read(enp, port, mmd, MMD_STATUS1_REG, 263 &word)) != 0) 264 goto fail1; 265 266 if (mmd == PMA_PMD_MMD || mmd == PCS_MMD || mmd == PHY_XS_MMD) { 267 if ((rc = falcon_mdio_read(enp, port, mmd, 268 MMD_STATUS2_REG, &word)) != 0) 269 goto fail2; 270 } 271 272 /* Check the current status and fault flags */ 273 if ((rc = falcon_mdio_read(enp, port, mmd, MMD_STATUS1_REG, 274 &word)) != 0) 275 goto fail3; 276 277 *upp = (EFX_WORD_FIELD(word, MMD_LINK_UP) != 0 && 278 EFX_WORD_FIELD(word, MMD_FAULT) == 0); 279 280 return (0); 281 282 fail3: 283 EFSYS_PROBE(fail3); 284 fail2: 285 EFSYS_PROBE(fail2); 286 fail1: 287 EFSYS_PROBE1(fail1, int, rc); 288 289 return (rc); 290 } 291 292 __checkReturn int 293 xphy_mmd_fault( 294 __in efx_nic_t *enp, 295 __in uint8_t port, 296 __out boolean_t *upp) 297 { 298 efx_word_t word; 299 int rc; 300 301 if ((rc = falcon_mdio_read(enp, port, PHY_XS_MMD, 302 MMD_STATUS2_REG, &word)) != 0) 303 goto fail1; 304 305 *upp = (EFX_WORD_FIELD(word, MMD_RX_FAULT) == 0); 306 307 return (0); 308 309 fail1: 310 EFSYS_PROBE1(fail1, int, rc); 311 312 return (rc); 313 } 314 315 __checkReturn int 316 xphy_mmd_loopback_set( 317 __in efx_nic_t *enp, 318 __in uint8_t port, 319 __in uint8_t mmd, 320 __in boolean_t on) 321 { 322 efx_word_t word; 323 int rc; 324 325 /* The Clause 22 extenion MMD does not implement IEEE registers */ 326 if (mmd == CL22EXT_MMD) { 327 rc = ENOTSUP; 328 goto fail1; 329 } 330 331 if ((rc = falcon_mdio_read(enp, port, mmd, MMD_CONTROL1_REG, 332 &word)) != 0) 333 goto fail2; 334 335 if (mmd == PMA_PMD_MMD) 336 EFX_SET_WORD_FIELD(word, MMD_PMA_LOOPBACK, (on) ? 1 : 0); 337 else 338 EFX_SET_WORD_FIELD(word, MMD_LOOPBACK, (on) ? 1 : 0); 339 340 if ((rc = falcon_mdio_write(enp, port, mmd, MMD_CONTROL1_REG, 341 &word)) != 0) 342 goto fail3; 343 344 return (0); 345 346 fail3: 347 EFSYS_PROBE(fail3); 348 fail2: 349 EFSYS_PROBE(fail2); 350 fail1: 351 EFSYS_PROBE1(fail1, int, rc); 352 353 return (rc); 354 } 355 356 #endif /* EFSYS_OPT_FALCON */