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