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