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