Print this page
10089 phy_check() is bitwise, should be streetwise
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/mii/mii.c
+++ new/usr/src/uts/common/io/mii/mii.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 + * Copyright (c) 2018, Joyent, Inc.
28 + */
29 +
30 +/*
27 31 * mii - MII/PHY support for MAC drivers
28 32 *
29 33 * Utility module to provide a consistent interface to a MAC driver accross
30 34 * different implementations of PHY devices
31 35 */
32 36
33 37 #include <sys/types.h>
34 38 #include <sys/debug.h>
35 39 #include <sys/errno.h>
36 40 #include <sys/param.h>
37 41 #include <sys/kmem.h>
38 42 #include <sys/conf.h>
39 43 #include <sys/ddi.h>
40 44 #include <sys/sunddi.h>
41 45 #include <sys/modctl.h>
42 46 #include <sys/cmn_err.h>
43 47 #include <sys/policy.h>
44 48 #include <sys/note.h>
45 49 #include <sys/strsun.h>
46 50 #include <sys/miiregs.h>
47 51 #include <sys/mac_provider.h>
48 52 #include <sys/mac_ether.h>
49 53 #include <sys/mii.h>
50 54 #include "miipriv.h"
51 55
52 56 #define MII_SECOND 1000000
53 57
54 58 /* indices into error array */
55 59 enum {
56 60 MII_EOK = 0,
57 61 MII_ERESET,
58 62 MII_ESTART,
59 63 MII_ENOPHY,
60 64 MII_ECHECK,
61 65 MII_ELOOP,
62 66 };
63 67
64 68 static const char * const mii_errors[] = {
65 69 "",
66 70 "Failure resetting PHY.",
67 71 "Failure starting PHY.",
68 72 "No Ethernet PHY found.",
69 73 "Failure reading PHY (removed?)",
70 74 "Failure setting loopback."
71 75 };
72 76
73 77 /* Indexed by XCVR_ type */
74 78 static const char * const mii_xcvr_types[] = {
75 79 "Undefined",
76 80 "Unknown",
77 81 "10 Mbps",
78 82 "100BASE-T4",
79 83 "100BASE-X",
80 84 "100BASE-T2",
81 85 "1000BASE-X",
82 86 "1000BASE-T"
83 87 };
84 88
85 89 /* state machine */
86 90 typedef enum {
87 91 MII_STATE_PROBE = 0,
88 92 MII_STATE_RESET,
89 93 MII_STATE_START,
90 94 MII_STATE_RUN,
91 95 MII_STATE_LOOPBACK,
92 96 } mii_tstate_t;
93 97
94 98 struct mii_handle {
95 99 dev_info_t *m_dip;
96 100 void *m_private;
97 101 mii_ops_t m_ops;
98 102
99 103 kt_did_t m_tq_id;
100 104 kmutex_t m_lock;
101 105 kcondvar_t m_cv;
102 106 ddi_taskq_t *m_tq;
103 107 int m_flags;
104 108
105 109 boolean_t m_started;
106 110 boolean_t m_suspending;
107 111 boolean_t m_suspended;
108 112 int m_error;
109 113 mii_tstate_t m_tstate;
110 114
111 115 #define MII_FLAG_EXIT 0x1 /* exit the thread */
112 116 #define MII_FLAG_STOP 0x2 /* shutdown MII monitoring */
113 117 #define MII_FLAG_RESET 0x4 /* reset the MII */
114 118 #define MII_FLAG_PROBE 0x8 /* probe for PHYs */
115 119 #define MII_FLAG_NOTIFY 0x10 /* notify about a change */
116 120 #define MII_FLAG_SUSPEND 0x20 /* monitoring suspended */
117 121 #define MII_FLAG_MACRESET 0x40 /* send reset to MAC */
118 122 #define MII_FLAG_PHYSTART 0x80 /* start up the PHY */
119 123
120 124 /* device name for printing, e.g. "hme0" */
121 125 char m_name[MODMAXNAMELEN + 16];
122 126
123 127 int m_addr;
124 128 phy_handle_t m_phys[32];
125 129 phy_handle_t m_bogus_phy;
126 130 phy_handle_t *m_phy;
127 131
128 132 link_state_t m_link;
129 133
130 134 /* these start out undefined, but get values due to mac_prop_set */
131 135 int m_en_aneg;
132 136 int m_en_10_hdx;
133 137 int m_en_10_fdx;
134 138 int m_en_100_t4;
135 139 int m_en_100_hdx;
136 140 int m_en_100_fdx;
137 141 int m_en_1000_hdx;
138 142 int m_en_1000_fdx;
139 143 int m_en_flowctrl;
140 144
141 145 boolean_t m_cap_pause;
142 146 boolean_t m_cap_asmpause;
143 147 };
144 148
145 149
146 150 static void _mii_task(void *);
147 151 static void _mii_probe_phy(phy_handle_t *);
148 152 static void _mii_probe(mii_handle_t);
149 153 static int _mii_reset(mii_handle_t);
150 154 static int _mii_loopback(mii_handle_t);
151 155 static void _mii_notify(mii_handle_t);
152 156 static int _mii_check(mii_handle_t);
153 157 static int _mii_start(mii_handle_t);
154 158
155 159 /*
156 160 * Loadable module structures/entrypoints
157 161 */
158 162
159 163 extern struct mod_ops mod_misc_ops;
160 164
161 165 static struct modlmisc modlmisc = {
162 166 &mod_miscops,
163 167 "802.3 MII support",
164 168 };
165 169
166 170 static struct modlinkage modlinkage = {
167 171 MODREV_1, &modlmisc, NULL
168 172 };
169 173
170 174 int
171 175 _init(void)
172 176 {
173 177 return (mod_install(&modlinkage));
174 178 }
175 179
176 180 int
177 181 _fini(void)
178 182 {
179 183 return (mod_remove(&modlinkage));
180 184 }
181 185
182 186 int
183 187 _info(struct modinfo *modinfop)
184 188 {
185 189 return (mod_info(&modlinkage, modinfop));
186 190 }
187 191
188 192 void
189 193 _mii_error(mii_handle_t mh, int errno)
190 194 {
191 195 /*
192 196 * This dumps an error message, but it avoids filling the log with
193 197 * repeated error messages.
194 198 */
195 199 if (mh->m_error != errno) {
196 200 cmn_err(CE_WARN, "%s: %s", mh->m_name, mii_errors[errno]);
197 201 mh->m_error = errno;
198 202 }
199 203 }
200 204
201 205 /*
202 206 * Known list of specific PHY probes.
203 207 */
204 208 typedef boolean_t (*phy_probe_t)(phy_handle_t *);
205 209 phy_probe_t _phy_probes[] = {
206 210 phy_natsemi_probe,
207 211 phy_intel_probe,
208 212 phy_qualsemi_probe,
209 213 phy_cicada_probe,
210 214 phy_marvell_probe,
211 215 phy_realtek_probe,
212 216 phy_other_probe,
213 217 NULL
214 218 };
215 219
216 220 /*
217 221 * MII Interface functions
218 222 */
219 223
220 224 mii_handle_t
221 225 mii_alloc_instance(void *private, dev_info_t *dip, int inst, mii_ops_t *ops)
222 226 {
223 227 mii_handle_t mh;
224 228 char tqname[16];
225 229
226 230 if (ops->mii_version != MII_OPS_VERSION) {
227 231 cmn_err(CE_WARN, "%s: incompatible MII version (%d)",
228 232 ddi_driver_name(dip), ops->mii_version);
229 233 return (NULL);
230 234 }
231 235 mh = kmem_zalloc(sizeof (*mh), KM_SLEEP);
232 236
233 237 (void) snprintf(mh->m_name, sizeof (mh->m_name), "%s%d",
234 238 ddi_driver_name(dip), inst);
235 239
236 240 /* DDI will prepend the driver name */
237 241 (void) snprintf(tqname, sizeof (tqname), "mii%d", inst);
238 242
239 243 mh->m_dip = dip;
240 244 mh->m_ops = *ops;
241 245 mh->m_private = private;
242 246 mh->m_suspended = B_FALSE;
243 247 mh->m_started = B_FALSE;
244 248 mh->m_tstate = MII_STATE_PROBE;
245 249 mh->m_link = LINK_STATE_UNKNOWN;
246 250 mh->m_error = MII_EOK;
247 251 mh->m_addr = -1;
248 252 mutex_init(&mh->m_lock, NULL, MUTEX_DRIVER, NULL);
249 253 cv_init(&mh->m_cv, NULL, CV_DRIVER, NULL);
250 254
251 255 mh->m_tq = ddi_taskq_create(dip, tqname, 1, TASKQ_DEFAULTPRI, 0);
252 256 if (mh->m_tq == NULL) {
253 257 cmn_err(CE_WARN, "%s: unable to create MII monitoring task",
254 258 ddi_driver_name(dip));
255 259 cv_destroy(&mh->m_cv);
256 260 mutex_destroy(&mh->m_lock);
257 261 kmem_free(mh, sizeof (*mh));
258 262 return (NULL);
259 263 }
260 264
261 265 /*
262 266 * Initialize user prefs by loading properties. Ultimately,
263 267 * Brussels interfaces would be superior here.
264 268 */
265 269 #define GETPROP(name) ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, name, -1)
266 270 mh->m_en_aneg = GETPROP("adv_autoneg_cap");
267 271 mh->m_en_10_hdx = GETPROP("adv_10hdx_cap");
268 272 mh->m_en_10_fdx = GETPROP("adv_10fdx_cap");
269 273 mh->m_en_100_hdx = GETPROP("adv_100hdx_cap");
270 274 mh->m_en_100_fdx = GETPROP("adv_100fdx_cap");
271 275 mh->m_en_100_t4 = GETPROP("adv_100T4_cap");
272 276 mh->m_en_1000_hdx = GETPROP("adv_1000hdx_cap");
273 277 mh->m_en_1000_fdx = GETPROP("adv_1000fdx_cap");
274 278
275 279 mh->m_cap_pause = B_FALSE;
276 280 mh->m_cap_asmpause = B_FALSE;
277 281
278 282 bzero(&mh->m_bogus_phy, sizeof (mh->m_bogus_phy));
279 283 mh->m_bogus_phy.phy_link = LINK_STATE_UNKNOWN;
280 284 mh->m_bogus_phy.phy_duplex = LINK_DUPLEX_UNKNOWN;
281 285 mh->m_bogus_phy.phy_addr = 0xff;
282 286 mh->m_bogus_phy.phy_type = XCVR_NONE;
283 287 mh->m_bogus_phy.phy_id = (uint32_t)-1;
284 288 mh->m_bogus_phy.phy_loopback = PHY_LB_NONE;
285 289 mh->m_bogus_phy.phy_flowctrl = LINK_FLOWCTRL_NONE;
286 290 mh->m_phy = &mh->m_bogus_phy;
287 291
288 292 for (int i = 0; i < 32; i++) {
289 293 mh->m_phys[i].phy_mii = mh;
290 294 }
291 295 mh->m_bogus_phy.phy_mii = mh;
292 296
293 297 return (mh);
294 298 }
295 299
296 300 mii_handle_t
297 301 mii_alloc(void *private, dev_info_t *dip, mii_ops_t *ops)
298 302 {
299 303 return (mii_alloc_instance(private, dip, ddi_get_instance(dip), ops));
300 304 }
301 305
302 306 void
303 307 mii_set_pauseable(mii_handle_t mh, boolean_t pauseable, boolean_t asymetric)
304 308 {
305 309 phy_handle_t *ph;
306 310
307 311 mutex_enter(&mh->m_lock);
308 312 ph = mh->m_phy;
309 313 ph->phy_cap_pause = mh->m_cap_pause = pauseable;
310 314 ph->phy_cap_asmpause = mh->m_cap_asmpause = asymetric;
311 315 if (pauseable) {
312 316 mh->m_en_flowctrl = LINK_FLOWCTRL_BI;
313 317 } else {
314 318 mh->m_en_flowctrl = LINK_FLOWCTRL_NONE;
315 319 }
316 320 mutex_exit(&mh->m_lock);
317 321 }
318 322
319 323 void
320 324 mii_free(mii_handle_t mh)
321 325 {
322 326 mutex_enter(&mh->m_lock);
323 327 mh->m_started = B_FALSE;
324 328 cv_broadcast(&mh->m_cv);
325 329 mutex_exit(&mh->m_lock);
326 330
327 331 ddi_taskq_destroy(mh->m_tq);
328 332 mutex_destroy(&mh->m_lock);
329 333 cv_destroy(&mh->m_cv);
330 334 kmem_free(mh, sizeof (*mh));
331 335 }
332 336
333 337 void
334 338 mii_reset(mii_handle_t mh)
335 339 {
336 340 mutex_enter(&mh->m_lock);
337 341 if (mh->m_tstate > MII_STATE_RESET)
338 342 mh->m_tstate = MII_STATE_RESET;
339 343 cv_broadcast(&mh->m_cv);
340 344 mutex_exit(&mh->m_lock);
341 345 }
342 346
343 347 void
344 348 mii_suspend(mii_handle_t mh)
345 349 {
346 350 mutex_enter(&mh->m_lock);
347 351 while ((!mh->m_suspended) && (mh->m_started)) {
348 352 mh->m_suspending = B_TRUE;
349 353 cv_broadcast(&mh->m_cv);
350 354 cv_wait(&mh->m_cv, &mh->m_lock);
351 355 }
352 356 mutex_exit(&mh->m_lock);
353 357 }
354 358
355 359 void
356 360 mii_resume(mii_handle_t mh)
357 361 {
358 362 mutex_enter(&mh->m_lock);
359 363
360 364 switch (mh->m_tstate) {
361 365 case MII_STATE_PROBE:
362 366 break;
363 367 case MII_STATE_RESET:
364 368 case MII_STATE_START:
365 369 case MII_STATE_RUN:
366 370 /* let monitor thread deal with this */
367 371 mh->m_tstate = MII_STATE_RESET;
368 372 break;
369 373
370 374 case MII_STATE_LOOPBACK:
371 375 /* loopback is handled synchronously */
372 376 (void) _mii_loopback(mh);
373 377 break;
374 378 }
375 379
376 380 mh->m_suspended = B_FALSE;
377 381 cv_broadcast(&mh->m_cv);
378 382 mutex_exit(&mh->m_lock);
379 383 }
380 384
381 385 void
382 386 mii_start(mii_handle_t mh)
383 387 {
384 388 mutex_enter(&mh->m_lock);
385 389 if (!mh->m_started) {
386 390 mh->m_tstate = MII_STATE_PROBE;
387 391 mh->m_started = B_TRUE;
388 392 if (ddi_taskq_dispatch(mh->m_tq, _mii_task, mh, DDI_NOSLEEP) !=
389 393 DDI_SUCCESS) {
390 394 cmn_err(CE_WARN,
391 395 "%s: unable to start MII monitoring task",
392 396 mh->m_name);
393 397 mh->m_started = B_FALSE;
394 398 }
395 399 }
396 400 cv_broadcast(&mh->m_cv);
397 401 mutex_exit(&mh->m_lock);
398 402 }
399 403
400 404 void
401 405 mii_stop(mii_handle_t mh)
402 406 {
403 407 mutex_enter(&mh->m_lock);
404 408 mh->m_started = B_FALSE;
405 409 /*
406 410 * Reset link state to unknown defaults, since we're not
407 411 * monitoring it anymore. We'll reprobe all link state later.
408 412 */
409 413 mh->m_link = LINK_STATE_UNKNOWN;
410 414 mh->m_phy = &mh->m_bogus_phy;
411 415 cv_broadcast(&mh->m_cv);
412 416 mutex_exit(&mh->m_lock);
413 417 /*
414 418 * Notify the MAC driver. This will allow it to call back
415 419 * into the MAC framework to clear any previous link state.
416 420 */
417 421 _mii_notify(mh);
418 422 }
419 423
420 424 void
421 425 mii_probe(mii_handle_t mh)
422 426 {
423 427 mutex_enter(&mh->m_lock);
424 428 _mii_probe(mh);
425 429 mutex_exit(&mh->m_lock);
426 430 }
427 431
428 432 void
429 433 mii_check(mii_handle_t mh)
430 434 {
431 435 mutex_enter(&mh->m_lock);
432 436 cv_broadcast(&mh->m_cv);
433 437 mutex_exit(&mh->m_lock);
434 438 }
435 439
436 440 int
437 441 mii_get_speed(mii_handle_t mh)
438 442 {
439 443 phy_handle_t *ph = mh->m_phy;
440 444
441 445 return (ph->phy_speed);
442 446 }
443 447
444 448 link_duplex_t
445 449 mii_get_duplex(mii_handle_t mh)
446 450 {
447 451 phy_handle_t *ph = mh->m_phy;
448 452
449 453 return (ph->phy_duplex);
450 454 }
451 455
452 456 link_state_t
453 457 mii_get_state(mii_handle_t mh)
454 458 {
455 459 phy_handle_t *ph = mh->m_phy;
456 460
457 461 return (ph->phy_link);
458 462 }
459 463
460 464 link_flowctrl_t
461 465 mii_get_flowctrl(mii_handle_t mh)
462 466 {
463 467 phy_handle_t *ph = mh->m_phy;
464 468
465 469 return (ph->phy_flowctrl);
466 470 }
467 471
468 472 int
469 473 mii_get_loopmodes(mii_handle_t mh, lb_property_t *modes)
470 474 {
471 475 phy_handle_t *ph = mh->m_phy;
472 476 int cnt = 0;
473 477 lb_property_t lmodes[MII_LOOPBACK_MAX];
474 478
475 479 lmodes[cnt].lb_type = normal;
476 480 (void) strlcpy(lmodes[cnt].key, "normal", sizeof (lmodes[cnt].key));
477 481 lmodes[cnt].value = PHY_LB_NONE;
478 482 cnt++;
479 483
480 484 if (ph->phy_cap_1000_fdx ||
481 485 ph->phy_cap_100_fdx ||
482 486 ph->phy_cap_10_fdx) {
483 487 /* we only support full duplex internal phy testing */
484 488 lmodes[cnt].lb_type = internal;
485 489 (void) strlcpy(lmodes[cnt].key, "PHY",
486 490 sizeof (lmodes[cnt].key));
487 491 lmodes[cnt].value = PHY_LB_INT_PHY;
488 492 cnt++;
489 493 }
490 494
491 495 if (ph->phy_cap_1000_fdx) {
492 496 lmodes[cnt].lb_type = external;
493 497 (void) strlcpy(lmodes[cnt].key, "1000Mbps",
494 498 sizeof (lmodes[cnt].key));
495 499 lmodes[cnt].value = PHY_LB_EXT_1000;
496 500 cnt++;
497 501 }
498 502
499 503 if (ph->phy_cap_100_fdx) {
500 504 lmodes[cnt].lb_type = external;
501 505 (void) strlcpy(lmodes[cnt].key, "100Mbps",
502 506 sizeof (lmodes[cnt].key));
503 507 lmodes[cnt].value = PHY_LB_EXT_100;
504 508 cnt++;
505 509 }
506 510
507 511 if (ph->phy_cap_10_fdx) {
508 512 lmodes[cnt].lb_type = external;
509 513 (void) strlcpy(lmodes[cnt].key, "10Mbps",
510 514 sizeof (lmodes[cnt].key));
511 515 lmodes[cnt].value = PHY_LB_EXT_10;
512 516 cnt++;
513 517 }
514 518
515 519 if (modes) {
516 520 bcopy(lmodes, modes, sizeof (lb_property_t) * cnt);
517 521 }
518 522
519 523 return (cnt);
520 524 }
521 525
522 526 uint32_t
523 527 mii_get_loopback(mii_handle_t mh)
524 528 {
525 529 phy_handle_t *ph = mh->m_phy;
526 530
527 531 return (ph->phy_loopback);
528 532 }
529 533
530 534 int
531 535 mii_set_loopback(mii_handle_t mh, uint32_t loop)
532 536 {
533 537 phy_handle_t *ph;
534 538 int rv;
535 539
536 540 mutex_enter(&mh->m_lock);
537 541 ph = mh->m_phy;
538 542
539 543 if ((!mh->m_started) || (!ph->phy_present) ||
540 544 (loop >= mii_get_loopmodes(mh, NULL))) {
541 545 return (EINVAL);
542 546 }
543 547
544 548 ph->phy_loopback = loop;
545 549 rv = _mii_loopback(mh);
546 550 if (rv == DDI_SUCCESS) {
547 551 mh->m_tstate = MII_STATE_LOOPBACK;
548 552 }
549 553 cv_broadcast(&mh->m_cv);
550 554 mutex_exit(&mh->m_lock);
551 555
552 556 return (rv == DDI_SUCCESS ? 0 : EIO);
553 557 }
554 558
555 559 uint32_t
556 560 mii_get_id(mii_handle_t mh)
557 561 {
558 562 phy_handle_t *ph = mh->m_phy;
559 563
560 564 return (ph->phy_id);
561 565 }
562 566
563 567 int
564 568 mii_get_addr(mii_handle_t mh)
565 569 {
566 570 return (mh->m_addr);
567 571 }
568 572
569 573 /* GLDv3 helpers */
570 574
571 575 boolean_t
572 576 mii_m_loop_ioctl(mii_handle_t mh, queue_t *wq, mblk_t *mp)
573 577 {
574 578 struct iocblk *iocp;
575 579 int rv = 0;
576 580 int cnt;
577 581 lb_property_t modes[MII_LOOPBACK_MAX];
578 582 lb_info_sz_t sz;
579 583 int cmd;
580 584 uint32_t mode;
581 585
582 586 iocp = (void *)mp->b_rptr;
583 587 cmd = iocp->ioc_cmd;
584 588
585 589 switch (cmd) {
586 590 case LB_SET_MODE:
587 591 case LB_GET_INFO_SIZE:
588 592 case LB_GET_INFO:
589 593 case LB_GET_MODE:
590 594 break;
591 595
592 596 default:
593 597 return (B_FALSE);
594 598 }
595 599
596 600 if (mp->b_cont == NULL) {
597 601 miocnak(wq, mp, 0, EINVAL);
598 602 return (B_TRUE);
599 603 }
600 604
601 605 switch (cmd) {
602 606 case LB_GET_INFO_SIZE:
603 607 cnt = mii_get_loopmodes(mh, modes);
604 608 if (iocp->ioc_count != sizeof (sz)) {
605 609 rv = EINVAL;
606 610 } else {
607 611 sz = cnt * sizeof (lb_property_t);
608 612 bcopy(&sz, mp->b_cont->b_rptr, sizeof (sz));
609 613 }
610 614 break;
611 615
612 616 case LB_GET_INFO:
613 617 cnt = mii_get_loopmodes(mh, modes);
614 618 if (iocp->ioc_count != (cnt * sizeof (lb_property_t))) {
615 619 rv = EINVAL;
616 620 } else {
617 621 bcopy(modes, mp->b_cont->b_rptr, iocp->ioc_count);
618 622 }
619 623 break;
620 624
621 625 case LB_GET_MODE:
622 626 if (iocp->ioc_count != sizeof (mode)) {
623 627 rv = EINVAL;
624 628 } else {
625 629 mode = mii_get_loopback(mh);
626 630 bcopy(&mode, mp->b_cont->b_rptr, sizeof (mode));
627 631 }
628 632 break;
629 633
630 634 case LB_SET_MODE:
631 635 rv = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
632 636 if (rv != 0)
633 637 break;
634 638 if (iocp->ioc_count != sizeof (mode)) {
635 639 rv = EINVAL;
636 640 break;
637 641 }
638 642 bcopy(mp->b_cont->b_rptr, &mode, sizeof (mode));
639 643 rv = mii_set_loopback(mh, mode);
640 644 break;
641 645 }
642 646
643 647 if (rv == 0) {
644 648 miocack(wq, mp, iocp->ioc_count, 0);
645 649 } else {
646 650 miocnak(wq, mp, 0, rv);
647 651 }
648 652 return (B_TRUE);
649 653 }
650 654
651 655 int
652 656 mii_m_getprop(mii_handle_t mh, const char *name, mac_prop_id_t num,
653 657 uint_t sz, void *val)
654 658 {
655 659 phy_handle_t *ph;
656 660 int err = 0;
657 661
658 662 _NOTE(ARGUNUSED(name));
659 663
660 664 if (sz < 1)
661 665 return (EINVAL);
662 666
663 667 mutex_enter(&mh->m_lock);
664 668
665 669 ph = mh->m_phy;
666 670
667 671 #define CASE_PROP_ABILITY(PROP, VAR) \
668 672 case MAC_PROP_ADV_##PROP: \
669 673 *(uint8_t *)val = ph->phy_adv_##VAR; \
670 674 break; \
671 675 \
672 676 case MAC_PROP_EN_##PROP: \
673 677 *(uint8_t *)val = ph->phy_en_##VAR; \
674 678 break;
675 679
676 680 switch (num) {
677 681 case MAC_PROP_DUPLEX:
678 682 ASSERT(sz >= sizeof (link_duplex_t));
679 683 bcopy(&ph->phy_duplex, val, sizeof (link_duplex_t));
680 684 break;
681 685
682 686 case MAC_PROP_SPEED: {
683 687 uint64_t speed = ph->phy_speed * 1000000ull;
684 688 ASSERT(sz >= sizeof (uint64_t));
685 689 bcopy(&speed, val, sizeof (speed));
686 690 break;
687 691 }
688 692
689 693 case MAC_PROP_AUTONEG:
690 694 *(uint8_t *)val = ph->phy_adv_aneg;
691 695 break;
692 696
693 697 case MAC_PROP_FLOWCTRL:
694 698 ASSERT(sz >= sizeof (link_flowctrl_t));
695 699 bcopy(&ph->phy_flowctrl, val, sizeof (link_flowctrl_t));
696 700 break;
697 701
698 702 CASE_PROP_ABILITY(1000FDX_CAP, 1000_fdx)
699 703 CASE_PROP_ABILITY(1000HDX_CAP, 1000_hdx)
700 704 CASE_PROP_ABILITY(100T4_CAP, 100_t4)
701 705 CASE_PROP_ABILITY(100FDX_CAP, 100_fdx)
702 706 CASE_PROP_ABILITY(100HDX_CAP, 100_hdx)
703 707 CASE_PROP_ABILITY(10FDX_CAP, 10_fdx)
704 708 CASE_PROP_ABILITY(10HDX_CAP, 10_hdx)
705 709
706 710 default:
707 711 err = ENOTSUP;
708 712 break;
709 713 }
710 714
711 715 mutex_exit(&mh->m_lock);
712 716
713 717 return (err);
714 718 }
715 719
716 720 void
717 721 mii_m_propinfo(mii_handle_t mh, const char *name, mac_prop_id_t num,
718 722 mac_prop_info_handle_t prh)
719 723 {
720 724 phy_handle_t *ph;
721 725
722 726 _NOTE(ARGUNUSED(name));
723 727
724 728 mutex_enter(&mh->m_lock);
725 729
726 730 ph = mh->m_phy;
727 731
728 732 switch (num) {
729 733 case MAC_PROP_DUPLEX:
730 734 case MAC_PROP_SPEED:
731 735 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
732 736 break;
733 737
734 738 case MAC_PROP_AUTONEG:
735 739 mac_prop_info_set_default_uint8(prh, ph->phy_cap_aneg);
736 740 break;
737 741
738 742 #define CASE_PROP_PERM(PROP, VAR) \
739 743 case MAC_PROP_ADV_##PROP: \
740 744 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); \
741 745 mac_prop_info_set_default_uint8(prh, ph->phy_cap_##VAR); \
742 746 break; \
743 747 \
744 748 case MAC_PROP_EN_##PROP: \
745 749 if (!ph->phy_cap_##VAR) \
746 750 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); \
747 751 mac_prop_info_set_default_uint8(prh, ph->phy_cap_##VAR); \
748 752 break;
749 753
750 754 CASE_PROP_PERM(1000FDX_CAP, 1000_fdx)
751 755 CASE_PROP_PERM(1000HDX_CAP, 1000_hdx)
752 756 CASE_PROP_PERM(100T4_CAP, 100_t4)
753 757 CASE_PROP_PERM(100FDX_CAP, 100_fdx)
754 758 CASE_PROP_PERM(100HDX_CAP, 100_hdx)
755 759 CASE_PROP_PERM(10FDX_CAP, 10_fdx)
756 760 CASE_PROP_PERM(10HDX_CAP, 10_hdx)
757 761 }
758 762
759 763 mutex_exit(&mh->m_lock);
760 764 }
761 765
762 766 int
763 767 mii_m_setprop(mii_handle_t mh, const char *name, mac_prop_id_t num,
764 768 uint_t sz, const void *valp)
765 769 {
766 770 phy_handle_t *ph;
767 771 boolean_t *advp = NULL;
768 772 boolean_t *capp = NULL;
769 773 int *macpp = NULL;
770 774 int rv = ENOTSUP;
771 775
772 776 _NOTE(ARGUNUSED(name));
773 777
774 778 if (sz < 1)
775 779 return (EINVAL);
776 780
777 781 mutex_enter(&mh->m_lock);
778 782
779 783 ph = mh->m_phy;
780 784
781 785 /* we don't support changing parameters while in loopback mode */
782 786 if (ph->phy_loopback != PHY_LB_NONE) {
783 787 switch (num) {
784 788 case MAC_PROP_EN_1000FDX_CAP:
785 789 case MAC_PROP_EN_1000HDX_CAP:
786 790 case MAC_PROP_EN_100FDX_CAP:
787 791 case MAC_PROP_EN_100HDX_CAP:
788 792 case MAC_PROP_EN_100T4_CAP:
789 793 case MAC_PROP_EN_10FDX_CAP:
790 794 case MAC_PROP_EN_10HDX_CAP:
791 795 case MAC_PROP_AUTONEG:
792 796 case MAC_PROP_FLOWCTRL:
793 797 return (EBUSY);
794 798 }
795 799 }
796 800
797 801 switch (num) {
798 802 case MAC_PROP_EN_1000FDX_CAP:
799 803 capp = &ph->phy_cap_1000_fdx;
800 804 advp = &ph->phy_en_1000_fdx;
801 805 macpp = &mh->m_en_1000_fdx;
802 806 break;
803 807 case MAC_PROP_EN_1000HDX_CAP:
804 808 capp = &ph->phy_cap_1000_hdx;
805 809 advp = &ph->phy_en_1000_hdx;
806 810 macpp = &mh->m_en_1000_hdx;
807 811 break;
808 812 case MAC_PROP_EN_100FDX_CAP:
809 813 capp = &ph->phy_cap_100_fdx;
810 814 advp = &ph->phy_en_100_fdx;
811 815 macpp = &mh->m_en_100_fdx;
812 816 break;
813 817 case MAC_PROP_EN_100HDX_CAP:
814 818 capp = &ph->phy_cap_100_hdx;
815 819 advp = &ph->phy_en_100_hdx;
816 820 macpp = &mh->m_en_100_hdx;
817 821 break;
818 822 case MAC_PROP_EN_100T4_CAP:
819 823 capp = &ph->phy_cap_100_t4;
820 824 advp = &ph->phy_en_100_t4;
821 825 macpp = &mh->m_en_100_t4;
822 826 break;
823 827 case MAC_PROP_EN_10FDX_CAP:
824 828 capp = &ph->phy_cap_10_fdx;
825 829 advp = &ph->phy_en_10_fdx;
826 830 macpp = &mh->m_en_10_fdx;
827 831 break;
828 832 case MAC_PROP_EN_10HDX_CAP:
829 833 capp = &ph->phy_cap_10_hdx;
830 834 advp = &ph->phy_en_10_hdx;
831 835 macpp = &mh->m_en_10_hdx;
832 836 break;
833 837 case MAC_PROP_AUTONEG:
834 838 capp = &ph->phy_cap_aneg;
835 839 advp = &ph->phy_en_aneg;
836 840 macpp = &mh->m_en_aneg;
837 841 break;
838 842 case MAC_PROP_FLOWCTRL: {
839 843 link_flowctrl_t fc;
840 844 boolean_t chg;
841 845
842 846 ASSERT(sz >= sizeof (link_flowctrl_t));
843 847 bcopy(valp, &fc, sizeof (fc));
844 848
845 849 chg = fc == ph->phy_en_flowctrl ? B_FALSE : B_TRUE;
846 850 switch (fc) {
847 851 case LINK_FLOWCTRL_NONE:
848 852 ph->phy_en_pause = B_FALSE;
849 853 ph->phy_en_asmpause = B_FALSE;
850 854 ph->phy_en_flowctrl = fc;
851 855 break;
852 856 /*
853 857 * Note that while we don't have a way to advertise
854 858 * that we can RX pause (we just won't send pause
855 859 * frames), we advertise full support. The MAC driver
856 860 * will learn of the configuration via the saved value
857 861 * of the tunable.
858 862 */
859 863 case LINK_FLOWCTRL_BI:
860 864 case LINK_FLOWCTRL_RX:
861 865 if (ph->phy_cap_pause) {
862 866 ph->phy_en_pause = B_TRUE;
863 867 ph->phy_en_asmpause = B_TRUE;
864 868 ph->phy_en_flowctrl = fc;
865 869 } else {
866 870 rv = EINVAL;
867 871 }
868 872 break;
869 873
870 874 /*
871 875 * Tell the other side that we can assert pause, but
872 876 * we cannot resend.
873 877 */
874 878 case LINK_FLOWCTRL_TX:
875 879 if (ph->phy_cap_asmpause) {
876 880 ph->phy_en_pause = B_FALSE;
877 881 ph->phy_en_flowctrl = fc;
878 882 ph->phy_en_asmpause = B_TRUE;
879 883 } else {
880 884 rv = EINVAL;
881 885 }
882 886 break;
883 887 default:
884 888 rv = EINVAL;
885 889 break;
886 890 }
887 891 if ((rv == 0) && chg) {
888 892 mh->m_en_flowctrl = fc;
889 893 mh->m_tstate = MII_STATE_RESET;
890 894 cv_broadcast(&mh->m_cv);
891 895 }
892 896 break;
893 897 }
894 898
895 899 default:
896 900 rv = ENOTSUP;
897 901 break;
898 902 }
899 903
900 904 if (capp && advp && macpp) {
901 905 if (sz < sizeof (uint8_t)) {
902 906 rv = EINVAL;
903 907
904 908 } else if (*capp) {
905 909 if (*advp != *(uint8_t *)valp) {
906 910 *advp = *(uint8_t *)valp;
907 911 *macpp = *(uint8_t *)valp;
908 912 mh->m_tstate = MII_STATE_RESET;
909 913 cv_broadcast(&mh->m_cv);
910 914 }
911 915 rv = 0;
912 916 }
913 917 }
914 918
915 919 mutex_exit(&mh->m_lock);
916 920 return (rv);
917 921 }
918 922
919 923 int
920 924 mii_m_getstat(mii_handle_t mh, uint_t stat, uint64_t *val)
921 925 {
922 926 phy_handle_t *ph;
923 927 int rv = 0;
924 928
925 929 mutex_enter(&mh->m_lock);
926 930
927 931 ph = mh->m_phy;
928 932
929 933 switch (stat) {
930 934 case MAC_STAT_IFSPEED:
931 935 *val = ph->phy_speed * 1000000ull;
932 936 break;
933 937 case ETHER_STAT_LINK_DUPLEX:
934 938 *val = ph->phy_duplex;
935 939 break;
936 940 case ETHER_STAT_LINK_AUTONEG:
937 941 *val = !!(ph->phy_adv_aneg && ph->phy_lp_aneg);
938 942 break;
939 943 case ETHER_STAT_XCVR_ID:
940 944 *val = ph->phy_id;
941 945 break;
942 946 case ETHER_STAT_XCVR_INUSE:
943 947 *val = ph->phy_type;
944 948 break;
945 949 case ETHER_STAT_XCVR_ADDR:
946 950 *val = ph->phy_addr;
947 951 break;
948 952 case ETHER_STAT_LINK_ASMPAUSE:
949 953 *val = ph->phy_adv_asmpause && ph->phy_lp_asmpause &&
950 954 ph->phy_adv_pause != ph->phy_lp_pause;
951 955 break;
952 956 case ETHER_STAT_LINK_PAUSE:
953 957 *val = (ph->phy_flowctrl == LINK_FLOWCTRL_BI) ||
954 958 (ph->phy_flowctrl == LINK_FLOWCTRL_RX);
955 959 break;
956 960 case ETHER_STAT_CAP_1000FDX:
957 961 *val = ph->phy_cap_1000_fdx;
958 962 break;
959 963 case ETHER_STAT_CAP_1000HDX:
960 964 *val = ph->phy_cap_1000_hdx;
961 965 break;
962 966 case ETHER_STAT_CAP_100FDX:
963 967 *val = ph->phy_cap_100_fdx;
964 968 break;
965 969 case ETHER_STAT_CAP_100HDX:
966 970 *val = ph->phy_cap_100_hdx;
967 971 break;
968 972 case ETHER_STAT_CAP_10FDX:
969 973 *val = ph->phy_cap_10_fdx;
970 974 break;
971 975 case ETHER_STAT_CAP_10HDX:
972 976 *val = ph->phy_cap_10_hdx;
973 977 break;
974 978 case ETHER_STAT_CAP_100T4:
975 979 *val = ph->phy_cap_100_t4;
976 980 break;
977 981 case ETHER_STAT_CAP_AUTONEG:
978 982 *val = ph->phy_cap_aneg;
979 983 break;
980 984 case ETHER_STAT_CAP_PAUSE:
981 985 *val = ph->phy_cap_pause;
982 986 break;
983 987 case ETHER_STAT_CAP_ASMPAUSE:
984 988 *val = ph->phy_cap_asmpause;
985 989 break;
986 990
987 991 case ETHER_STAT_LP_CAP_1000FDX:
988 992 *val = ph->phy_lp_1000_fdx;
989 993 break;
990 994 case ETHER_STAT_LP_CAP_1000HDX:
991 995 *val = ph->phy_lp_1000_hdx;
992 996 break;
993 997 case ETHER_STAT_LP_CAP_100FDX:
994 998 *val = ph->phy_lp_100_fdx;
995 999 break;
996 1000 case ETHER_STAT_LP_CAP_100HDX:
997 1001 *val = ph->phy_lp_100_hdx;
998 1002 break;
999 1003 case ETHER_STAT_LP_CAP_10FDX:
1000 1004 *val = ph->phy_lp_10_fdx;
1001 1005 break;
1002 1006 case ETHER_STAT_LP_CAP_10HDX:
1003 1007 *val = ph->phy_lp_10_hdx;
1004 1008 break;
1005 1009 case ETHER_STAT_LP_CAP_100T4:
1006 1010 *val = ph->phy_lp_100_t4;
1007 1011 break;
1008 1012 case ETHER_STAT_LP_CAP_AUTONEG:
1009 1013 *val = ph->phy_lp_aneg;
1010 1014 break;
1011 1015 case ETHER_STAT_LP_CAP_PAUSE:
1012 1016 *val = ph->phy_lp_pause;
1013 1017 break;
1014 1018 case ETHER_STAT_LP_CAP_ASMPAUSE:
1015 1019 *val = ph->phy_lp_asmpause;
1016 1020 break;
1017 1021
1018 1022 case ETHER_STAT_ADV_CAP_1000FDX:
1019 1023 *val = ph->phy_adv_1000_fdx;
1020 1024 break;
1021 1025 case ETHER_STAT_ADV_CAP_1000HDX:
1022 1026 *val = ph->phy_adv_1000_hdx;
1023 1027 break;
1024 1028 case ETHER_STAT_ADV_CAP_100FDX:
1025 1029 *val = ph->phy_adv_100_fdx;
1026 1030 break;
1027 1031 case ETHER_STAT_ADV_CAP_100HDX:
1028 1032 *val = ph->phy_adv_100_hdx;
1029 1033 break;
1030 1034 case ETHER_STAT_ADV_CAP_10FDX:
1031 1035 *val = ph->phy_adv_10_fdx;
1032 1036 break;
1033 1037 case ETHER_STAT_ADV_CAP_10HDX:
1034 1038 *val = ph->phy_adv_10_hdx;
1035 1039 break;
1036 1040 case ETHER_STAT_ADV_CAP_100T4:
1037 1041 *val = ph->phy_adv_100_t4;
1038 1042 break;
1039 1043 case ETHER_STAT_ADV_CAP_AUTONEG:
1040 1044 *val = ph->phy_adv_aneg;
1041 1045 break;
1042 1046 case ETHER_STAT_ADV_CAP_PAUSE:
1043 1047 *val = ph->phy_adv_pause;
1044 1048 break;
1045 1049 case ETHER_STAT_ADV_CAP_ASMPAUSE:
1046 1050 *val = ph->phy_adv_asmpause;
1047 1051 break;
1048 1052
1049 1053 default:
1050 1054 rv = ENOTSUP;
1051 1055 break;
1052 1056 }
1053 1057 mutex_exit(&mh->m_lock);
1054 1058
1055 1059 return (rv);
1056 1060 }
1057 1061
1058 1062 /*
1059 1063 * PHY support routines. Private to the MII module and the vendor
1060 1064 * specific PHY implementation code.
1061 1065 */
1062 1066 uint16_t
1063 1067 phy_read(phy_handle_t *ph, uint8_t reg)
1064 1068 {
1065 1069 mii_handle_t mh = ph->phy_mii;
1066 1070
1067 1071 return ((*mh->m_ops.mii_read)(mh->m_private, ph->phy_addr, reg));
1068 1072 }
1069 1073
1070 1074 void
1071 1075 phy_write(phy_handle_t *ph, uint8_t reg, uint16_t val)
1072 1076 {
1073 1077 mii_handle_t mh = ph->phy_mii;
1074 1078
1075 1079 (*mh->m_ops.mii_write)(mh->m_private, ph->phy_addr, reg, val);
1076 1080 }
1077 1081
1078 1082 int
1079 1083 phy_reset(phy_handle_t *ph)
1080 1084 {
1081 1085 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1082 1086
1083 1087 /*
1084 1088 * For our device, make sure its powered up and unisolated.
1085 1089 */
1086 1090 PHY_CLR(ph, MII_CONTROL,
1087 1091 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
1088 1092
1089 1093 /*
1090 1094 * Finally reset it.
1091 1095 */
1092 1096 PHY_SET(ph, MII_CONTROL, MII_CONTROL_RESET);
1093 1097
1094 1098 /*
1095 1099 * Apparently some devices (DP83840A) like to have a little
1096 1100 * bit of a wait before we start accessing anything else on
1097 1101 * the PHY.
1098 1102 */
1099 1103 drv_usecwait(500);
1100 1104
1101 1105 /*
1102 1106 * Wait for reset to complete - probably very fast, but no
1103 1107 * more than 0.5 sec according to spec. It would be nice if
1104 1108 * we could use delay() here, but MAC drivers may call
1105 1109 * functions which hold this lock in interrupt context, so
1106 1110 * sleeping would be a definite no-no. The good news here is
1107 1111 * that it seems to be the case that most devices come back
1108 1112 * within only a few hundred usec.
1109 1113 */
1110 1114 for (int i = 500000; i; i -= 100) {
1111 1115 if ((phy_read(ph, MII_CONTROL) & MII_CONTROL_RESET) == 0) {
1112 1116 /* reset completed */
1113 1117 return (DDI_SUCCESS);
1114 1118 }
1115 1119 drv_usecwait(100);
1116 1120 }
1117 1121
1118 1122 return (DDI_FAILURE);
1119 1123 }
1120 1124
1121 1125 int
1122 1126 phy_stop(phy_handle_t *ph)
1123 1127 {
1124 1128 phy_write(ph, MII_CONTROL, MII_CONTROL_ISOLATE);
1125 1129
1126 1130 return (DDI_SUCCESS);
1127 1131 }
1128 1132
1129 1133 int
1130 1134 phy_loop(phy_handle_t *ph)
1131 1135 {
1132 1136 uint16_t bmcr, gtcr;
1133 1137
1134 1138 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1135 1139
1136 1140 /*
1137 1141 * Disable everything to start... we'll add in modes as we go.
1138 1142 */
1139 1143 ph->phy_adv_aneg = B_FALSE;
1140 1144 ph->phy_adv_1000_fdx = B_FALSE;
1141 1145 ph->phy_adv_1000_hdx = B_FALSE;
1142 1146 ph->phy_adv_100_fdx = B_FALSE;
1143 1147 ph->phy_adv_100_t4 = B_FALSE;
1144 1148 ph->phy_adv_100_hdx = B_FALSE;
1145 1149 ph->phy_adv_10_fdx = B_FALSE;
1146 1150 ph->phy_adv_10_hdx = B_FALSE;
1147 1151 ph->phy_adv_pause = B_FALSE;
1148 1152 ph->phy_adv_asmpause = B_FALSE;
1149 1153
1150 1154 bmcr = 0;
1151 1155 gtcr = MII_MSCONTROL_MANUAL | MII_MSCONTROL_MASTER;
1152 1156
1153 1157 switch (ph->phy_loopback) {
1154 1158 case PHY_LB_NONE:
1155 1159 /* We shouldn't be here */
1156 1160 ASSERT(0);
1157 1161 break;
1158 1162
1159 1163 case PHY_LB_INT_PHY:
1160 1164 bmcr |= MII_CONTROL_LOOPBACK;
1161 1165 ph->phy_duplex = LINK_DUPLEX_FULL;
1162 1166 if (ph->phy_cap_1000_fdx) {
1163 1167 bmcr |= MII_CONTROL_1GB | MII_CONTROL_FDUPLEX;
1164 1168 ph->phy_speed = 1000;
1165 1169 } else if (ph->phy_cap_100_fdx) {
1166 1170 bmcr |= MII_CONTROL_100MB | MII_CONTROL_FDUPLEX;
1167 1171 ph->phy_speed = 100;
1168 1172 } else if (ph->phy_cap_10_fdx) {
1169 1173 bmcr |= MII_CONTROL_FDUPLEX;
1170 1174 ph->phy_speed = 10;
1171 1175 }
1172 1176 break;
1173 1177
1174 1178 case PHY_LB_EXT_10:
1175 1179 bmcr = MII_CONTROL_FDUPLEX;
1176 1180 ph->phy_speed = 10;
1177 1181 ph->phy_duplex = LINK_DUPLEX_FULL;
1178 1182 break;
1179 1183
1180 1184 case PHY_LB_EXT_100:
1181 1185 bmcr = MII_CONTROL_100MB | MII_CONTROL_FDUPLEX;
1182 1186 ph->phy_speed = 100;
1183 1187 ph->phy_duplex = LINK_DUPLEX_FULL;
1184 1188 break;
1185 1189
1186 1190 case PHY_LB_EXT_1000:
1187 1191 bmcr = MII_CONTROL_1GB | MII_CONTROL_FDUPLEX;
1188 1192 ph->phy_speed = 1000;
1189 1193 ph->phy_duplex = LINK_DUPLEX_FULL;
1190 1194 break;
1191 1195 }
1192 1196
1193 1197 ph->phy_link = LINK_STATE_UP; /* force up for loopback */
1194 1198 ph->phy_flowctrl = LINK_FLOWCTRL_NONE;
1195 1199
1196 1200 switch (ph->phy_type) {
1197 1201 case XCVR_1000T:
1198 1202 case XCVR_1000X:
1199 1203 case XCVR_100T2:
1200 1204 phy_write(ph, MII_MSCONTROL, gtcr);
1201 1205 break;
1202 1206 }
1203 1207
1204 1208 phy_write(ph, MII_CONTROL, bmcr);
1205 1209
1206 1210 return (DDI_SUCCESS);
1207 1211 }
1208 1212
1209 1213 int
1210 1214 phy_start(phy_handle_t *ph)
1211 1215 {
1212 1216 uint16_t bmcr, anar, gtcr;
1213 1217 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1214 1218
1215 1219 ASSERT(ph->phy_loopback == PHY_LB_NONE);
1216 1220
1217 1221 /*
1218 1222 * No loopback overrides, so try to advertise everything
1219 1223 * that is administratively enabled.
1220 1224 */
1221 1225 ph->phy_adv_aneg = ph->phy_en_aneg;
1222 1226 ph->phy_adv_1000_fdx = ph->phy_en_1000_fdx;
1223 1227 ph->phy_adv_1000_hdx = ph->phy_en_1000_hdx;
1224 1228 ph->phy_adv_100_fdx = ph->phy_en_100_fdx;
1225 1229 ph->phy_adv_100_t4 = ph->phy_en_100_t4;
1226 1230 ph->phy_adv_100_hdx = ph->phy_en_100_hdx;
1227 1231 ph->phy_adv_10_fdx = ph->phy_en_10_fdx;
1228 1232 ph->phy_adv_10_hdx = ph->phy_en_10_hdx;
1229 1233 ph->phy_adv_pause = ph->phy_en_pause;
1230 1234 ph->phy_adv_asmpause = ph->phy_en_asmpause;
1231 1235
1232 1236 /*
1233 1237 * Limit properties to what the hardware can actually support.
1234 1238 */
1235 1239 #define FILTER_ADV(CAP) \
1236 1240 if (!ph->phy_cap_##CAP) \
1237 1241 ph->phy_adv_##CAP = 0
1238 1242
1239 1243 FILTER_ADV(aneg);
1240 1244 FILTER_ADV(1000_fdx);
1241 1245 FILTER_ADV(1000_hdx);
1242 1246 FILTER_ADV(100_fdx);
1243 1247 FILTER_ADV(100_t4);
1244 1248 FILTER_ADV(100_hdx);
1245 1249 FILTER_ADV(10_fdx);
1246 1250 FILTER_ADV(10_hdx);
1247 1251 FILTER_ADV(pause);
1248 1252 FILTER_ADV(asmpause);
1249 1253
1250 1254 #undef FILTER_ADV
1251 1255
1252 1256 /*
1253 1257 * We need at least one valid mode.
1254 1258 */
1255 1259 if ((!ph->phy_adv_1000_fdx) &&
1256 1260 (!ph->phy_adv_1000_hdx) &&
1257 1261 (!ph->phy_adv_100_t4) &&
1258 1262 (!ph->phy_adv_100_fdx) &&
1259 1263 (!ph->phy_adv_100_hdx) &&
1260 1264 (!ph->phy_adv_10_fdx) &&
1261 1265 (!ph->phy_adv_10_hdx)) {
1262 1266
1263 1267 phy_warn(ph,
1264 1268 "No valid link mode selected. Powering down PHY.");
1265 1269
1266 1270 PHY_SET(ph, MII_CONTROL, MII_CONTROL_PWRDN);
1267 1271
1268 1272 ph->phy_link = LINK_STATE_DOWN;
1269 1273 return (DDI_SUCCESS);
1270 1274 }
1271 1275
1272 1276 bmcr = 0;
1273 1277 gtcr = 0;
1274 1278
1275 1279 if (ph->phy_adv_aneg) {
1276 1280 bmcr |= MII_CONTROL_ANE | MII_CONTROL_RSAN;
1277 1281 }
1278 1282
1279 1283 if ((ph->phy_adv_1000_fdx) || (ph->phy_adv_1000_hdx)) {
1280 1284 bmcr |= MII_CONTROL_1GB;
1281 1285
1282 1286 } else if (ph->phy_adv_100_fdx || ph->phy_adv_100_hdx ||
1283 1287 ph->phy_adv_100_t4) {
1284 1288 bmcr |= MII_CONTROL_100MB;
1285 1289 }
1286 1290
1287 1291 if (ph->phy_adv_1000_fdx || ph->phy_adv_100_fdx || ph->phy_adv_10_fdx) {
1288 1292 bmcr |= MII_CONTROL_FDUPLEX;
1289 1293 }
1290 1294
1291 1295 if (ph->phy_type == XCVR_1000X) {
1292 1296 /* 1000BASE-X (usually fiber) */
1293 1297 anar = 0;
1294 1298 if (ph->phy_adv_1000_fdx) {
1295 1299 anar |= MII_ABILITY_X_FD;
1296 1300 }
1297 1301 if (ph->phy_adv_1000_hdx) {
1298 1302 anar |= MII_ABILITY_X_HD;
1299 1303 }
1300 1304 if (ph->phy_adv_pause) {
1301 1305 anar |= MII_ABILITY_X_PAUSE;
1302 1306 }
1303 1307 if (ph->phy_adv_asmpause) {
1304 1308 anar |= MII_ABILITY_X_ASMPAUSE;
1305 1309 }
1306 1310
1307 1311 } else if (ph->phy_type == XCVR_100T2) {
1308 1312 /* 100BASE-T2 */
1309 1313 anar = 0;
1310 1314 if (ph->phy_adv_100_fdx) {
1311 1315 anar |= MII_ABILITY_T2_FD;
1312 1316 }
1313 1317 if (ph->phy_adv_100_hdx) {
1314 1318 anar |= MII_ABILITY_T2_HD;
1315 1319 }
1316 1320
1317 1321 } else {
1318 1322 anar = MII_AN_SELECTOR_8023;
1319 1323
1320 1324 /* 1000BASE-T or 100BASE-X probably */
1321 1325 if (ph->phy_adv_1000_fdx) {
1322 1326 gtcr |= MII_MSCONTROL_1000T_FD;
1323 1327 }
1324 1328 if (ph->phy_adv_1000_hdx) {
1325 1329 gtcr |= MII_MSCONTROL_1000T;
1326 1330 }
1327 1331 if (ph->phy_adv_100_fdx) {
1328 1332 anar |= MII_ABILITY_100BASE_TX_FD;
1329 1333 }
1330 1334 if (ph->phy_adv_100_hdx) {
1331 1335 anar |= MII_ABILITY_100BASE_TX;
1332 1336 }
1333 1337 if (ph->phy_adv_100_t4) {
1334 1338 anar |= MII_ABILITY_100BASE_T4;
1335 1339 }
1336 1340 if (ph->phy_adv_10_fdx) {
1337 1341 anar |= MII_ABILITY_10BASE_T_FD;
1338 1342 }
1339 1343 if (ph->phy_adv_10_hdx) {
1340 1344 anar |= MII_ABILITY_10BASE_T;
1341 1345 }
1342 1346 if (ph->phy_adv_pause) {
1343 1347 anar |= MII_ABILITY_PAUSE;
1344 1348 }
1345 1349 if (ph->phy_adv_asmpause) {
1346 1350 anar |= MII_ABILITY_ASMPAUSE;
1347 1351 }
1348 1352 }
1349 1353
1350 1354 ph->phy_link = LINK_STATE_DOWN;
1351 1355 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1352 1356 ph->phy_speed = 0;
1353 1357
1354 1358 phy_write(ph, MII_AN_ADVERT, anar);
1355 1359 phy_write(ph, MII_CONTROL, bmcr & ~(MII_CONTROL_RSAN));
1356 1360
1357 1361 switch (ph->phy_type) {
1358 1362 case XCVR_1000T:
1359 1363 case XCVR_1000X:
1360 1364 case XCVR_100T2:
1361 1365 phy_write(ph, MII_MSCONTROL, gtcr);
1362 1366 }
1363 1367
1364 1368 /*
1365 1369 * Finally, this will start up autoneg if it is enabled, or
1366 1370 * force link settings otherwise.
1367 1371 */
1368 1372 phy_write(ph, MII_CONTROL, bmcr);
1369 1373
1370 1374 return (DDI_SUCCESS);
1371 1375 }
1372 1376
1373 1377
1374 1378 int
1375 1379 phy_check(phy_handle_t *ph)
1376 1380 {
1377 1381 uint16_t control, status, lpar, msstat, anexp;
1378 1382 int debounces = 100;
1379 1383
1380 1384 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1381 1385
1382 1386 debounce:
1383 1387 status = phy_read(ph, MII_STATUS);
1384 1388 control = phy_read(ph, MII_CONTROL);
1385 1389
1386 1390 if (status & MII_STATUS_EXTENDED) {
1387 1391 lpar = phy_read(ph, MII_AN_LPABLE);
1388 1392 anexp = phy_read(ph, MII_AN_EXPANSION);
1389 1393 } else {
1390 1394 lpar = 0;
1391 1395 anexp = 0;
1392 1396 }
1393 1397
1394 1398 /*
1395 1399 * We reread to clear any latched bits. This also debounces
1396 1400 * any state that might be in transition.
1397 1401 */
1398 1402 drv_usecwait(10);
1399 1403 if ((status != phy_read(ph, MII_STATUS)) && debounces) {
1400 1404 debounces--;
1401 1405 goto debounce;
1402 1406 }
1403 1407
1404 1408 /*
1405 1409 * Detect the situation where the PHY is removed or has died.
1406 1410 * According to spec, at least one bit of status must be set,
1407 1411 * and at least one bit must be clear.
1408 1412 */
1409 1413 if ((status == 0xffff) || (status == 0)) {
1410 1414 ph->phy_speed = 0;
1411 1415 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1412 1416 ph->phy_link = LINK_STATE_UNKNOWN;
1413 1417 ph->phy_present = B_FALSE;
1414 1418 return (DDI_FAILURE);
1415 1419 }
1416 1420
1417 1421 /* We only respect the link flag if we are not in loopback. */
1418 1422 if ((ph->phy_loopback != PHY_LB_INT_PHY) &&
1419 1423 ((status & MII_STATUS_LINKUP) == 0)) {
1420 1424 ph->phy_speed = 0;
1421 1425 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1422 1426 ph->phy_link = LINK_STATE_DOWN;
1423 1427 return (DDI_SUCCESS);
1424 1428 }
1425 1429
1426 1430 ph->phy_link = LINK_STATE_UP;
1427 1431
1428 1432 if ((control & MII_CONTROL_ANE) == 0) {
1429 1433
1430 1434 ph->phy_lp_aneg = B_FALSE;
1431 1435 ph->phy_lp_10_hdx = B_FALSE;
1432 1436 ph->phy_lp_10_fdx = B_FALSE;
1433 1437 ph->phy_lp_100_t4 = B_FALSE;
1434 1438 ph->phy_lp_100_hdx = B_FALSE;
1435 1439 ph->phy_lp_100_fdx = B_FALSE;
1436 1440 ph->phy_lp_1000_hdx = B_FALSE;
1437 1441 ph->phy_lp_1000_fdx = B_FALSE;
1438 1442
1439 1443 /*
1440 1444 * We have no idea what our link partner might or might
1441 1445 * not be able to support, except that it appears to
1442 1446 * support the same mode that we have forced.
1443 1447 */
1444 1448 if (control & MII_CONTROL_1GB) {
1445 1449 ph->phy_speed = 1000;
1446 1450 } else if (control & MII_CONTROL_100MB) {
1447 1451 ph->phy_speed = 100;
1448 1452 } else {
1449 1453 ph->phy_speed = 10;
1450 1454 }
1451 1455 ph->phy_duplex = control & MII_CONTROL_FDUPLEX ?
1452 1456 LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
1453 1457
1454 1458 return (DDI_SUCCESS);
1455 1459 }
1456 1460
1457 1461 if (ph->phy_type == XCVR_1000X) {
1458 1462
1459 1463 ph->phy_lp_10_hdx = B_FALSE;
1460 1464 ph->phy_lp_10_fdx = B_FALSE;
1461 1465 ph->phy_lp_100_t4 = B_FALSE;
1462 1466 ph->phy_lp_100_hdx = B_FALSE;
1463 1467 ph->phy_lp_100_fdx = B_FALSE;
1464 1468
1465 1469 /* 1000BASE-X requires autonegotiation */
1466 1470 ph->phy_lp_aneg = B_TRUE;
1467 1471 ph->phy_lp_1000_fdx = !!(lpar & MII_ABILITY_X_FD);
1468 1472 ph->phy_lp_1000_hdx = !!(lpar & MII_ABILITY_X_HD);
1469 1473 ph->phy_lp_pause = !!(lpar & MII_ABILITY_X_PAUSE);
1470 1474 ph->phy_lp_asmpause = !!(lpar & MII_ABILITY_X_ASMPAUSE);
1471 1475
1472 1476 } else if (ph->phy_type == XCVR_100T2) {
1473 1477 ph->phy_lp_10_hdx = B_FALSE;
1474 1478 ph->phy_lp_10_fdx = B_FALSE;
1475 1479 ph->phy_lp_100_t4 = B_FALSE;
1476 1480 ph->phy_lp_1000_hdx = B_FALSE;
1477 1481 ph->phy_lp_1000_fdx = B_FALSE;
1478 1482 ph->phy_lp_pause = B_FALSE;
1479 1483 ph->phy_lp_asmpause = B_FALSE;
1480 1484
1481 1485 /* 100BASE-T2 requires autonegotiation */
1482 1486 ph->phy_lp_aneg = B_TRUE;
1483 1487 ph->phy_lp_100_fdx = !!(lpar & MII_ABILITY_T2_FD);
1484 1488 ph->phy_lp_100_hdx = !!(lpar & MII_ABILITY_T2_HD);
1485 1489
1486 1490 } else if (anexp & MII_AN_EXP_PARFAULT) {
1487 1491 /*
1488 1492 * Parallel detection fault! This happens when the
1489 1493 * peer does not use autonegotiation, and the
1490 1494 * detection logic reports more than one type of legal
1491 1495 * link is available. Note that parallel detection
1492 1496 * can only happen with half duplex 10, 100, and
1493 1497 * 100TX4. We also should not have got here, because
1494 1498 * the link state bit should have failed.
1495 1499 */
1496 1500 #ifdef DEBUG
1497 1501 phy_warn(ph, "Parallel detection fault!");
1498 1502 #endif
1499 1503 ph->phy_lp_10_hdx = B_FALSE;
1500 1504 ph->phy_lp_10_fdx = B_FALSE;
1501 1505 ph->phy_lp_100_t4 = B_FALSE;
1502 1506 ph->phy_lp_100_hdx = B_FALSE;
1503 1507 ph->phy_lp_100_fdx = B_FALSE;
1504 1508 ph->phy_lp_1000_hdx = B_FALSE;
1505 1509 ph->phy_lp_1000_fdx = B_FALSE;
1506 1510 ph->phy_lp_pause = B_FALSE;
1507 1511 ph->phy_lp_asmpause = B_FALSE;
1508 1512 ph->phy_speed = 0;
1509 1513 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1510 1514 return (DDI_SUCCESS);
1511 1515
↓ open down ↓ |
1475 lines elided |
↑ open up ↑ |
1512 1516 } else {
1513 1517 ph->phy_lp_aneg = !!(anexp & MII_AN_EXP_LPCANAN);
1514 1518
1515 1519 /*
1516 1520 * Note: If the peer doesn't support autonegotiation, then
1517 1521 * according to clause 28.5.4.5, the link partner ability
1518 1522 * register will still have the right bits set. However,
1519 1523 * gigabit modes cannot use legacy parallel detection.
1520 1524 */
1521 1525
1522 - if ((ph->phy_type == XCVR_1000T) &
1526 + if ((ph->phy_type == XCVR_1000T) &&
1523 1527 (anexp & MII_AN_EXP_LPCANAN)) {
1524 1528
1525 1529 /* check for gige */
1526 1530 msstat = phy_read(ph, MII_MSSTATUS);
1527 1531
1528 1532 ph->phy_lp_1000_hdx =
1529 1533 !!(msstat & MII_MSSTATUS_LP1000T);
1530 1534
1531 1535 ph->phy_lp_1000_fdx =
1532 1536 !!(msstat & MII_MSSTATUS_LP1000T_FD);
1533 1537 }
1534 1538
1535 1539 ph->phy_lp_100_fdx = !!(lpar & MII_ABILITY_100BASE_TX_FD);
1536 1540 ph->phy_lp_100_hdx = !!(lpar & MII_ABILITY_100BASE_TX);
1537 1541 ph->phy_lp_100_t4 = !!(lpar & MII_ABILITY_100BASE_T4);
1538 1542 ph->phy_lp_10_fdx = !!(lpar & MII_ABILITY_10BASE_T_FD);
1539 1543 ph->phy_lp_10_hdx = !!(lpar & MII_ABILITY_10BASE_T);
1540 1544 ph->phy_lp_pause = !!(lpar & MII_ABILITY_PAUSE);
1541 1545 ph->phy_lp_asmpause = !!(lpar & MII_ABILITY_ASMPAUSE);
1542 1546 }
1543 1547
1544 1548 /* resolve link pause */
1545 1549 if ((ph->phy_en_flowctrl == LINK_FLOWCTRL_BI) &&
1546 1550 (ph->phy_lp_pause)) {
1547 1551 ph->phy_flowctrl = LINK_FLOWCTRL_BI;
1548 1552 } else if ((ph->phy_en_flowctrl == LINK_FLOWCTRL_RX) &&
1549 1553 (ph->phy_lp_pause || ph->phy_lp_asmpause)) {
1550 1554 ph->phy_flowctrl = LINK_FLOWCTRL_RX;
1551 1555 } else if ((ph->phy_en_flowctrl == LINK_FLOWCTRL_TX) &&
1552 1556 (ph->phy_lp_pause)) {
1553 1557 ph->phy_flowctrl = LINK_FLOWCTRL_TX;
1554 1558 } else {
1555 1559 ph->phy_flowctrl = LINK_FLOWCTRL_NONE;
1556 1560 }
1557 1561
1558 1562 if (ph->phy_adv_1000_fdx && ph->phy_lp_1000_fdx) {
1559 1563 ph->phy_speed = 1000;
1560 1564 ph->phy_duplex = LINK_DUPLEX_FULL;
1561 1565
1562 1566 } else if (ph->phy_adv_1000_hdx && ph->phy_lp_1000_hdx) {
1563 1567 ph->phy_speed = 1000;
1564 1568 ph->phy_duplex = LINK_DUPLEX_HALF;
1565 1569
1566 1570 } else if (ph->phy_adv_100_fdx && ph->phy_lp_100_fdx) {
1567 1571 ph->phy_speed = 100;
1568 1572 ph->phy_duplex = LINK_DUPLEX_FULL;
1569 1573
1570 1574 } else if (ph->phy_adv_100_t4 && ph->phy_lp_100_t4) {
1571 1575 ph->phy_speed = 100;
1572 1576 ph->phy_duplex = LINK_DUPLEX_HALF;
1573 1577
1574 1578 } else if (ph->phy_adv_100_hdx && ph->phy_lp_100_hdx) {
1575 1579 ph->phy_speed = 100;
1576 1580 ph->phy_duplex = LINK_DUPLEX_HALF;
1577 1581
1578 1582 } else if (ph->phy_adv_10_fdx && ph->phy_lp_10_fdx) {
1579 1583 ph->phy_speed = 10;
1580 1584 ph->phy_duplex = LINK_DUPLEX_FULL;
1581 1585
1582 1586 } else if (ph->phy_adv_10_hdx && ph->phy_lp_10_hdx) {
1583 1587 ph->phy_speed = 10;
1584 1588 ph->phy_duplex = LINK_DUPLEX_HALF;
1585 1589
1586 1590 } else {
1587 1591 #ifdef DEBUG
1588 1592 phy_warn(ph, "No common abilities.");
1589 1593 #endif
1590 1594 ph->phy_speed = 0;
1591 1595 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1592 1596 }
1593 1597
1594 1598 return (DDI_SUCCESS);
1595 1599 }
1596 1600
1597 1601 int
1598 1602 phy_get_prop(phy_handle_t *ph, char *prop, int dflt)
1599 1603 {
1600 1604 mii_handle_t mh = ph->phy_mii;
1601 1605
1602 1606 return (ddi_prop_get_int(DDI_DEV_T_ANY, mh->m_dip, 0, prop, dflt));
1603 1607 }
1604 1608
1605 1609 const char *
1606 1610 phy_get_name(phy_handle_t *ph)
1607 1611 {
1608 1612 mii_handle_t mh = ph->phy_mii;
1609 1613
1610 1614 return (mh->m_name);
1611 1615 }
1612 1616
1613 1617 const char *
1614 1618 phy_get_driver(phy_handle_t *ph)
1615 1619 {
1616 1620 mii_handle_t mh = ph->phy_mii;
1617 1621
1618 1622 return (ddi_driver_name(mh->m_dip));
1619 1623 }
1620 1624
1621 1625 void
1622 1626 phy_warn(phy_handle_t *ph, const char *fmt, ...)
1623 1627 {
1624 1628 va_list va;
1625 1629 char buf[256];
1626 1630
1627 1631 (void) snprintf(buf, sizeof (buf), "%s: %s", phy_get_name(ph), fmt);
1628 1632
1629 1633 va_start(va, fmt);
1630 1634 vcmn_err(CE_WARN, buf, va);
1631 1635 va_end(va);
1632 1636 }
1633 1637
1634 1638 /*
1635 1639 * Internal support routines.
1636 1640 */
1637 1641
1638 1642 void
1639 1643 _mii_notify(mii_handle_t mh)
1640 1644 {
1641 1645 if (mh->m_ops.mii_notify != NULL) {
1642 1646 mh->m_ops.mii_notify(mh->m_private, mh->m_link);
1643 1647 }
1644 1648 }
1645 1649
1646 1650 void
1647 1651 _mii_probe_phy(phy_handle_t *ph)
1648 1652 {
1649 1653 uint16_t bmsr;
1650 1654 uint16_t extsr;
1651 1655 mii_handle_t mh = ph->phy_mii;
1652 1656
1653 1657
1654 1658 /*
1655 1659 * Apparently, PHY 0 is less likely to be physically
1656 1660 * connected, and should always be the last one tried. Most
1657 1661 * single solution NICs use PHY1 for their built-in
1658 1662 * transceiver. NICs with an external MII will often place
1659 1663 * the external PHY at address 1, and use address 0 for the
1660 1664 * internal PHY.
1661 1665 */
1662 1666
1663 1667 ph->phy_id = 0;
1664 1668 ph->phy_model = "PHY";
1665 1669 ph->phy_vendor = "Unknown Vendor";
1666 1670
1667 1671 /* done twice to clear any latched bits */
1668 1672 bmsr = phy_read(ph, MII_STATUS);
1669 1673 bmsr = phy_read(ph, MII_STATUS);
1670 1674 if ((bmsr == 0) || (bmsr == 0xffff)) {
1671 1675 ph->phy_present = B_FALSE;
1672 1676 return;
1673 1677 }
1674 1678
1675 1679 if (bmsr & MII_STATUS_EXTSTAT) {
1676 1680 extsr = phy_read(ph, MII_EXTSTATUS);
1677 1681 } else {
1678 1682 extsr = 0;
1679 1683 }
1680 1684
1681 1685 ph->phy_present = B_TRUE;
1682 1686 ph->phy_id = ((uint32_t)phy_read(ph, MII_PHYIDH) << 16) |
1683 1687 phy_read(ph, MII_PHYIDL);
1684 1688
1685 1689 /* setup default handlers */
1686 1690 ph->phy_reset = phy_reset;
1687 1691 ph->phy_start = phy_start;
1688 1692 ph->phy_stop = phy_stop;
1689 1693 ph->phy_check = phy_check;
1690 1694 ph->phy_loop = phy_loop;
1691 1695
1692 1696 /*
1693 1697 * We ignore the non-existent 100baseT2 stuff -- no
1694 1698 * known products for it exist.
1695 1699 */
1696 1700 ph->phy_cap_aneg = !!(bmsr & MII_STATUS_CANAUTONEG);
1697 1701 ph->phy_cap_100_t4 = !!(bmsr & MII_STATUS_100_BASE_T4);
1698 1702 ph->phy_cap_100_fdx = !!(bmsr & MII_STATUS_100_BASEX_FD);
1699 1703 ph->phy_cap_100_hdx = !!(bmsr & MII_STATUS_100_BASEX);
1700 1704 ph->phy_cap_10_fdx = !!(bmsr & MII_STATUS_10_FD);
1701 1705 ph->phy_cap_10_hdx = !!(bmsr & MII_STATUS_10);
1702 1706 ph->phy_cap_1000_fdx =
1703 1707 !!(extsr & (MII_EXTSTATUS_1000X_FD|MII_EXTSTATUS_1000T_FD));
1704 1708 ph->phy_cap_1000_hdx =
1705 1709 !!(extsr & (MII_EXTSTATUS_1000X | MII_EXTSTATUS_1000T));
1706 1710 ph->phy_cap_pause = mh->m_cap_pause;
1707 1711 ph->phy_cap_asmpause = mh->m_cap_asmpause;
1708 1712
1709 1713 if (bmsr & MII_STATUS_10) {
1710 1714 ph->phy_cap_10_hdx = B_TRUE;
1711 1715 ph->phy_type = XCVR_10;
1712 1716 }
1713 1717 if (bmsr & MII_STATUS_10_FD) {
1714 1718 ph->phy_cap_10_fdx = B_TRUE;
1715 1719 ph->phy_type = XCVR_10;
1716 1720 }
1717 1721 if (bmsr & MII_STATUS_100T2) {
1718 1722 ph->phy_cap_100_hdx = B_TRUE;
1719 1723 ph->phy_type = XCVR_100T2;
1720 1724 }
1721 1725 if (bmsr & MII_STATUS_100T2_FD) {
1722 1726 ph->phy_cap_100_fdx = B_TRUE;
1723 1727 ph->phy_type = XCVR_100T2;
1724 1728 }
1725 1729 if (bmsr & MII_STATUS_100_BASE_T4) {
1726 1730 ph->phy_cap_100_hdx = B_TRUE;
1727 1731 ph->phy_type = XCVR_100T4;
1728 1732 }
1729 1733 if (bmsr & MII_STATUS_100_BASEX) {
1730 1734 ph->phy_cap_100_hdx = B_TRUE;
1731 1735 ph->phy_type = XCVR_100X;
1732 1736 }
1733 1737 if (bmsr & MII_STATUS_100_BASEX_FD) {
1734 1738 ph->phy_cap_100_fdx = B_TRUE;
1735 1739 ph->phy_type = XCVR_100X;
1736 1740 }
1737 1741 if (extsr & MII_EXTSTATUS_1000X) {
1738 1742 ph->phy_cap_1000_hdx = B_TRUE;
1739 1743 ph->phy_type = XCVR_1000X;
1740 1744 }
1741 1745 if (extsr & MII_EXTSTATUS_1000X_FD) {
1742 1746 ph->phy_cap_1000_fdx = B_TRUE;
1743 1747 ph->phy_type = XCVR_1000X;
1744 1748 }
1745 1749 if (extsr & MII_EXTSTATUS_1000T) {
1746 1750 ph->phy_cap_1000_hdx = B_TRUE;
1747 1751 ph->phy_type = XCVR_1000T;
1748 1752 }
1749 1753 if (extsr & MII_EXTSTATUS_1000T_FD) {
1750 1754 ph->phy_cap_1000_fdx = B_TRUE;
1751 1755 ph->phy_type = XCVR_1000T;
1752 1756 }
1753 1757
1754 1758 for (int j = 0; _phy_probes[j] != NULL; j++) {
1755 1759 if ((*_phy_probes[j])(ph)) {
1756 1760 break;
1757 1761 }
1758 1762 }
1759 1763
1760 1764 #define INIT_ENABLE(CAP) \
1761 1765 ph->phy_en_##CAP = (mh->m_en_##CAP > 0) ? \
1762 1766 mh->m_en_##CAP : ph->phy_cap_##CAP
1763 1767
1764 1768 INIT_ENABLE(aneg);
1765 1769 INIT_ENABLE(1000_fdx);
1766 1770 INIT_ENABLE(1000_hdx);
1767 1771 INIT_ENABLE(100_fdx);
1768 1772 INIT_ENABLE(100_t4);
1769 1773 INIT_ENABLE(100_hdx);
1770 1774 INIT_ENABLE(10_fdx);
1771 1775 INIT_ENABLE(10_hdx);
1772 1776
1773 1777 #undef INIT_ENABLE
1774 1778 ph->phy_en_flowctrl = mh->m_en_flowctrl;
1775 1779 switch (ph->phy_en_flowctrl) {
1776 1780 case LINK_FLOWCTRL_BI:
1777 1781 case LINK_FLOWCTRL_RX:
1778 1782 ph->phy_en_pause = B_TRUE;
1779 1783 ph->phy_en_asmpause = B_TRUE;
1780 1784 break;
1781 1785 case LINK_FLOWCTRL_TX:
1782 1786 ph->phy_en_pause = B_FALSE;
1783 1787 ph->phy_en_asmpause = B_TRUE;
1784 1788 break;
1785 1789 default:
1786 1790 ph->phy_en_pause = B_FALSE;
1787 1791 ph->phy_en_asmpause = B_FALSE;
1788 1792 break;
1789 1793 }
1790 1794 }
1791 1795
1792 1796 void
1793 1797 _mii_probe(mii_handle_t mh)
1794 1798 {
1795 1799 uint8_t new_addr;
1796 1800 uint8_t old_addr;
1797 1801 uint8_t user_addr;
1798 1802 uint8_t curr_addr;
1799 1803 phy_handle_t *ph;
1800 1804 int pri = 0;
1801 1805 int first;
1802 1806
1803 1807 user_addr = ddi_prop_get_int(DDI_DEV_T_ANY, mh->m_dip, 0,
1804 1808 "phy-addr", -1);
1805 1809 old_addr = mh->m_addr;
1806 1810 new_addr = 0xff;
1807 1811
1808 1812 /*
1809 1813 * Apparently, PHY 0 is less likely to be physically
1810 1814 * connected, and should always be the last one tried. Most
1811 1815 * single solution NICs use PHY1 for their built-in
1812 1816 * transceiver. NICs with an external MII will often place
1813 1817 * the external PHY at address 1, and use address 0 for the
1814 1818 * internal PHY.
1815 1819 *
1816 1820 * Some devices have a different preference however. They can
1817 1821 * override the default starting point of the search by
1818 1822 * exporting a "first-phy" property.
1819 1823 */
1820 1824
1821 1825 first = ddi_prop_get_int(DDI_DEV_T_ANY, mh->m_dip, 0, "first-phy", 1);
1822 1826 if ((first < 0) || (first > 31)) {
1823 1827 first = 1;
1824 1828 }
1825 1829 for (int i = first; i < (first + 32); i++) {
1826 1830
1827 1831 /*
1828 1832 * This is tricky: it lets us start searching at an
1829 1833 * arbitrary address instead of 0, dealing with the
1830 1834 * wrap-around at address 31 properly.
1831 1835 */
1832 1836 curr_addr = i % 32;
1833 1837
1834 1838 ph = &mh->m_phys[curr_addr];
1835 1839
1836 1840 bzero(ph, sizeof (*ph));
1837 1841 ph->phy_addr = curr_addr;
1838 1842 ph->phy_mii = mh;
1839 1843
1840 1844 _mii_probe_phy(ph);
1841 1845
1842 1846 if (!ph->phy_present)
1843 1847 continue;
1844 1848
1845 1849 if (curr_addr == user_addr) {
1846 1850 /*
1847 1851 * We always try to honor the user configured phy.
1848 1852 */
1849 1853 new_addr = curr_addr;
1850 1854 pri = 4;
1851 1855
1852 1856 }
1853 1857
1854 1858 /* two reads to clear latched bits */
1855 1859 if ((phy_read(ph, MII_STATUS) & MII_STATUS_LINKUP) &&
1856 1860 (phy_read(ph, MII_STATUS) & MII_STATUS_LINKUP) &&
1857 1861 (pri < 3)) {
1858 1862 /*
1859 1863 * Link present is good. We prefer this over
1860 1864 * a possibly disconnected link.
1861 1865 */
1862 1866 new_addr = curr_addr;
1863 1867 pri = 3;
1864 1868 }
1865 1869 if ((curr_addr == old_addr) && (pri < 2)) {
1866 1870 /*
1867 1871 * All else being equal, minimize change.
1868 1872 */
1869 1873 new_addr = curr_addr;
1870 1874 pri = 2;
1871 1875
1872 1876 }
1873 1877 if (pri < 1) {
1874 1878 /*
1875 1879 * But make sure we at least select a present PHY.
1876 1880 */
1877 1881 new_addr = curr_addr;
1878 1882 pri = 1;
1879 1883 }
1880 1884 }
1881 1885
1882 1886 if (new_addr == 0xff) {
1883 1887 mh->m_addr = -1;
1884 1888 mh->m_phy = &mh->m_bogus_phy;
1885 1889 _mii_error(mh, MII_ENOPHY);
1886 1890 } else {
1887 1891 mh->m_addr = new_addr;
1888 1892 mh->m_phy = &mh->m_phys[new_addr];
1889 1893 mh->m_tstate = MII_STATE_RESET;
1890 1894 if (new_addr != old_addr) {
1891 1895 cmn_err(CE_CONT,
1892 1896 "?%s: Using %s Ethernet PHY at %d: %s %s\n",
1893 1897 mh->m_name, mii_xcvr_types[mh->m_phy->phy_type],
1894 1898 mh->m_addr, mh->m_phy->phy_vendor,
1895 1899 mh->m_phy->phy_model);
1896 1900 mh->m_link = LINK_STATE_UNKNOWN;
1897 1901 }
1898 1902 }
1899 1903 }
1900 1904
1901 1905 int
1902 1906 _mii_reset(mii_handle_t mh)
1903 1907 {
1904 1908 phy_handle_t *ph;
1905 1909 boolean_t notify;
1906 1910
1907 1911 ASSERT(mutex_owned(&mh->m_lock));
1908 1912
1909 1913 /*
1910 1914 * Reset logic. We want to isolate all the other
1911 1915 * phys that are not in use.
1912 1916 */
1913 1917 for (int i = 0; i < 32; i++) {
1914 1918 ph = &mh->m_phys[i];
1915 1919
1916 1920 if (!ph->phy_present)
1917 1921 continue;
1918 1922
1919 1923 /* Don't touch our own phy, yet. */
1920 1924 if (ph == mh->m_phy)
1921 1925 continue;
1922 1926
1923 1927 ph->phy_stop(ph);
1924 1928 }
1925 1929
1926 1930 ph = mh->m_phy;
1927 1931
1928 1932 ASSERT(ph->phy_present);
1929 1933
1930 1934 /* If we're resetting the PHY, then we want to notify loss of link */
1931 1935 notify = (mh->m_link != LINK_STATE_DOWN);
1932 1936 mh->m_link = LINK_STATE_DOWN;
1933 1937 ph->phy_link = LINK_STATE_DOWN;
1934 1938 ph->phy_speed = 0;
1935 1939 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1936 1940
1937 1941 if (ph->phy_reset(ph) != DDI_SUCCESS) {
1938 1942 _mii_error(mh, MII_ERESET);
1939 1943 return (DDI_FAILURE);
1940 1944 }
1941 1945
1942 1946 /* Perform optional mac layer reset. */
1943 1947 if (mh->m_ops.mii_reset != NULL) {
1944 1948 mh->m_ops.mii_reset(mh->m_private);
1945 1949 }
1946 1950
1947 1951 /* Perform optional mac layer notification. */
1948 1952 if (notify) {
1949 1953 _mii_notify(mh);
1950 1954 }
1951 1955 return (DDI_SUCCESS);
1952 1956 }
1953 1957
1954 1958 int
1955 1959 _mii_loopback(mii_handle_t mh)
1956 1960 {
1957 1961 phy_handle_t *ph;
1958 1962
1959 1963 ASSERT(mutex_owned(&mh->m_lock));
1960 1964
1961 1965 ph = mh->m_phy;
1962 1966
1963 1967 if (_mii_reset(mh) != DDI_SUCCESS) {
1964 1968 return (DDI_FAILURE);
1965 1969 }
1966 1970 if (ph->phy_loopback == PHY_LB_NONE) {
1967 1971 mh->m_tstate = MII_STATE_START;
1968 1972 return (DDI_SUCCESS);
1969 1973 }
1970 1974 if (ph->phy_loop(ph) != DDI_SUCCESS) {
1971 1975 _mii_error(mh, MII_ELOOP);
1972 1976 return (DDI_FAILURE);
1973 1977 }
1974 1978
1975 1979 /* Just force loopback to link up. */
1976 1980 mh->m_link = ph->phy_link = LINK_STATE_UP;
1977 1981 _mii_notify(mh);
1978 1982
1979 1983 return (DDI_SUCCESS);
1980 1984 }
1981 1985
1982 1986 int
1983 1987 _mii_start(mii_handle_t mh)
1984 1988 {
1985 1989 phy_handle_t *ph;
1986 1990
1987 1991 ph = mh->m_phy;
1988 1992
1989 1993 ASSERT(mutex_owned(&mh->m_lock));
1990 1994 ASSERT(ph->phy_present);
1991 1995 ASSERT(ph->phy_loopback == PHY_LB_NONE);
1992 1996
1993 1997 if (ph->phy_start(ph) != DDI_SUCCESS) {
1994 1998 _mii_error(mh, MII_ESTART);
1995 1999 return (DDI_FAILURE);
1996 2000 }
1997 2001 /* clear the error state since we got a good startup! */
1998 2002 mh->m_error = MII_EOK;
1999 2003 return (DDI_SUCCESS);
2000 2004 }
2001 2005
2002 2006 int
2003 2007 _mii_check(mii_handle_t mh)
2004 2008 {
2005 2009 link_state_t olink;
2006 2010 int ospeed;
2007 2011 link_duplex_t oduplex;
2008 2012 link_flowctrl_t ofctrl;
2009 2013 phy_handle_t *ph;
2010 2014
2011 2015 ph = mh->m_phy;
2012 2016
2013 2017 olink = mh->m_link;
2014 2018 ospeed = ph->phy_speed;
2015 2019 oduplex = ph->phy_duplex;
2016 2020 ofctrl = ph->phy_flowctrl;
2017 2021
2018 2022 ASSERT(ph->phy_present);
2019 2023
2020 2024 if (ph->phy_check(ph) == DDI_FAILURE) {
2021 2025 _mii_error(mh, MII_ECHECK);
2022 2026 mh->m_link = LINK_STATE_UNKNOWN;
2023 2027 _mii_notify(mh);
2024 2028 return (DDI_FAILURE);
2025 2029 }
2026 2030
2027 2031 mh->m_link = ph->phy_link;
2028 2032
2029 2033 /* if anything changed, notify! */
2030 2034 if ((mh->m_link != olink) ||
2031 2035 (ph->phy_speed != ospeed) ||
2032 2036 (ph->phy_duplex != oduplex) ||
2033 2037 (ph->phy_flowctrl != ofctrl)) {
2034 2038 _mii_notify(mh);
2035 2039 }
2036 2040
2037 2041 return (DDI_SUCCESS);
2038 2042 }
2039 2043
2040 2044 void
2041 2045 _mii_task(void *_mh)
2042 2046 {
2043 2047 mii_handle_t mh = _mh;
2044 2048 phy_handle_t *ph;
2045 2049 clock_t wait;
2046 2050 clock_t downtime;
2047 2051
2048 2052 mutex_enter(&mh->m_lock);
2049 2053
2050 2054 for (;;) {
2051 2055
2052 2056 /* If detaching, exit the thread. */
2053 2057 if (!mh->m_started) {
2054 2058 break;
2055 2059 }
2056 2060
2057 2061 ph = mh->m_phy;
2058 2062
2059 2063 /*
2060 2064 * If we're suspended or otherwise not supposed to be
2061 2065 * monitoring the link, just go back to sleep.
2062 2066 *
2063 2067 * Theoretically we could power down the PHY, but we
2064 2068 * don't bother. (The link might be used for
2065 2069 * wake-on-lan!) Another option would be to reduce
2066 2070 * power on the PHY if both it and the link partner
2067 2071 * support 10 Mbps mode.
2068 2072 */
2069 2073 if (mh->m_suspending) {
2070 2074 mh->m_suspended = B_TRUE;
2071 2075 cv_broadcast(&mh->m_cv);
2072 2076 }
2073 2077 if (mh->m_suspended) {
2074 2078 mh->m_suspending = B_FALSE;
2075 2079 cv_wait(&mh->m_cv, &mh->m_lock);
2076 2080 continue;
2077 2081 }
2078 2082
2079 2083 switch (mh->m_tstate) {
2080 2084 case MII_STATE_PROBE:
2081 2085 _mii_probe(mh);
2082 2086 ph = mh->m_phy;
2083 2087 if (!ph->phy_present) {
2084 2088 /*
2085 2089 * If no PHY is found, wait a bit before
2086 2090 * trying the probe again. 10 seconds ought
2087 2091 * to be enough.
2088 2092 */
2089 2093 wait = 10 * MII_SECOND;
2090 2094 } else {
2091 2095 wait = 0;
2092 2096 }
2093 2097 break;
2094 2098
2095 2099 case MII_STATE_RESET:
2096 2100 if (_mii_reset(mh) == DDI_SUCCESS) {
2097 2101 mh->m_tstate = MII_STATE_START;
2098 2102 wait = 0;
2099 2103 } else {
2100 2104 /*
2101 2105 * If an error occurred, wait a bit and
2102 2106 * try again later.
2103 2107 */
2104 2108 wait = 10 * MII_SECOND;
2105 2109 }
2106 2110 break;
2107 2111
2108 2112 case MII_STATE_START:
2109 2113 /*
2110 2114 * If an error occurs, we're going to go back to
2111 2115 * probe or reset state. Otherwise we go to run
2112 2116 * state. In all cases we want to wait 1 second
2113 2117 * before doing anything else - either for link to
2114 2118 * settle, or to give other code a chance to run
2115 2119 * while we reset.
2116 2120 */
2117 2121 if (_mii_start(mh) == DDI_SUCCESS) {
2118 2122 /* reset watchdog to latest */
2119 2123 downtime = ddi_get_lbolt();
2120 2124 mh->m_tstate = MII_STATE_RUN;
2121 2125 } else {
2122 2126 mh->m_tstate = MII_STATE_PROBE;
2123 2127 }
2124 2128 wait = 0;
2125 2129 break;
2126 2130
2127 2131 case MII_STATE_LOOPBACK:
2128 2132 /*
2129 2133 * In loopback mode we don't check anything,
2130 2134 * and just wait for some condition to change.
2131 2135 */
2132 2136 wait = (clock_t)-1;
2133 2137 break;
2134 2138
2135 2139 case MII_STATE_RUN:
2136 2140 default:
2137 2141 if (_mii_check(mh) == DDI_FAILURE) {
2138 2142 /*
2139 2143 * On error (PHY removed?), wait a
2140 2144 * short bit before reprobing or
2141 2145 * resetting.
2142 2146 */
2143 2147 wait = MII_SECOND;
2144 2148 mh->m_tstate = MII_STATE_PROBE;
2145 2149
2146 2150 } else if (mh->m_link == LINK_STATE_UP) {
2147 2151 /* got goood link, so reset the watchdog */
2148 2152 downtime = ddi_get_lbolt();
2149 2153 /* rescan again in a second */
2150 2154 wait = MII_SECOND;
2151 2155
2152 2156 } else if ((ddi_get_lbolt() - downtime) >
2153 2157 (drv_usectohz(MII_SECOND * 10))) {
2154 2158
2155 2159 /*
2156 2160 * If we were down for 10 seconds,
2157 2161 * hard reset the PHY.
2158 2162 */
2159 2163 mh->m_tstate = MII_STATE_RESET;
2160 2164 wait = 0;
2161 2165
2162 2166 } else {
2163 2167 /*
2164 2168 * Otherwise, if we are still down,
2165 2169 * rescan the link much more
2166 2170 * frequently. We might be trying to
2167 2171 * autonegotiate.
2168 2172 */
2169 2173 wait = MII_SECOND / 4;
2170 2174 }
2171 2175 break;
2172 2176 }
2173 2177
2174 2178 switch (wait) {
2175 2179 case 0:
2176 2180 break;
2177 2181
2178 2182 case (clock_t)-1:
2179 2183 cv_wait(&mh->m_cv, &mh->m_lock);
2180 2184 break;
2181 2185
2182 2186 default:
2183 2187 (void) cv_reltimedwait(&mh->m_cv, &mh->m_lock,
2184 2188 drv_usectohz(wait), TR_CLOCK_TICK);
2185 2189 }
2186 2190 }
2187 2191
2188 2192 mutex_exit(&mh->m_lock);
2189 2193 }
↓ open down ↓ |
657 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX