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