miiLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:68k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* miiLib.c - Media Independent Interface library */
  2.  
  3. /* Copyright 1989-2002 Wind River Systems, Inc. */
  4. #include "copyright_wrs.h"
  5. /*
  6. modification history
  7. --------------------
  8. 01p,13may02,rcs set the phyAddr before calling pPhyOptRegsRtn also created
  9.                 miiPhyOptFuncMultiSet() to facilitate multiple types of devices
  10.                 spr# 76711
  11. 01o,14jun01,rcs protected calls to new PHY_INFO fields with test for 
  12.                 MII_PHY_GMII_TYPE (SPR# 68502)  
  13. 01n,23feb01,jln add basic GMII support for 1000T auto-negotiation capability,
  14.                 restored call to miiLibInit (). (SPR# 68502)
  15. 01m,12dec00,rcs removed global variables miiValue and miiFunc[]
  16. 01l,12dec00,rcs fix coding error (SPR# 62972)  
  17. 01k,25oct00,ham doc: cleanup for vxWorks AE 1.0.
  18. 01j,19sep00,rcs in miiBasicCheck() changed MII_SYS_DELAY argument  
  19.                 and ix increment to sysClkRateGet(). (SPR# 33991)
  20. 01i,10jun00,dat restored funcBindP.h
  21. 01h,06may00,jgn SPR 31705, fixed wdog use, fixed link status change monitoring,
  22.                 added more debug messages
  23. 01g,05jan00,stv removed private/funcBindP.h (SPR# 29875).
  24. 01f,23nov99,cn  removed call to miiLibInit (), to make miiLib a component 
  25.                 (SPR #29542).
  26. 01e,28oct99,cn  added miiLibInit (), miiLibUnInit (), miiPhyUnInit (),
  27.                 miiPhyBusScan (), miiPhyMonitorStart (), miiPhyMonitor (). 
  28.                 Also updated documentation.
  29. 01d,28sep99,cn  changed miiProbe to better detect PHYs.
  30. 01c,13sep99,cn  fixed SPR# 28305. Also added show routines.
  31. 01b,16jun99,cn  implemented changes after code review.
  32. 01a,16mar99,cn  written from motFecEnd.c, 01c.
  33. */
  34. /*
  35. DESCRIPTION
  36. This module implements a Media Independent Interface (MII) library. 
  37. The MII is an inexpensive and easy-to-implement interconnection between
  38. the Carrier Sense Multiple Access with Collision Detection (CSMA/CD)
  39. media access controllers and the Physical Layer Entities (PHYs).
  40. The purpose of this library is to provide Ethernet drivers in VxWorks
  41. with a standardized, MII-compliant, easy-to-use interface to various PHYs.
  42. In other words, using the services of this library, network drivers
  43. will be able to scan the existing PHYs, run diagnostics, electrically
  44. isolate a subset of them, negotiate their technology abilities with other
  45. link-partners on the network, and ultimately initialize and configure a
  46. specific PHY in a proper, MII-compliant fashion.
  47. In order to initialize and configure a PHY, its MII management interface 
  48. has to be used. This is made up of two lines: management data clock (MDC) 
  49. and management data input/output (MDIO). The former provides the timing 
  50. reference for transfer of information on the MDIO signal.  The latter is 
  51. used to transfer control and status information between the PHY and the 
  52. MAC controller. For this transfer to be successful, the information itself
  53. has to be encoded into a frame format, and both the MDIO and MDC signals have
  54. to comply with certain requirements as described in the 802.3u IEEE Standard.
  55. Since no assumption can be made as to the specific MAC-to-MII
  56. interface, this library expects the driver's writer to provide it with 
  57. specialized read and write routines to access that interface. See EXTERNAL 
  58. SUPPORT REQUIREMENTS below.
  59. miiPhyUnInit (), miiLibInit (), miiLibUnInit (), miiPhyOptFuncSet ().
  60.     STATUS     miiLibInit (void);
  61. .CE
  62. .CS
  63.     STATUS     miiLibUnInit (void);
  64. EXTERNAL SUPPORT REQUIREMENTS
  65. .IP phyReadRtn ()
  66. .CS
  67.     STATUS     phyReadRtn (DRV_CTRL * pDrvCtrl, UINT8 phyAddr, 
  68.     UINT8 phyReg, UINT16 * value);
  69. .CE
  70. This routine is expected to perform any driver-specific functions required
  71. to read a 16-bit word from the <phyReg> register of the MII-compliant PHY
  72. whose address is specified by <phyAddr>. Reading is performed through the
  73. MII management interface.
  74. .IP phyWriteRtn ()
  75. .CS
  76.     STATUS     phyWriteRtn (DRV_CTRL * pDrvCtrl, UINT8 phyAddr, 
  77.      UINT8 phyReg, UINT16 value);
  78. .CE
  79. This routine is expected to perform any driver-specific functions required
  80. to write a 16-bit word to the <phyReg> register of the MII-compliant PHY
  81. whose address is specified by <phyAddr>. Writing is performed through the
  82. MII management interface.
  83. .IP phyDelayRtn ()
  84. .CS
  85.     STATUS     phyDelayRtn (UINT32 phyDelayParm);
  86. .CE
  87. This routine is expected to cause a limited delay to the calling task,
  88. no matter whether this is an active delay, or an inactive one.
  89. miiPhyInit () calls this routine on several occasions throughout
  90. the code with <phyDelayParm> as parameter. This represents the granularity 
  91. of the delay itself, whereas the field <phyMaxDelay> in PHY_INFO is the
  92. maximum allowed delay, in <phyDelayParm> units. The minimum elapsed time
  93. (<phyMaxDelay> * <phyDelayParm>) must be 5 seconds.
  94. The user should be aware that some of these events may take as long as
  95. 2-3 seconds to be completed, and he should therefore tune this routine
  96. and the parameter <phyMaxDelay> accordingly.
  97. If the related field <phyDelayRtn> in the PHY_INFO structure is initialized 
  98. to NULL, no delay is performed.
  99. .IP phyLinkDownRtn ()
  100. .CS
  101.     STATUS     phyLinkDownRtn (DRV_CTRL *);
  102. .CE
  103. This routine is expected to take any action necessary to re-initialize the
  104. media interface, including possibly stopping and restarting the driver itself.
  105. It is called when a link down event is detected for any active PHY, with the
  106. pointer to the relevant driver control structure as only parameter.
  107. .LP
  108. To use this feature, include the following component:
  109. INCLUDE_MIILIB
  110. SEE ALSO: 
  111. .I "IEEE 802.3.2000 Standard"
  112. INTERNAL
  113. This library contains conditional compilation switch MII_DBG.
  114. If defined, adds debug output routines.  Output is further
  115. selectable at run-time via the miiDbg global variable.
  116. */
  117. #include "vxWorks.h"
  118. #include "errnoLib.h"
  119. #include "stdio.h"
  120. #include "stdlib.h"
  121. #include "iosLib.h"
  122. #include "net/mbuf.h"
  123. #include "logLib.h"
  124. #include "netLib.h"
  125. #include "end.h"
  126. #include "sysLib.h"
  127. #include "taskLib.h"
  128. #include "wdLib.h"
  129. #include "lstLib.h"
  130. #include "miiLib.h"
  131. #include "private/funcBindP.h" /* for logMsg */
  132. /* defines */
  133. /* Driver debug control */
  134. #undef MII_DBG 
  135. /* Driver debug control */
  136. #ifdef MII_DBG
  137. #define MII_DBG_ANY     0xffff
  138. UINT32 miiDbg = 0x0;
  139. PHY_INFO * phyInfoDbg = NULL;
  140. #define MII_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
  141.     do {
  142. if ((miiDbg & FLG) && (_func_logMsg != NULL))
  143.     _func_logMsg ((X0), (int)(X1), (int)(X2),(int)(X3),
  144. (int)(X4),(int)(X5),(int)(X6));   
  145.     } while (0)
  146. #else /* MII_DBG */
  147. #define MII_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
  148. #endif /* MII_DBG */
  149.  
  150. #define   MII_PHY_CHECK_CABLE
  151.       do {
  152.   if (_func_logMsg != NULL)
  153.       _func_logMsg ("miiPhyInit check cable connection n",
  154.   0, 0, 0, 0, 0, 0);
  155.       } while (0)
  156. /*
  157.  * the table below is used to translate user settings
  158.  * into MII-standard values for the control register.
  159.  */
  160.  
  161. LOCAL UINT16 miiDefLookupTbl [] = {
  162.                                   MII_CR_NORM_EN,
  163.                                   MII_CR_FDX,
  164.                                   MII_CR_100,
  165.                                   (MII_CR_100 | MII_CR_FDX),
  166.                                   MII_CR_100,
  167.        MII_CR_RESTART | MII_CR_AUTO_EN
  168.                                   };
  169.  
  170. #define MII_FROM_ANSR_TO_ANAR(statReg, adsReg)
  171.     {
  172.     phyStat &= MII_SR_ABIL_MASK;
  173.     phyStat >>= 6;
  174.     phyAds = phyStat + (phyAds & 0x7000) + (phyAds & MII_ADS_SEL_MASK); 
  175.     }
  176. #define MII_SEM_TAKE(tmout) 
  177.     semTake (miiMutex, (int) (tmout))
  178. #define MII_SEM_GIVE() 
  179.     semGive (miiMutex)
  180. /* globals */
  181. /* locals */
  182. LOCAL SEM_ID miiMutex; /* mutex semaphore */
  183. LOCAL LIST miiList; /* all PHYs in the system */
  184. LOCAL BOOL miiLibInitialized = FALSE; /* have we been initialized? */
  185. LOCAL WDOG_ID   miiWd = NULL; /* monitor watchdog ID */
  186. LOCAL FUNCPTR pPhyOptRegsRtn = NULL;
  187. /* forward function declarations */
  188. LOCAL STATUS miiDiag (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  189. LOCAL STATUS miiPhyIsolate (PHY_INFO * pPhyInfo, UINT8 isoPhyAddr);
  190. LOCAL STATUS miiPhyPwrDown (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  191. LOCAL STATUS miiPhyBestModeSet (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  192. LOCAL STATUS miiPhyDefModeSet (PHY_INFO * pPhyInfo);
  193. LOCAL STATUS miiAutoNegotiate (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  194. LOCAL STATUS miiAutoNegStart (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  195. LOCAL STATUS miiModeForce (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  196. LOCAL STATUS miiDefForce (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  197. LOCAL STATUS miiPhyUpdate (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  198. LOCAL STATUS miiFlagsHandle (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  199. LOCAL STATUS miiProbe (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  200. LOCAL STATUS miiAbilFlagSet (PHY_INFO * pPhyInfo, UINT8 phyAddr);
  201. LOCAL STATUS miiPhyMonitor (void);
  202. LOCAL STATUS miiPhyListAdd (PHY_INFO * pPhyInfo);
  203. LOCAL STATUS miiPhyBusScan (PHY_INFO * pPhyInfo);
  204. LOCAL STATUS miiPhyLinkSet (PHY_INFO * pPhyInfo);
  205. LOCAL STATUS miiPhyMonitorStart (void);
  206. /**************************************************************************
  207. *
  208. * miiPhyInit - initialize and configure the PHY devices
  209. *
  210. * This routine scans, initializes and configures the PHY device described
  211. * in <phyInfo>. Space for <phyInfo> is to be provided by the calling
  212. * task.
  213. *
  214. * This routine is called from the driver's Start routine to
  215. * perform media inialization and configuration. To access the PHY
  216. * device through the MII-management interface, it uses the read and
  217. * write routines which are provided by the driver itself
  218. * in the fields  phyReadRtn(), phyWriteRtn() of the phyInfo structure.
  219. * Before it attempts to use this routine, the driver has to properly 
  220. * initialize some of the fields in the <phyInfo> structure, and optionally
  221. * fill in others, as below:
  222. * .CS
  223. *
  224. *    /@ fill in mandatory fields in phyInfo @/
  225. *    pDrvCtrl->phyInfo->pDrvCtrl = (void *) pDrvCtrl;
  226. *    pDrvCtrl->phyInfo->phyWriteRtn = (FUNCPTR) xxxMiiWrite;
  227. *    pDrvCtrl->phyInfo->phyReadRtn = (FUNCPTR) xxxMiiRead;
  228. *    /@ fill in some optional fields in phyInfo @/
  229. *    pDrvCtrl->phyInfo->phyFlags = 0;
  230. *    pDrvCtrl->phyInfo->phyAddr = (UINT8) MII_PHY_DEF_ADDR;
  231. *    pDrvCtrl->phyInfo->phyDefMode = (UINT8) PHY_10BASE_T;
  232. *    pDrvCtrl->phyInfo->phyAnOrderTbl = (MII_AN_ORDER_TBL *)
  233. *                                        &xxxPhyAnOrderTbl;
  234. *    /@ 
  235. *     @ fill in some more optional fields in phyInfo: the delay stuff
  236. *     @ we want this routine to use our xxxDelay () routine, with
  237. *     @ the constant one as an argument, and the max delay we may
  238. *     @ tolerate is the constant MII_PHY_DEF_DELAY, in xxxDelay units
  239. *     @/
  240. *    pDrvCtrl->phyInfo->phyDelayRtn = (FUNCPTR) xxxDelay;
  241. *    pDrvCtrl->phyInfo->phyMaxDelay = MII_PHY_DEF_DELAY;
  242. *    pDrvCtrl->phyInfo->phyDelayParm = 1;
  243. *
  244. *    /@ 
  245. *     @ fill in some more optional fields in phyInfo: the PHY's callback
  246. *     @ to handle "link down" events. This routine is invoked whenever 
  247. *     @ the link status in the PHY being used is detected to be low.
  248. *     @/
  249. *    pDrvCtrl->phyInfo->phyStatChngRtn = (FUNCPTR) xxxRestart;
  250. *
  251. * .CE
  252. *
  253. * Some of the above fields may be overwritten by this routine, since 
  254. * for instance, the logical address of the PHY actually used may differ
  255. * from the user's initial setting. Likewise, the specific PHY being
  256. * initialized, may not support all the technology abilities the user
  257. * has allowed for its operations.
  258. * This routine first scans for all possible PHY addresses in the range 0-31,
  259. * checking for an MII-compliant PHY, and attempts at running some diagnostics 
  260. * on it. If none is found, ERROR is returned.
  261. *
  262. * Typically PHYs are scanned from address 0, but if the user specifies
  263. * an alternative start PHY address via the parameter phyAddr in the 
  264. * phyInfo structure, PHYs are scanned in order starting 
  265. * with the specified PHY address. In addition, if the flag <MII_ALL_BUS_SCAN> 
  266. * is set, this routine will scan the whole bus even if a valid PHY has 
  267. * already been found, and stores bus topology information. If the flags 
  268. * <MII_PHY_ISO>, <MII_PHY_PWR_DOWN> are set, all of the PHYs found but the
  269. * first will be respectively electrically isolated from the MII interface
  270. * and/or put in low-power mode. These two flags are meaningless in a 
  271. * configuration where only one PHY is present.
  272. *
  273. * The phyAddr parameter is very important from a performance point of view.
  274. * Since the MII management interface, through which the PHY is configured,
  275. * is a very slow one, providing an incorrect or invalid address in this
  276. * field may result in a particularly long boot process.
  277. *
  278. * If the flag <MII_ALL_BUS_SCAN> is not set, this routine will 
  279. * assume that the first PHY found is the only one.
  280. *
  281. * This routine then attempts to bring the link up.
  282. * This routine offers two strategies to select a PHY and establish a
  283. * valid link. The default strategy is to use the standard 802.3 style 
  284. * auto-negotiation, where both link partners negotiate all their 
  285. * technology abilities at the same time, and the highest common 
  286. * denominator ability is chosen. Before the auto-negotiation
  287. * is started, the next-page exchange mechanism is disabled.
  288. *
  289. * If GMII interface is used, users can specify it through userFlags --
  290. * <MII_PHY_GMII_TYPE>.
  291. *
  292. * The user can prevent the PHY from negotiating certain abilities via 
  293. * userFlags -- <MII_PHY_FD>, <MII_PHY_100>, <MII_PHY_HD>, and <MII_PHY_10>. 
  294. * as well as <MII_PHY_1000T_HD> and <MII_PHY_1000T_FD> if GMII is used.
  295. * When <MII_PHY_FD> is not specified, full duplex will not be 
  296. * negotiated; when <MII_PHY_HD> is not specified half duplex 
  297. * will not be negotiated, when <MII_PHY_100> is not specified, 
  298. * 100Mbps ability will not be negotiated; when <MII_PHY_10> is not 
  299. * specified, 10Mbps ability will not be negotiated.
  300. * Also, if GMII is used, when <MII_PHY_1000T_HD> is not specified,
  301. * 1000T with half duplex mode will not be negotiated. Same thing 
  302. * applied to 1000T with full duplex mode via <MII_PHY_1000T_FD>.
  303. * Flow control ability can also be negotiated via user flags --
  304. * <MII_PHY_TX_FLOW_CTRL> and <MII_PHY_RX_FLOW_CTRL>. For symmetric
  305. * PAUSE ability (MII), user can set/clean both flags together. For
  306. * asymmetric PAUSE ability (GMII), user can seperate transmit and receive
  307. * flow control ability. However, user should be aware that flow control
  308. * ability is meaningful only if full duplex mode is used.
  309. *
  310. * When <MII_PHY_TBL> is set in the user flags, the BSP specific 
  311. * table whose address may be provided in the <phyAnOrderTbl>
  312. * field of the <phyInfo> structure, is used to obtain the list, and 
  313. * the order of technology abilities to be negotiated.
  314. * The entries in this table are ordered such that entry 0 is the
  315. * highest priority, entry 1 in next and so on. Entries in this table 
  316. * may be repeated, and multiple technology abilities can
  317. * be OR'd to create a single  entry. If a PHY cannot support a
  318. * ability in an entry, that entry is ignored. 
  319. *
  320. * If no PHY provides a valid link, and if <MII_PHY_DEF_SET> is set in the
  321. * phyFlags field of the PHY_INFO structure, the first PHY that supports 
  322. * the default abilities defined in the <phyDefMode> of the phyInfo structure 
  323. * will be selected, regardless of the link status.
  324. *
  325. * In addition, this routine adds an entry in a linked list of PHY devices
  326. * for each active PHY it found. If the flag <MII_PHY_MONITOR> is set, the 
  327. * link status for the relevant PHY is continually monitored for a link down 
  328. * event. If such event is detected, and if the <phyLinkDownRtn> in the PHY_INFO * structure is a valid function pointer, then the routine it points at is 
  329. * executed in the context of the netTask ().  The parameter MII_MONITOR_DELAY
  330. * may be used to define the period in seconds with which the link status is 
  331. * checked. Its default value is 5.
  332. *
  333. * RETURNS: OK or ERROR if the PHY could not be initialised,
  334. *
  335. */
  336. STATUS miiPhyInit
  337.     (
  338.     PHY_INFO *  pPhyInfo       /* pointer to PHY_INFO structure */
  339.     )
  340.     {
  341.     int retVal; /* convenient holder for return value */
  342.     /* sanity checks */
  343.     if (pPhyInfo == NULL ||
  344. (pPhyInfo->phyReadRtn == NULL) ||
  345. (pPhyInfo->phyWriteRtn == NULL) ||
  346. (pPhyInfo->pDrvCtrl == NULL))
  347. {
  348. MII_LOG (MII_DBG_ANY, ("miiPhyInit... missing params n"),
  349.        0, 0, 0, 0, 0, 0);
  350. return (ERROR);
  351. }
  352.     /* Ensure that pPhyInfo->phyMaxDelay is minimum 5 seconds */
  353.     if (pPhyInfo->phyMaxDelay < (sysClkRateGet() * 5))
  354.         {
  355.         /* Set max delay porportionally */
  356.  
  357.         pPhyInfo->phyMaxDelay = sysClkRateGet() * 5;
  358.         }
  359.     /* initialize the MII library  */
  360.     if (miiLibInit () == ERROR)
  361.         return (ERROR);
  362. #ifdef MII_DBG
  363.     phyInfoDbg = pPhyInfo;
  364. #endif /* MII_DBG */
  365.     /* scan the whole bus */
  366.     if (miiPhyBusScan (pPhyInfo) == ERROR)
  367. return (ERROR);
  368.     /* set the mode for a PHY, return in case of success or fatal error */
  369.     retVal = miiPhyLinkSet (pPhyInfo);
  370.     if (retVal == OK)
  371. return (OK);
  372.     if (errno != S_miiLib_PHY_LINK_DOWN)
  373. return (ERROR);
  374.     /* if we're here, none of the PHYs could be initialized */
  375.     MII_PHY_CHECK_CABLE;
  376.     if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_DEF_SET)))
  377.     return (ERROR);
  378.     /* set the default mode for a PHY, do not check the link */
  379.     return (miiPhyDefModeSet (pPhyInfo));
  380.     } 
  381. /**************************************************************************
  382. *
  383. * miiPhyUnInit - uninitialize a PHY
  384. *
  385. * This routine uninitializes the PHY specified in <pPhyInfo>. It brings it
  386. * in low-power mode, and electrically isolate it from the MII management 
  387. * interface to which it is attached. In addition, it frees resources 
  388. * previously allocated.
  389. *
  390. * RETURNS: OK, ERROR in case of fatal errors.
  391. *
  392. */
  393. STATUS miiPhyUnInit
  394.     (
  395.     PHY_INFO *  pPhyInfo       /* pointer to PHY_INFO structure */
  396.     )
  397.     {
  398.     if (pPhyInfo == NULL)
  399. return (ERROR);
  400.     MII_LOG (MII_DBG_ANY, ("miiPhyUnInit n"),
  401.    0, 0, 0, 0, 0, 0);
  402.     /* this counts also for isolate */
  403.     if (miiProbe (pPhyInfo, pPhyInfo->phyAddr) == ERROR)
  404. return (ERROR);
  405.     if (miiPhyPwrDown (pPhyInfo, pPhyInfo->phyAddr) == ERROR)
  406. return (ERROR);
  407.     MII_PHY_FLAGS_CLEAR (MII_PHY_INIT);
  408.     /* protect it from other MII routines */
  409.     MII_SEM_TAKE (WAIT_FOREVER);
  410.     lstDelete (&miiList, (NODE *) pPhyInfo->pMiiPhyNode);
  411.     /* we're done, release the mutex */
  412.     MII_SEM_GIVE ();
  413.     /* free memory */
  414.     free ((char *) pPhyInfo->pMiiPhyNode);
  415.     free ((char *) pPhyInfo->miiPhyPresent);
  416.     pPhyInfo->pMiiPhyNode = NULL;
  417.     /* stop the monitor if necessary */
  418.     if (miiList.count == 0)
  419. return (wdCancel (miiWd));
  420.     return (OK);
  421.     }
  422. /**************************************************************************
  423. *
  424. * miiProbe - probe the PHY device
  425. *
  426. * This routine probes the PHY device by reading its control register.
  427. * It also checks the PHY can be successfully electrically isolated from its
  428. * MII interface.
  429. *
  430. * RETURNS: OK, ERROR in case of fatal errors.
  431. *
  432. * ERRNO: S_miiLib_PHY_NULL
  433. *
  434. */
  435. LOCAL STATUS miiProbe
  436.     (
  437.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  438.     UINT8 phyAddr /* the PHY being read */
  439.     )
  440.     {
  441.     UINT8 regAddr; /* the PHY's register being read */
  442.     UINT16 data; /* data to be written to the PHY's reg */
  443.     int retVal; /* convenient holder for return value */
  444.     MII_LOG (MII_DBG_ANY, "miiProbe for addr %#x startsn",phyAddr,0,0,0,0,0);
  445.     regAddr = MII_CTRL_REG;
  446.     MII_READ (phyAddr, regAddr, &data, retVal);
  447.     if (retVal == ERROR)
  448. return (ERROR);
  449.     /* check the reserved bits, and the ability to isolate the PHY */
  450.     MII_LOG (MII_DBG_ANY, "miiProbe checking addr %#xn",phyAddr,0,0,0,0,0);
  451.     if (((data & MII_CR_RES_MASK) > 0x0) ||
  452.         ((miiPhyIsolate (pPhyInfo, phyAddr) != OK)))
  453.         {
  454. errnoSet (S_miiLib_PHY_NULL); 
  455. return (ERROR);
  456. }
  457.     MII_LOG (MII_DBG_ANY, ("miiProbe... endsn"),
  458.    0, 0, 0, 0, 0, 0);
  459.     return (OK);
  460.     }
  461. /*******************************************************************************
  462. *
  463. * miiDiag - run some diagnostics
  464. *
  465. * This routine runs some diagnostics on the PHY whose address is 
  466. * specified in the parameter <phyAddr>.
  467. *
  468. * RETURNS: OK or ERROR.
  469. */
  470. LOCAL STATUS miiDiag
  471.     (
  472.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  473.     UINT8 phyAddr /* address of a PHY */
  474.     )
  475.     {
  476.     UINT16 data; /* data to be written to the control reg */
  477.     UINT8 regAddr; /* PHY register */
  478.     UINT16 ix = 0; /*  a counter */
  479.     int retVal; /* convenient holder for return value */
  480.     /* reset the PHY */
  481.     regAddr = MII_CTRL_REG;
  482.     data = MII_CR_RESET;
  483.     MII_WRITE (phyAddr, regAddr, data, retVal);
  484.     if (retVal != OK)
  485. return (ERROR);
  486.     while (ix++ < pPhyInfo->phyMaxDelay)
  487. {
  488. MII_SYS_DELAY (pPhyInfo->phyDelayParm);
  489. MII_READ (phyAddr, regAddr, &data, retVal);
  490. if (retVal == ERROR)
  491.     return (ERROR);
  492. if (!(data & MII_CR_RESET))
  493.     break;
  494. }
  495.     if (ix >= pPhyInfo->phyMaxDelay)
  496. {
  497. MII_LOG (MII_DBG_ANY, ("miiDiag reset failn"),
  498.        0, 0, 0, 0, 0, 0);
  499. return (ERROR);
  500. }
  501.     /* re-enable the chip */
  502.     data = MII_CR_NORM_EN;
  503.     MII_WRITE (phyAddr, regAddr, data, retVal);
  504.     if (retVal != OK)
  505. {
  506. MII_LOG (MII_DBG_ANY, ("miiDiag write failn"),
  507.        0, 0, 0, 0, 0, 0);
  508. return (ERROR);
  509. }
  510.     /* check isolate bit is deasserted */
  511.     ix = 0;
  512.     while (ix++ < pPhyInfo->phyMaxDelay)
  513. {
  514. MII_SYS_DELAY (pPhyInfo->phyDelayParm);
  515. MII_READ (phyAddr, regAddr, &data, retVal);
  516. if (retVal != OK)
  517.     {
  518.     MII_LOG (MII_DBG_ANY, ("miiDiag read failn"),
  519.    0, 0, 0, 0, 0, 0);
  520.     return (ERROR);
  521.     }
  522. if (!(data & MII_CR_ISOLATE))
  523.     break;
  524. }
  525.     if (ix >= pPhyInfo->phyMaxDelay)
  526. {
  527. MII_LOG (MII_DBG_ANY, ("miiDiag de-isolate failn"),
  528.        0, 0, 0, 0, 0, 0);
  529. return (ERROR);
  530. }
  531.     MII_LOG (MII_DBG_ANY, ("miiDiag... endsn"),
  532.    0, 0, 0, 0, 0, 0);
  533.     return (OK);
  534.     }
  535. /*******************************************************************************
  536. *
  537. * miiPhyIsolate - isolate the PHY device
  538. *
  539. * This routine isolates the PHY device whose address is specified in 
  540. * the parameter <isoPhyAddr>.
  541. *
  542. * RETURNS: OK or ERROR.
  543. */
  544. LOCAL STATUS miiPhyIsolate
  545.     (
  546.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  547.     UINT8 isoPhyAddr /* address of a PHY to be isolated */
  548.     )
  549.     {
  550.     UINT8 regAddr; /* PHY register */
  551.     UINT16 ix = 0; /*  a counter */
  552.     UINT16 data; /* data to be written to the control reg */
  553.     int retVal; /* convenient holder for return value */
  554.     if (isoPhyAddr == MII_PHY_NULL)
  555. return (OK);
  556.     data = MII_CR_ISOLATE;
  557.     regAddr = MII_CTRL_REG;
  558.     MII_WRITE (isoPhyAddr, regAddr, data, retVal);
  559.     if (retVal != OK)
  560. return (ERROR);
  561.     /* check isolate bit is asserted */
  562.     while (ix++ < pPhyInfo->phyMaxDelay)
  563. {
  564. MII_SYS_DELAY (pPhyInfo->phyDelayParm);
  565. MII_READ (isoPhyAddr, regAddr, &data, retVal);
  566. if (retVal != OK)
  567.     return (ERROR);
  568. if ((data & MII_CR_ISOLATE))
  569.     break;
  570. }
  571.     if (ix >= pPhyInfo->phyMaxDelay)
  572. {
  573. MII_LOG (MII_DBG_ANY, ("miiPhyIsolate failn"),
  574.        0, 0, 0, 0, 0, 0);
  575. return (ERROR);
  576. }
  577.     MII_LOG (MII_DBG_ANY, ("miiPhyIsolate... endsn"),
  578.    0, 0, 0, 0, 0, 0);
  579.     return (OK);
  580.     }
  581. /*******************************************************************************
  582. *
  583. * miiPhyPwrDown - put the PHY in power down mode
  584. *
  585. * This routine puts the PHY specified in <phyAddr> in power down mode.
  586. *
  587. * RETURNS: OK or ERROR.
  588. */
  589. LOCAL STATUS miiPhyPwrDown
  590.     (
  591.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  592.     UINT8  phyAddr /* phy to be put in power down mode */
  593.     )
  594.     {
  595.     int retVal; /* convenient holder for return value */
  596.     UINT8 regAddr; /* PHY register */
  597.     UINT16 data; /* data to be written to the control reg */
  598.     if (phyAddr == MII_PHY_NULL)
  599. return (OK);
  600.     data = MII_CR_POWER_DOWN;
  601.     regAddr = MII_CTRL_REG;
  602.     MII_WRITE (phyAddr, regAddr, data, retVal);
  603.     return (retVal);
  604.     }
  605. /*******************************************************************************
  606. *
  607. * miiPhyBusScan - scan the MII bus
  608. *
  609. * This routine scans the MII bus, in the search for an MII-compliant PHY.
  610. * If it succeeds, and if the flag MII_ALL_BUS_SCAN is not set, it returns
  611. * OK. Otherwise, it keeps scanning the bus and storing relevant information
  612. * in the miiPhyPresent field of the structure referenced to by <pPhyInfo>.
  613. * Other PHYs than the first one found, will be put in
  614. * low-power mode and electrically isolated from the MII interface.
  615. *
  616. * SEE ALSO: miiAutoNegotiate (), miiModeForce ().
  617. * RETURNS: OK or ERROR.
  618. *
  619. */
  620. LOCAL STATUS miiPhyBusScan
  621.     (
  622.     PHY_INFO *  pPhyInfo        /* pointer to PHY_INFO structure */
  623.     )
  624.     {
  625.     UINT16 ix; /* a counter */
  626.     int retVal; /* holder for return value */
  627.     UINT8 phyAddr; /* address of a PHY */
  628.     if ((pPhyInfo->miiPhyPresent = (MII_PHY_BUS *) 
  629.    calloc (1, sizeof (MII_PHY_BUS)))
  630. == NULL)
  631. return (ERROR);
  632.     /* 
  633.      * there may be as many as 32 PHYs, with distinct logical addresses
  634.      * Start with the one the user suggested and, in case of failure in 
  635.      * probing the device, scan the whole range.
  636.      */
  637.     for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
  638. {
  639. phyAddr = (ix + pPhyInfo->phyAddr) % MII_MAX_PHY_NUM;
  640. MII_LOG (MII_DBG_ANY,
  641.       ("miiPhyBusScan trying phyAddr=0x%x phyInfo=0x%x n"),
  642.       phyAddr, pPhyInfo, 0, 0, 0, 0);
  643. /* check the PHY is there */
  644. retVal = miiProbe (pPhyInfo, phyAddr);
  645. /* deal with the error condition if possible */
  646. if (retVal == ERROR) 
  647.     {
  648.     if (errno != S_miiLib_PHY_NULL) 
  649. return (ERROR);
  650.     else
  651. {
  652. if (ix == (MII_MAX_PHY_NUM - 1))
  653.     return (ERROR);
  654. /* no PHY was found with this address: keep scanning */
  655. MII_LOG (MII_DBG_ANY, "No PHY at address %#xn", phyAddr,
  656.  0,0,0,0,0);
  657. errno = 0;
  658. continue;
  659. }
  660.     }
  661. else
  662.     {
  663.     /* run some diagnostics */
  664.     if (miiDiag (pPhyInfo, phyAddr) != OK)
  665. {
  666. MII_LOG (MII_DBG_ANY, "miiDiag failed for addr %#xn",
  667.  phyAddr,0,0,0,0,0);
  668. return (ERROR);
  669. }
  670.     /* record this information */
  671.     * ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) = TRUE;
  672.     /* should we scan the whole bus? */
  673.     if (!(MII_PHY_FLAGS_ARE_SET (MII_ALL_BUS_SCAN))) 
  674. {
  675. MII_LOG (MII_DBG_ANY, "Not scanning whole busn", 0,0,0,0,0,0);
  676. return (OK);
  677. }
  678.     MII_LOG (MII_DBG_ANY, ("miiPhyBusScan phyAddr=0x%x n"),
  679.    phyAddr, 0, 0, 0, 0, 0);
  680.     }
  681. }
  682.     /* set optional features for the other PHYs */
  683.     for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
  684. {
  685. /* check the PHY is there */
  686. if (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) == TRUE)
  687.     {
  688.     /* set it in power down mode */
  689.     if (MII_PHY_FLAGS_ARE_SET (MII_PHY_PWR_DOWN))
  690. {
  691. MII_LOG (MII_DBG_ANY, "Powering down PHY %#xn", ix,
  692.  0,0,0,0,0);
  693. if (miiPhyPwrDown (pPhyInfo, ix) == ERROR)
  694.     return (ERROR);
  695. }
  696.     /* eletrically isolate it from the MII interface */
  697.     if (MII_PHY_FLAGS_ARE_SET (MII_PHY_ISO))
  698. {
  699. MII_LOG (MII_DBG_ANY, "miiPhyBusScan isolating phyAddr=0x%xn",
  700.        ix, 0, 0, 0, 0, 0);
  701. if (miiPhyIsolate (pPhyInfo, ix) == ERROR)
  702.     return (ERROR);
  703. }
  704.     }
  705. }
  706.     return (OK);
  707.     }
  708. /*******************************************************************************
  709. *
  710. * miiPhyBestModeSet - set the best operating mode for a PHY
  711. *
  712. * This routine sets the best operating mode for a PHY looking at the 
  713. * parameters in <pPhyInfo>. It may call miiAutoNegotiate (), and/or 
  714. * miiModeForce (). Upon success, it stores the <phyAddr> in the relevant
  715. * field of the structure pointed to by <pPhyInfo>.
  716. *
  717. * SEE ALSO: miiAutoNegotiate (), miiModeForce ().
  718. * RETURNS: OK or ERROR.
  719. *
  720. */
  721. LOCAL STATUS miiPhyBestModeSet
  722.     (
  723.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  724.     UINT8  phyAddr         /* PHY's address */
  725.     )
  726.     {
  727.     /* 
  728.      * start the auto-negotiation process,
  729.      * unless the user dictated the contrary. 
  730.      */
  731.     if (pPhyInfo->phyFlags & MII_PHY_AUTO)
  732. if (miiAutoNegotiate (pPhyInfo, phyAddr) == OK)
  733.     {
  734.             if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  735.                 {
  736.                 pPhyInfo->phyLinkMethod = MII_PHY_LINK_AUTO;
  737.         }
  738.             goto miiPhyOk;
  739.             }
  740.     /* 
  741.      * the auto-negotiation process did not succeed 
  742.      * in establishing a valid link: try to do it
  743.      * manually, enabling as many high priority abilities
  744.      * as possible.
  745.      */
  746.     if (miiModeForce (pPhyInfo, phyAddr) == OK)
  747.         {
  748.         if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  749.             {
  750.             pPhyInfo->phyLinkMethod = MII_PHY_LINK_FORCE;
  751.             }
  752.          goto miiPhyOk;
  753.          }
  754.     return (ERROR);
  755. miiPhyOk:
  756.     /* store this PHY and return */
  757.     pPhyInfo->phyAddr = phyAddr;
  758.     MII_PHY_FLAGS_SET (MII_PHY_INIT);
  759.     return (OK);
  760.     }
  761. /*******************************************************************************
  762. *
  763. * miiPhyLinkSet - set the link for a PHY
  764. *
  765. * This routine sets the link for the PHY pointed to by <pPhyInfo>. To do
  766. * so, it calls miiPhyBestModeSet (). Upon success it returns OK.
  767. * Otherwise, it checks whether other PHYs are on the bus, and attempts at
  768. * establishing a link for them starting from the first and scanning the 
  769. * whole range. In case of failure, ERROR is returned.
  770. *
  771. * SEE ALSO: miiPhyBestModeSet ().
  772. * RETURNS: OK or ERROR.
  773. *
  774. * ERRNO: S_miiLib_PHY_LINK_DOWN
  775. *
  776. */
  777. LOCAL STATUS miiPhyLinkSet
  778.     (
  779.     PHY_INFO *  pPhyInfo        /* pointer to PHY_INFO structure */
  780.     )
  781.     {
  782.     UINT16 ix; /* a counter */
  783.     UINT8 phyAddr; /* address of a PHY */
  784.     UINT32 phyFlags; /* default PHY's flags */
  785.     /* store the default phy's flags */
  786.     phyFlags = pPhyInfo->phyFlags;
  787.     for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
  788. {
  789. phyAddr = (ix + pPhyInfo->phyAddr) % MII_MAX_PHY_NUM;
  790. MII_LOG (MII_DBG_ANY, ("miiPhyLinkSet phyAddr=0x%x n"),
  791.        phyAddr, 0, 0, 0, 0, 0);
  792. if (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) == FALSE)
  793.     continue;
  794. /* add this PHY to the linked list */
  795. if (miiPhyListAdd (pPhyInfo) == ERROR)
  796.     return (ERROR);
  797. MII_LOG (MII_DBG_ANY, ("miiPhyLinkSet phyAddr=0x%x pres=0x%x n"),
  798.        phyAddr, 
  799.        (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr)),
  800.        0, 0, 0, 0);
  801. /* find out the PHY's abilities and set flags accordingly */
  802. if (miiAbilFlagSet (pPhyInfo, phyAddr) != OK)
  803.     return (ERROR);
  804.         /* we need this phyAddr before we call pPhyOptRegsRtn */
  805.         pPhyInfo->phyAddr = phyAddr;
  806. /* 
  807.  * check with the BSP if we need to do something else before
  808.  * we try and establish the link 
  809.  */
  810.         if (pPhyInfo->pPhyOptRegsRtn != NULL)
  811.             (* pPhyInfo->pPhyOptRegsRtn) (pPhyInfo);
  812.         else
  813.     if (pPhyOptRegsRtn != NULL)
  814.         (* pPhyOptRegsRtn) (pPhyInfo);
  815.         /* initialize phyLinkMethod */
  816.         if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  817.             {
  818.             pPhyInfo->phyLinkMethod = MII_PHY_LINK_UNKNOWN;
  819.             } 
  820. /* establist the link */
  821. if (miiPhyBestModeSet (pPhyInfo, phyAddr) == OK)
  822.     {
  823.     return (OK);
  824.     }
  825. /* restore the default flags, miiAbilFlagSet may have changed them */
  826. pPhyInfo->phyFlags = phyFlags;
  827. }
  828.     /* set errno, since we did not establish a valid link */
  829.     errnoSet (S_miiLib_PHY_LINK_DOWN);
  830.     return (ERROR);
  831.     }
  832. /*******************************************************************************
  833. *
  834. * miiPhyDefModeSet - set the default operating mode for a PHY
  835. *
  836. * This routine sets the default operating mode for a PHY looking at the 
  837. * parameters in <pPhyInfo>. It calls miiDefForce () for each PHY found.
  838. *
  839. * SEE ALSO: miiDefForce ().
  840. * RETURNS: OK or ERROR.
  841. *
  842. */
  843. LOCAL STATUS miiPhyDefModeSet
  844.     (
  845.     PHY_INFO *  pPhyInfo        /* pointer to PHY_INFO structure */
  846.     )
  847.     {
  848.     UINT16 ix; /* a counter */
  849.     int retVal; /* holder for return value */
  850.     UINT8 phyAddr; /* address of a PHY */
  851.     /* try to establish a default operating mode, do not check the link! */
  852.     for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
  853. {
  854. phyAddr = (ix + pPhyInfo->phyAddr) % MII_MAX_PHY_NUM;
  855. /* check the PHY is there */
  856. if (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) == FALSE)
  857.     continue;
  858. /* 
  859.  * Force default parameters: field phyDefMode in the PHY info 
  860.  * structure. Return OK even if the link is not up.
  861.  */
  862. retVal = miiDefForce (pPhyInfo, phyAddr);
  863. if (retVal == OK) 
  864.     {
  865.     /* store this PHY and return */
  866.     pPhyInfo->phyAddr = phyAddr;
  867.     MII_PHY_FLAGS_SET (MII_PHY_INIT);
  868.     return (OK);
  869.     }
  870. /* if the PHY does not have the default abilities... */
  871. if (errno == S_miiLib_PHY_NO_ABLE)
  872.     {
  873.     if (ix == (MII_MAX_PHY_NUM - 1))
  874. return (ERROR);
  875.     errno = 0;
  876.     continue;
  877.     }
  878. }
  879.     return (ERROR);
  880.     }
  881. /*******************************************************************************
  882. *
  883. * miiAutoNegotiate - run the auto-negotiation process
  884. *
  885. * This routine runs the auto-negotiation process for the PHY whose
  886. * address is specified in the parameter <phyAddr>, without enabling the 
  887. * next page function. It also calls miiAnCheck() to ensure
  888. * a valid link has been established.
  889. *
  890. * RETURNS: OK or ERROR.
  891. */
  892. LOCAL STATUS miiAutoNegotiate
  893.     (
  894.     PHY_INFO *  pPhyInfo,  /* pointer to PHY_INFO structure */
  895.     UINT8 phyAddr        /* address of a PHY */
  896.     )
  897.     {
  898.     UINT8 regAddr;       /* PHY register */
  899.     UINT16 phyAds;        /* holder for the PHY ads register value */
  900.     UINT16 status;        /* PHY auto-negotiation status */
  901.     UINT16 ix;            /* a counter */
  902.     int retVal;        /* holder for return value */
  903.     UINT16 phyStat;       /* PHY auto-negotiation status */
  904.     UINT16  phyMstSlaCtrl; /* PHY Mater-slave Control */
  905.     UINT16  phyExtStat;    /* PHY extented status */
  906.     /* save phyFlags for phyAutoNegotiateFlags */
  907.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  908.         {
  909.         pPhyInfo->phyAutoNegotiateFlags = pPhyInfo->phyFlags; 
  910.         }
  911.     /* Read ANER to clear status from previous operations */
  912.   
  913.     regAddr = MII_AN_EXP_REG;
  914.     MII_READ (phyAddr, regAddr, &status, retVal);
  915.     if (retVal != OK)
  916. return (ERROR);
  917.     /* 
  918.      * copy the abilities in ANSR to ANAR. This is necessary because
  919.      * according to the 802.3 standard, the technology ability
  920.      * field in ANAR "is set based on the value in the MII status
  921.      * register or equivalent". What does "equivalent" mean?
  922.      */
  923.  
  924.     regAddr = MII_AN_ADS_REG;
  925.     MII_READ (phyAddr, regAddr, &phyAds, retVal);
  926.     if (retVal != OK)
  927. return (ERROR);
  928.     MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%x expStat=0x%x n"),
  929.    phyAds, status, 0, 0, 0, 0);
  930.     regAddr = MII_STAT_REG;
  931.     MII_READ (phyAddr, regAddr, &phyStat, retVal);
  932.     if (retVal != OK)
  933.         return (ERROR);
  934.  
  935.     MII_FROM_ANSR_TO_ANAR (phyStat, phyAds);
  936.     /* also disable the next page function */
  937.     phyAds &= (~MII_NP_NP);
  938.     MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate write to ANAR=0x%xn"),
  939.                            phyAds, 0, 0, 0, 0, 0);
  940.  
  941.     /* configure flow control */
  942.     /* MII defines symmetric PAUSE ability */ 
  943.     if ((MII_PHY_FLAGS_ARE_SET (MII_PHY_TX_FLOW_CTRL)) &&
  944.                 (MII_PHY_FLAGS_ARE_SET (MII_PHY_RX_FLOW_CTRL)))
  945.         phyAds |= MII_ANAR_PAUSE;
  946.     else
  947.         phyAds &= ~MII_ANAR_PAUSE;
  948.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  949.         {
  950.         /* GMII also defines asymmetric PAUSE ability */
  951.         if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_TX_FLOW_CTRL)) &&
  952.                 !(MII_PHY_FLAGS_ARE_SET (MII_PHY_RX_FLOW_CTRL)))
  953.              {
  954.              /* not flow control */
  955.              phyAds &= ~MII_ANAR_ASM_PAUSE;
  956.              phyAds &= ~MII_ANAR_PAUSE;
  957.              }
  958.          else if ((MII_PHY_FLAGS_ARE_SET (MII_PHY_TX_FLOW_CTRL)) && 
  959.                     !(MII_PHY_FLAGS_ARE_SET (MII_PHY_RX_FLOW_CTRL)))
  960.              {
  961.              /* TX flow control */
  962.              phyAds |= MII_ANAR_ASM_PAUSE;
  963.              phyAds &= ~MII_ANAR_PAUSE;
  964.              }
  965.          else    
  966.              {
  967.              /* RX flow control */
  968.              phyAds |= MII_ANAR_ASM_PAUSE;
  969.              phyAds |= MII_ANAR_PAUSE;
  970.              }
  971.          }
  972.     /* write ANAR */
  973.     regAddr = MII_AN_ADS_REG;
  974.     MII_WRITE (phyAddr, regAddr, phyAds, retVal);
  975.     if (retVal != OK)
  976. return (ERROR);
  977.  
  978.     /* store the current registers values */
  979.     pPhyInfo->miiRegs.phyAds = phyAds;
  980.     
  981.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  982.         {
  983.         /* get Master-Slave Control (MSC) Register */
  984.         regAddr =  MII_MASSLA_CTRL_REG;
  985.         MII_READ (phyAddr, regAddr, &phyMstSlaCtrl, retVal);
  986.         if (retVal != OK)
  987.             return (ERROR);
  988.         /* get extended status register */
  989.         regAddr = MII_EXT_STAT_REG;
  990.         MII_READ (phyAddr, regAddr, &phyExtStat, retVal);
  991.         if (retVal != OK)
  992.             return (ERROR);
  993.      
  994.         /* set MSC register value based on PHY ability on EXTS */
  995.    
  996.         phyMstSlaCtrl = (phyExtStat & MII_EXT_STAT_1000T_HD) ?
  997.                         (phyMstSlaCtrl | MII_MASSLA_CTRL_1000T_HD) :
  998.                         (phyMstSlaCtrl & ~MII_MASSLA_CTRL_1000T_HD);
  999.         phyMstSlaCtrl = (phyExtStat & MII_EXT_STAT_1000T_FD) ?
  1000.                         (phyMstSlaCtrl | MII_MASSLA_CTRL_1000T_FD) :
  1001.                         (phyMstSlaCtrl & ~MII_MASSLA_CTRL_1000T_FD);                         
  1002.           
  1003.         /* write MSC register value */
  1004.         regAddr = MII_MASSLA_CTRL_REG;
  1005.         MII_WRITE (phyAddr, regAddr, phyMstSlaCtrl, retVal);
  1006.         if (retVal != OK)
  1007.             return (ERROR);
  1008.         /* store the current registers values */
  1009.         pPhyInfo->miiGRegs.phyMSCtrl = phyMstSlaCtrl;
  1010.         }
  1011.     /* 
  1012.      * start the auto-negotiation process, possibly
  1013.      * following the order the user dictated.
  1014.      */
  1015.     for (ix = 0; ; ix++)
  1016. {
  1017. if (MII_PHY_FLAGS_ARE_SET (MII_PHY_TBL))
  1018.     {
  1019.     if (pPhyInfo->phyAnOrderTbl == NULL)
  1020. {
  1021. MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate no auto-neg tablen"),
  1022.        0, 0, 0, 0, 0, 0);
  1023. return (ERROR);
  1024. }
  1025.     /* check we're not at the end of the user table */
  1026.     if (*((INT16*) pPhyInfo->phyAnOrderTbl + ix) == -1)
  1027. return (ERROR);
  1028.     /* just negotiate one ability at a time */
  1029.     phyAds &= ~MII_ADS_TECH_MASK;
  1030.     /* translate user settings */
  1031.     phyAds |= *((INT16*) pPhyInfo->phyAnOrderTbl + ix);
  1032.     /* check the PHY has the desidered ability */
  1033.     if (!(phyAds & pPhyInfo->miiRegs.phyAds))
  1034. continue;
  1035.     }
  1036. else
  1037.     {
  1038.     /* check the PHY flags and possibly mask some abilities off */
  1039.     if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_FD)))
  1040. phyAds &= ~(MII_TECH_10BASE_FD | MII_TECH_100BASE_TX_FD);
  1041.     if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_HD)))
  1042. phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_100BASE_TX 
  1043.     | MII_TECH_100BASE_T4);
  1044.     if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_100)))
  1045. phyAds &= ~(MII_TECH_100BASE_TX | MII_TECH_100BASE_TX_FD
  1046.     | MII_TECH_100BASE_T4);
  1047.     if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_10)))
  1048. phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_10BASE_FD);
  1049.     /* store the current registers values */
  1050.     pPhyInfo->miiRegs.phyAds = phyAds;
  1051.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  1052.         {
  1053.         /* check phyFlags with 1000T FD mode */
  1054.         if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_FD)))
  1055.             phyMstSlaCtrl &= ~MII_MASSLA_CTRL_1000T_FD;
  1056.         /* check phyFlags with 1000T HD mode */
  1057.         if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_HD)))
  1058.             phyMstSlaCtrl &= ~MII_MASSLA_CTRL_1000T_HD;
  1059.        /* store the current registers values */
  1060.         pPhyInfo->miiGRegs.phyMSCtrl = phyMstSlaCtrl;;
  1061.         MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyMSCtrl=0x%xn"),
  1062.    phyMstSlaCtrl, 0, 0, 0, 0, 0);
  1063.         }
  1064.     MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%xn"),
  1065.    phyAds, 0, 0, 0, 0, 0);
  1066.     }
  1067. /* set the ANAR accordingly */
  1068. regAddr = MII_AN_ADS_REG;
  1069. MII_WRITE (phyAddr, regAddr, phyAds, retVal);
  1070. if (retVal != OK)
  1071.     return (ERROR);
  1072.     MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%xn"),
  1073.    phyAds, 0, 0, 0, 0, 0);
  1074.     /* set MSC register accordingly */
  1075.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  1076.         {
  1077.         regAddr = MII_MASSLA_CTRL_REG;
  1078.         MII_WRITE (phyAddr, regAddr, phyMstSlaCtrl, retVal);
  1079.         if (retVal != OK)
  1080.             return (ERROR);
  1081.         }
  1082. /* 
  1083.  * start the auto-negotiation process: return
  1084.  * only in case of fatal error.
  1085.  */
  1086. retVal = miiAutoNegStart (pPhyInfo, phyAddr);
  1087. /* 
  1088.  * in case of fatal error, we return immediately; otherwise,
  1089.  * we try to recover from the failure, if we're not using 
  1090.  * the standard auto-negotiation process.
  1091.  */
  1092. if (retVal == ERROR)
  1093.     {
  1094.     if (errno != S_miiLib_PHY_AN_FAIL)
  1095. return (ERROR);
  1096.     else
  1097. {
  1098. if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_TBL)))
  1099.     return (ERROR);
  1100. else
  1101.     {
  1102.     /* let's try the next entry in the table */
  1103.     errno = 0;
  1104.     continue;
  1105.     }
  1106. }
  1107.     }
  1108. /* check the negotiation was successful */
  1109. if (miiAnCheck (pPhyInfo, phyAddr) == OK)
  1110.     return (OK);
  1111. /* 
  1112.  * we are here if the negotiation went wong:
  1113.  * if the auto-negotiation order table was not 
  1114.  * used, we return ERROR, as all the PHY abilities
  1115.  * were negotiated at once.
  1116.  */
  1117. if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_TBL)))
  1118.     return (ERROR);
  1119. }
  1120.     return (OK);
  1121.     }
  1122. /*******************************************************************************
  1123. *
  1124. * miiAutoNegStart - start the auto-negotiation process
  1125. *
  1126. * This routine starts the auto-negotiation process for the PHY whose
  1127. * address is specified in the parameter <phyAddr>.
  1128. *
  1129. * RETURNS: OK or ERROR.
  1130. *
  1131. * ERRNO: S_miiLib_PHY_AN_FAIL
  1132. *
  1133. */
  1134. LOCAL STATUS miiAutoNegStart
  1135.     (
  1136.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1137.     UINT8 phyAddr /* address of a PHY */
  1138.     )
  1139.     {
  1140.     UINT16 data; /* data to be written to the control reg */
  1141.     UINT8 regAddr; /* PHY register */
  1142.     UINT16 phyStatus; /* holder for the PHY status */
  1143.     UINT16 ix = 0; /* a counter */
  1144.     int retVal; /* convenient holder for return value */
  1145.     regAddr = MII_STAT_REG;
  1146.     MII_READ (phyAddr, regAddr, &phyStatus, retVal);
  1147.     if (retVal != OK)
  1148. return (ERROR);
  1149.     MII_LOG (MII_DBG_ANY, ("miiAutoNegStart phy=0x%x reg=0x%x status=0x%xn"),
  1150.    phyAddr, regAddr, phyStatus, 0, 0, 0);
  1151.     /* check the PHY has this ability */
  1152.     if ((phyStatus & MII_SR_AUTO_SEL) != MII_SR_AUTO_SEL)
  1153. {
  1154. MII_LOG (MII_DBG_ANY, ("miiAutoNegStart phy not 
  1155.        auto neg capablen"), 
  1156.        0, 0, 0, 0, 0, 0);
  1157. return (ERROR);
  1158. }
  1159.     /* restart the auto-negotiation process */
  1160.     regAddr = MII_CTRL_REG;
  1161.     data = (MII_CR_RESTART | MII_CR_AUTO_EN);
  1162.     MII_WRITE (phyAddr, regAddr, data, retVal);
  1163.     if (retVal != OK)
  1164. return (ERROR);
  1165.     /* save status info */
  1166.     pPhyInfo->miiRegs.phyCtrl = data;
  1167.     /* let's check the PHY status for completion */
  1168.     regAddr = MII_STAT_REG;
  1169.     /* spin until it is done */
  1170.     do
  1171. {
  1172. MII_SYS_DELAY (pPhyInfo->phyDelayParm);
  1173. if (ix++ == pPhyInfo->phyMaxDelay)
  1174.     break;
  1175. MII_READ (phyAddr, regAddr, &phyStatus, retVal);
  1176. if (retVal != OK)
  1177.     return (ERROR);
  1178. } while ((phyStatus & MII_SR_AUTO_NEG) != MII_SR_AUTO_NEG);
  1179.     MII_LOG (MII_DBG_ANY, ("miiAutoNegStart auto neg attempts=%d n"),
  1180.    ix, 0, 0, 0, 0, 0);
  1181.     if (ix >= pPhyInfo->phyMaxDelay)
  1182. {
  1183. MII_LOG (MII_DBG_ANY, ("miiAutoNegStart auto neg failn"),
  1184.        0, 0, 0, 0, 0, 0);
  1185. errnoSet (S_miiLib_PHY_AN_FAIL);
  1186. return (ERROR);
  1187. }
  1188.     else
  1189. {
  1190. MII_LOG (MII_DBG_ANY, ("miiAutoNegStart auto neg done phyStat=0x%xn"),
  1191.        phyStatus, 0, 0, 0, 0, 0);
  1192. }
  1193.     return (OK);
  1194.     }
  1195. /*******************************************************************************
  1196. *
  1197. * miiBasicCheck - run a basic check on the PHY status register
  1198. *
  1199. * This routine runs a basic check on the PHY status register to
  1200. * ensure a valid link has been established and no faults have been 
  1201. * detected.
  1202. *
  1203. * RETURNS: OK or ERROR.
  1204. *
  1205. */
  1206. LOCAL STATUS miiBasicCheck
  1207.     (
  1208.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1209.     UINT8 phyAddr /* address of a PHY */
  1210.     )
  1211.     {
  1212.     UINT8 regAddr; /* PHY register */
  1213.     UINT16 phyStatus; /* holder for the PHY status */
  1214.     UINT16 ix = 0; /* a counter */
  1215.     int retVal; /* convenient holder for return value */
  1216.     /* let's check the PHY status for completion */
  1217.     regAddr = MII_STAT_REG;
  1218.     /* spin until it is done */
  1219.     do
  1220. {
  1221.   MII_SYS_DELAY (sysClkRateGet());
  1222.         ix += sysClkRateGet(); 
  1223. if (ix >= pPhyInfo->phyMaxDelay)
  1224.     break;
  1225. MII_READ (phyAddr, regAddr, &phyStatus, retVal); 
  1226.    if (retVal != OK)
  1227.     return (ERROR);
  1228. } while ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS); 
  1229.     if (ix >= pPhyInfo->phyMaxDelay)
  1230. {
  1231. MII_LOG (MII_DBG_ANY, ("miiBasicCheck failn"),
  1232.        0, 0, 0, 0, 0, 0);
  1233. return (ERROR);
  1234. }
  1235.     MII_LOG (MII_DBG_ANY, ("miiBasicCheck Link up! status=0x%xn"),
  1236.    phyStatus, 0, 0, 0, 0, 0);
  1237.     /* check for remote fault condition, read twice */
  1238.     MII_READ (phyAddr, regAddr, &phyStatus, retVal);
  1239.     if (retVal != OK)
  1240. return (ERROR);
  1241.     MII_READ (phyAddr, regAddr, &phyStatus, retVal);
  1242.     if (retVal != OK)
  1243. return (ERROR);
  1244.     if ((phyStatus & MII_SR_REMOTE_FAULT) == MII_SR_REMOTE_FAULT)
  1245. {
  1246. MII_LOG (MII_DBG_ANY, ("miiBasicCheck remote faultn"),
  1247.        0, 0, 0, 0, 0, 0);
  1248. return (ERROR);
  1249. }
  1250.     /* store the current registers values */
  1251.     pPhyInfo->miiRegs.phyStatus = phyStatus;
  1252.     return (OK);
  1253.     }
  1254. /*******************************************************************************
  1255. *
  1256. * miiFlagsHandle - handle some flags
  1257. *
  1258. * This routine sets some fields in the PHY_INFO structure according to the
  1259. * values of the related flags.
  1260. *
  1261. * RETURNS: OK, always.
  1262. */
  1263. LOCAL STATUS miiFlagsHandle
  1264.     (
  1265.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1266.     UINT8 phyAddr /* address of a PHY */
  1267.     )
  1268.     {
  1269.     /* check speed ... */ 
  1270.     if (MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_FD) || 
  1271.         MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_HD))
  1272.         pPhyInfo->phySpeed = MII_1000MBS;
  1273.     else if (MII_PHY_FLAGS_ARE_SET (MII_PHY_100))
  1274. pPhyInfo->phySpeed = MII_100MBS;
  1275.     else
  1276. pPhyInfo->phySpeed = MII_10MBS;
  1277.  
  1278.     if (MII_PHY_FLAGS_ARE_SET (MII_PHY_FD))
  1279.         {
  1280.         bcopy (MII_FDX_STR, (char *) pPhyInfo->phyMode, MII_FDX_LEN);
  1281.         }
  1282.     else
  1283.         {
  1284.         bcopy (MII_HDX_STR, (char *) pPhyInfo->phyMode, MII_HDX_LEN);
  1285.         }
  1286.     MII_LOG (MII_DBG_ANY, ("miiFlagsHandle speed=%d mode=%sn"),
  1287.    pPhyInfo->phySpeed, 
  1288.    (char *) pPhyInfo->phyMode, 0, 0, 0, 0);
  1289.     return (OK);
  1290.     }
  1291. /*******************************************************************************
  1292. *
  1293. * miiPhyUpdate - update the phyInfo structure to the latest PHY status
  1294. *
  1295. * This routine updates the phyInfo structure to the latest PHY status.
  1296. *
  1297. * RETURNS: OK or ERROR.
  1298. */
  1299. LOCAL STATUS miiPhyUpdate
  1300.     (
  1301.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1302.     UINT8 phyAddr /* address of a PHY */
  1303.     )
  1304.     {
  1305.     UINT16 phyStatus; /* holder for the PHY status */
  1306.     UINT16 phyAds; /* PHY advertisement register value */
  1307.     UINT16 phyPrtn; /* PHY partner ability register value */
  1308.     UINT16 phyExp; /* PHY expansion register value */
  1309.     UINT16  phyMstSlaCtrl; /* PHY Master-slave Control value */
  1310.     UINT16  phyMstSlaStat; /* PHY Master-slave Status value */
  1311.     UINT16 negAbility; /* abilities after negotiation */
  1312.     int retVal; /* convenient holder for return value */
  1313.     MII_READ (phyAddr, MII_STAT_REG, &phyStatus, retVal);
  1314.     if (retVal == ERROR)
  1315. return (ERROR);
  1316.     /* does the PHY support the extended registers set? */
  1317.     if (!(phyStatus & MII_SR_EXT_CAP))
  1318. return (OK);
  1319.     MII_READ (phyAddr, MII_AN_ADS_REG, &phyAds, retVal);
  1320.     if (retVal == ERROR)
  1321. return (ERROR);
  1322.     MII_READ (phyAddr, MII_AN_PRTN_REG, &phyPrtn, retVal);
  1323.     if (retVal == ERROR)
  1324. return (ERROR);
  1325.     MII_READ (phyAddr, MII_AN_EXP_REG, &phyExp, retVal);
  1326.     if (retVal == ERROR)
  1327. return (ERROR);
  1328.     /* flow control configuration */
  1329.     /* MII defines symmetric PAUSE ability */
  1330.     if ((!(phyAds & MII_ANAR_PAUSE)) || (!(phyPrtn & MII_TECH_PAUSE)))
  1331.         pPhyInfo->phyFlags &= ~(MII_PHY_TX_FLOW_CTRL | MII_PHY_RX_FLOW_CTRL); 
  1332.     else
  1333.         pPhyInfo->phyFlags |= (MII_PHY_TX_FLOW_CTRL | MII_PHY_RX_FLOW_CTRL); 
  1334.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  1335.         {
  1336.         /* GMII also defines asymmetric PAUSE ability */
  1337.         /* Advertises transmitter but no receiver */
  1338.         if (((phyAds & MII_ANAR_PAUSE_MASK) == MII_ANAR_ASM_PAUSE) &&
  1339.              ((phyPrtn & MII_TECH_PAUSE_MASK) == MII_TECH_PAUSE_MASK))
  1340.             {
  1341.             pPhyInfo->phyFlags |= MII_PHY_TX_FLOW_CTRL;
  1342.             }
  1343.         /* Advertises receiver but no transmitter */
  1344.         else if (((phyAds & MII_ANAR_PAUSE_MASK) == MII_ANAR_PAUSE_MASK) &&
  1345.             ((phyPrtn & MII_TECH_PAUSE_MASK) == MII_TECH_ASM_PAUSE))
  1346.             {
  1347.             pPhyInfo->phyFlags |= MII_PHY_RX_FLOW_CTRL;
  1348.             }
  1349.         /* no flow control */
  1350.         else if ((!(phyAds & MII_ANAR_PAUSE)) || (!(phyPrtn & MII_TECH_PAUSE)))
  1351.             {
  1352.             pPhyInfo->phyFlags &= ~(MII_PHY_TX_FLOW_CTRL | 
  1353.                                        MII_PHY_RX_FLOW_CTRL);
  1354.             }
  1355.         /* TX and RX flow control */
  1356.         else
  1357.             {
  1358.             pPhyInfo->phyFlags |= (MII_PHY_TX_FLOW_CTRL | MII_PHY_RX_FLOW_CTRL);
  1359.             }
  1360.         }
  1361.     /* find out the max common abilities */
  1362.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  1363.         {
  1364.         /* search for 1000T capbility */
  1365.         /* get MASTER-SLAVE control register */
  1366.         MII_READ (phyAddr, MII_MASSLA_CTRL_REG, &phyMstSlaCtrl, retVal);
  1367.         if (retVal == ERROR)
  1368.             return (ERROR);
  1369.         /* get MASTER-SLAVE status register */
  1370.         MII_READ (phyAddr, MII_MASSLA_STAT_REG, &phyMstSlaStat, retVal);
  1371.         if (retVal == ERROR)
  1372.             return (ERROR);
  1373.         MII_READ (phyAddr, MII_MASSLA_STAT_REG, &phyMstSlaStat, retVal);
  1374.         if (retVal == ERROR)
  1375.             return (ERROR);
  1376.         if ((phyMstSlaStat & MII_MASSLA_STAT_LP1000T_FD) && 
  1377.             (phyMstSlaCtrl & MII_MASSLA_CTRL_1000T_FD))
  1378.             {
  1379.             /* 1000T FD supported */
  1380.              
  1381.             MII_PHY_FLAGS_SET (MII_PHY_FD);
  1382.             goto exitPhyUpdate;
  1383.             }
  1384.         else if ((phyMstSlaStat & MII_MASSLA_STAT_LP1000T_HD) && 
  1385.                  (phyMstSlaCtrl & MII_MASSLA_CTRL_1000T_HD))
  1386.             {
  1387.                /* 1000T HD supported */
  1388.                  
  1389.             MII_PHY_FLAGS_SET (MII_PHY_HD);
  1390.             MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_FD);
  1391.             goto exitPhyUpdate;
  1392.             }
  1393.         else
  1394.             {
  1395.             /* 1000T not supported, go check other abilities */
  1396.             MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_FD); 
  1397.             MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_HD);
  1398.             }
  1399.         }
  1400.     negAbility = phyPrtn & phyAds & MII_ADS_TECH_MASK;
  1401.     MII_LOG (MII_DBG_ANY, ("miiPhyUpdate phyAds=0x%x
  1402.    phyPrtn=0x%x common=0x%x phyExp=0x%xn"),
  1403.    phyAds, 
  1404.    phyPrtn, 
  1405.    negAbility, 
  1406.    phyExp, 0, 0);
  1407.     if (negAbility & MII_TECH_100BASE_TX_FD)
  1408. {
  1409. }
  1410.     else if ((negAbility & MII_TECH_100BASE_TX) ||
  1411.  (negAbility & MII_TECH_100BASE_T4))
  1412. {
  1413. MII_PHY_FLAGS_CLEAR (MII_PHY_FD);
  1414. }
  1415.     else if (negAbility & MII_TECH_10BASE_FD)
  1416. {
  1417. MII_PHY_FLAGS_CLEAR (MII_PHY_100); 
  1418. }
  1419.     else if (negAbility & MII_TECH_10BASE_T)
  1420. {
  1421. MII_PHY_FLAGS_CLEAR (MII_PHY_FD);
  1422. MII_PHY_FLAGS_CLEAR (MII_PHY_100); 
  1423. }
  1424.     else
  1425. {
  1426. MII_LOG (MII_DBG_ANY, ("miiPhyUpdate fail!n"),
  1427.        0, 0, 0, 0, 0, 0);
  1428. return (ERROR);
  1429. }
  1430.     /* store the current registers values */
  1431. exitPhyUpdate:
  1432.     pPhyInfo->miiRegs.phyStatus = phyStatus;
  1433.     pPhyInfo->miiRegs.phyAds = phyAds;
  1434.     pPhyInfo->miiRegs.phyPrtn = phyPrtn;
  1435.     pPhyInfo->miiRegs.phyExp = phyExp;
  1436.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  1437.         {    
  1438.         pPhyInfo->miiGRegs.phyMSStatus = phyMstSlaStat;
  1439.         pPhyInfo->miiGRegs.phyMSCtrl = phyMstSlaCtrl;
  1440.         }
  1441.     /* handle some flags */
  1442.     if (miiFlagsHandle (pPhyInfo, phyAddr) != OK)
  1443. return (ERROR);
  1444.     return (OK);
  1445.     }
  1446. /*******************************************************************************
  1447. *
  1448. * miiAnCheck - check the auto-negotiation process result
  1449. *
  1450. * This routine checks the auto-negotiation process has completed
  1451. * successfully and no faults have been detected by any of the PHYs 
  1452. * engaged in the process.
  1453. *
  1454. * NOTE: 
  1455. * In case the cable is pulled out and reconnect to the same/different 
  1456. * hub/switch again. PHY probably starts a new auto-negotiation process and 
  1457. * get different negotiation results. User should call this routine to check 
  1458. * link status and update phyFlags. pPhyInfo should include a valid 
  1459. * PHY bus number (phyAddr), and include the phyFlags that was used last time 
  1460. * to configure auto-negotiation process.
  1461. *
  1462. * RETURNS: OK or ERROR.
  1463. */
  1464. STATUS miiAnCheck
  1465.     (
  1466.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1467.     UINT8 phyAddr /* address of a PHY */
  1468.     )
  1469.     {
  1470.     UINT8 regAddr; /* PHY register */
  1471.     UINT16 phyPrtn; /* PHY partner ability register value */
  1472.     UINT16 phyExp; /* PHY expansion register value */
  1473.     int retVal; /* convenient holder for return value */
  1474.     /* 
  1475.      * The sysClkRate could have changed since  the link was lost. 
  1476.      * Ensure that pPhyInfo->phyMaxDelay is at lease 5 seconds. 
  1477.      */
  1478.     if (pPhyInfo->phyMaxDelay < (sysClkRateGet() * 5))
  1479.         {
  1480.         /* Set max delay porportionally */
  1481.         pPhyInfo->phyMaxDelay = sysClkRateGet() * 5;
  1482.         }
  1483.     /* run a check on the status bits of basic registers only */
  1484.     retVal = miiBasicCheck (pPhyInfo, phyAddr);
  1485.     if (retVal != OK)
  1486. return (retVal);
  1487.     /* we know the auto-negotiation process has finished */
  1488.     regAddr = MII_AN_EXP_REG;
  1489.     MII_READ (phyAddr, regAddr, &phyExp, retVal);
  1490.     if (retVal != OK)
  1491. return (ERROR);
  1492.     /* check for faults detected by the parallel function */
  1493.     if ((phyExp & MII_EXP_FAULT) == MII_EXP_FAULT)
  1494. {
  1495. MII_LOG (MII_DBG_ANY, ("miiAnCheck: fault expStat=0x%xn"),
  1496.        phyExp, 0, 0, 0, 0, 0);
  1497. /*
  1498.  * Don't fail here as some PHY devices don't support this register,
  1499.  * but seem to return 0xffff when it is read (jgn - 5/8/00)
  1500.  */
  1501. /* return (ERROR); */
  1502. }
  1503.     /* check for remote faults */
  1504.     regAddr = MII_AN_PRTN_REG;
  1505.     MII_READ (phyAddr, regAddr, &phyPrtn, retVal);
  1506.     if (retVal != OK)
  1507. return (ERROR);
  1508.     if ((phyPrtn & MII_BP_FAULT) == MII_BP_FAULT)
  1509. {
  1510. MII_LOG (MII_DBG_ANY, ("miiAnCheck partner stat=0x%xn"),
  1511.        phyPrtn, 0, 0, 0, 0, 0);
  1512. return (ERROR);
  1513. }
  1514.     if (miiPhyUpdate (pPhyInfo, phyAddr) == ERROR)
  1515. {
  1516. MII_LOG (MII_DBG_ANY, "miiPhyUpdate errorn",0,0,0,0,0,0);
  1517. return (ERROR);
  1518. }
  1519.     MII_LOG (MII_DBG_ANY, ("miiAnCheck OKn"),
  1520.    0, 0, 0, 0, 0, 0);
  1521.     return (OK);
  1522.     }
  1523. /*******************************************************************************
  1524. *
  1525. * miiModeForce - force an operating mode for the PHY
  1526. *
  1527. * This routine forces an operating mode for the PHY whose address is 
  1528. * specified in the parameter <phyAddr>. It also calls miiBasicCheck() 
  1529. * to ensure a valid link has been established.
  1530. *
  1531. * RETURNS: OK or ERROR.
  1532. */
  1533. LOCAL STATUS miiModeForce
  1534.     (
  1535.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1536.     UINT8 phyAddr /* address of a PHY */
  1537.     )
  1538.     {
  1539.     UINT16 data; /* data to be written to the control reg */
  1540.     UINT8 regAddr; /* PHY register */
  1541.     int retVal; /* convenient holder for return value */
  1542.     MII_LOG (MII_DBG_ANY, ("miiModeForce n"),
  1543.    0, 0, 0, 0, 0, 0);
  1544.     /*
  1545.      * force as a high priority as possible operating
  1546.      * mode, not overlooking what the user dictated.
  1547.      */
  1548.  
  1549.     data = MII_CR_NORM_EN;
  1550.  
  1551.     if (MII_PHY_FLAGS_ARE_SET (MII_PHY_100))
  1552.         {
  1553.         data |= MII_CR_100;
  1554.         }
  1555.  
  1556.     if (MII_PHY_FLAGS_ARE_SET (MII_PHY_FD))
  1557.         {
  1558.         data |= MII_CR_FDX;
  1559.         }
  1560.  
  1561.     pPhyInfo->miiRegs.phyCtrl = data;
  1562.  
  1563.     regAddr = MII_CTRL_REG;
  1564.  
  1565.     /* try to establish the link */
  1566.     MII_WRITE (phyAddr, regAddr, data, retVal);
  1567.     if (retVal != OK)
  1568. return (ERROR);
  1569.     /* run a check on the status bits of basic registers only */
  1570.     if (miiBasicCheck (pPhyInfo, phyAddr) != OK)
  1571. return (ERROR);
  1572.     /* handle some flags */
  1573.     if (miiFlagsHandle (pPhyInfo, phyAddr) != OK)
  1574. return (ERROR);
  1575.     return (OK);
  1576.     }
  1577. /*******************************************************************************
  1578. *
  1579. * miiDefForce - force a default operating mode for the PHY
  1580. *
  1581. * This routine forces a default operating mode for the PHY whose address is 
  1582. * specified in the parameter <phyAddr>. It also calls miiBasicCheck() 
  1583. * to ensure a valid link has been established.
  1584. *
  1585. * RETURNS: OK or ERROR.
  1586. *
  1587. * ERRNO: S_miiLib_PHY_NO_ABLE
  1588. *
  1589. */
  1590. LOCAL STATUS miiDefForce
  1591.     (
  1592.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1593.     UINT8 phyAddr /* address of a PHY */
  1594.     )
  1595.     {
  1596.     UINT16 data; /* data to be written to the control reg */
  1597.     UINT8 regAddr; /* PHY register */
  1598.     int retVal; /* convenient holder for return value */
  1599.     UINT16 phyStatus; /* holder for the PHY status */
  1600.     MII_LOG (MII_DBG_ANY, ("miiDefForce n"),
  1601.    0, 0, 0, 0, 0, 0);
  1602.     /* translate user settings */
  1603.     data = miiDefLookupTbl [(pPhyInfo->phyDefMode)];
  1604.     /* find out what abilities the PHY features */
  1605.  
  1606.     regAddr = MII_STAT_REG;
  1607.     MII_READ (phyAddr, regAddr, &phyStatus, retVal);
  1608.     if (retVal == ERROR)
  1609. return (ERROR);
  1610.     if (data & MII_CR_100) 
  1611. {
  1612. if (!(phyStatus & (MII_SR_TX_HALF_DPX
  1613.    | MII_SR_TX_FULL_DPX
  1614.    | MII_SR_T4)))
  1615.     {
  1616.     errnoSet (S_miiLib_PHY_NO_ABLE);
  1617.     return (ERROR); 
  1618.     }
  1619. MII_PHY_FLAGS_SET (MII_PHY_100);
  1620. }
  1621.     else
  1622. {
  1623. if (!(phyStatus & (MII_SR_10T_HALF_DPX 
  1624.  | MII_SR_10T_FULL_DPX)))
  1625.     {
  1626.     errnoSet (S_miiLib_PHY_NO_ABLE);
  1627.     return (ERROR); 
  1628.     }
  1629. MII_PHY_FLAGS_CLEAR (MII_PHY_100);
  1630. }
  1631.     if (data & MII_CR_FDX)
  1632. {
  1633. if (!(phyStatus & (MII_SR_10T_FULL_DPX 
  1634.  | MII_SR_TX_FULL_DPX)))
  1635.     {
  1636.     errnoSet (S_miiLib_PHY_NO_ABLE);
  1637.     return (ERROR); 
  1638.     }
  1639. MII_PHY_FLAGS_SET (MII_PHY_FD);
  1640. }
  1641.     else
  1642. {
  1643. if (!(phyStatus & (MII_SR_10T_HALF_DPX 
  1644.  | MII_SR_TX_HALF_DPX)))
  1645.     {
  1646.     errnoSet (S_miiLib_PHY_NO_ABLE);
  1647.     return (ERROR); 
  1648.     }
  1649. MII_PHY_FLAGS_CLEAR (MII_PHY_FD); 
  1650. }
  1651.     pPhyInfo->miiRegs.phyCtrl = data;
  1652.     regAddr = MII_CTRL_REG;
  1653.     /* force this specific operating mode, but do not check the link */
  1654.     MII_WRITE (phyAddr, regAddr, data, retVal);
  1655.     /* handle some flags */
  1656.     if (miiFlagsHandle (pPhyInfo, phyAddr) != OK)
  1657. return (ERROR);
  1658.     return (OK);
  1659.     }
  1660. /**************************************************************************
  1661. *
  1662. * miiAbilFlagSet - set some ability flags 
  1663. *
  1664. * This routine sets some ability flags for a later use.
  1665. *
  1666. * RETURNS: OK, always.
  1667. */
  1668. LOCAL STATUS miiAbilFlagSet
  1669.     (
  1670.     PHY_INFO *  pPhyInfo,       /* pointer to PHY_INFO structure */
  1671.     UINT8 phyAddr /* address of a PHY */
  1672.     )
  1673.     {
  1674.     UINT8 regAddr; /* PHY register */
  1675.     UINT16 phyStatus; /* holder for the PHY status */
  1676.     UINT16 phyExtStat;     /* holder for the PHY Extended status */
  1677.     int retVal; /* convenient holder for return value */
  1678.     /* find out what abilities the PHY features */
  1679.  
  1680.     regAddr = MII_STAT_REG;
  1681.     MII_READ (phyAddr, regAddr, &phyStatus, retVal);
  1682.     if (retVal == ERROR)
  1683. return (ERROR);
  1684.     /* handle phy flags */
  1685.     if (!(phyStatus & (MII_SR_TX_HALF_DPX 
  1686.        | MII_SR_TX_FULL_DPX
  1687.        | MII_SR_T4)))
  1688. {
  1689. MII_PHY_FLAGS_CLEAR (MII_PHY_100);
  1690. }
  1691.     if (!(phyStatus & (MII_SR_10T_FULL_DPX 
  1692.      | MII_SR_TX_FULL_DPX)))
  1693. {
  1694. MII_PHY_FLAGS_CLEAR (MII_PHY_FD);
  1695. }
  1696.     if (!(phyStatus & (MII_SR_10T_HALF_DPX 
  1697.      | MII_SR_10T_FULL_DPX)))
  1698. {
  1699. MII_PHY_FLAGS_CLEAR (MII_PHY_10);
  1700. }
  1701.     if (!(phyStatus & (MII_SR_TX_HALF_DPX 
  1702.      | MII_SR_10T_HALF_DPX)))
  1703. {
  1704. MII_PHY_FLAGS_CLEAR (MII_PHY_HD);
  1705. }
  1706.     if (!(phyStatus & MII_SR_AUTO_SEL))
  1707. {
  1708. MII_LOG (MII_DBG_ANY, ("miiAbilFlagSet phy not 
  1709.        auto neg capablen"), 
  1710.        0, 0, 0, 0, 0, 0);
  1711. MII_PHY_FLAGS_CLEAR (MII_PHY_AUTO);
  1712. }
  1713.     if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
  1714.         {
  1715.         regAddr = MII_EXT_STAT_REG;
  1716.         MII_READ (phyAddr, regAddr, &phyExtStat, retVal);
  1717.         if (retVal != OK)
  1718.             return (ERROR);
  1719.  
  1720.         /* mask off 1000T FD if PHY not supported */
  1721.         if (!(phyExtStat & MII_EXT_STAT_1000T_HD))
  1722.              MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_HD);
  1723.         /* mask off 1000T HD if PHY not supported */
  1724.         if (!(phyExtStat & MII_EXT_STAT_1000T_FD))
  1725.              MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_FD);
  1726.         }
  1727.     return (OK);
  1728.     }
  1729. /**************************************************************************
  1730. *
  1731. * miiPhyOptFuncMultiSet - set pointers to MII optional registers handlers
  1732. *
  1733. * This routine sets the function pointers in <pPhyInfo->optRegsFunc> to the 
  1734. * MII optional, PHY-specific registers handler. The handler will be executed
  1735. * before the PHY's technology abilities are negotiated. If a system employees
  1736. * more than on type of network device requiring a PHY-specific registers 
  1737. * handler use this routine instead of miiPhyOptFuncSet() to ensure device
  1738. * specific handlers and to avoid overwritting one's with the other's. 
  1739. *
  1740. * PROTECTION DOMAINS
  1741. * (VxAE) This function can only be called from within the kernel protection
  1742. * domain. The argument optRegsFunc MUST be a pointer to function in the kernel
  1743. * protection domain.
  1744. *
  1745. * RETURNS: N/A.
  1746. */
  1747. void miiPhyOptFuncMultiSet
  1748.     (
  1749.     PHY_INFO * pPhyInfo, /* device specific pPhyInfo pointer */ 
  1750.     FUNCPTR    optRegsFunc      /* function pointer */
  1751.     )
  1752.     {
  1753.     if (optRegsFunc != NULL)
  1754.         pPhyInfo->pPhyOptRegsRtn = optRegsFunc;
  1755.     else
  1756.         pPhyInfo->pPhyOptRegsRtn = NULL;
  1757.     }
  1758. /**************************************************************************
  1759. *
  1760. * miiPhyOptFuncSet - set the pointer to the MII optional registers handler
  1761. *
  1762. * This routine sets the function pointer in <optRegsFunc> to the MII 
  1763. * optional, PHY-specific registers handler. The handler will be executed 
  1764. * before the PHY's technology abilities are negotiated.
  1765. *
  1766. * PROTECTION DOMAINS
  1767. * (VxAE) This function can only be called from within the kernel protection
  1768. * domain. The argument optRegsFunc MUST be a pointer to function in the kernel
  1769. * protection domain.
  1770. *
  1771. * RETURNS: N/A.
  1772. */
  1773.  
  1774. void miiPhyOptFuncSet
  1775.     (
  1776.     FUNCPTR    optRegsFunc      /* function pointer */
  1777.     )
  1778.     {
  1779.     if (optRegsFunc != NULL)
  1780. pPhyOptRegsRtn = optRegsFunc;
  1781.     else
  1782. pPhyOptRegsRtn = NULL;
  1783.     }
  1784. /**************************************************************************
  1785. *
  1786. * miiPhyMonitorStart - monitor all the PHYs to detect a status change
  1787. *
  1788. * This routine monitors all the PHYs to detect a status change.
  1789. *
  1790. * RETURNS: OK or ERROR.
  1791. */
  1792.  
  1793. LOCAL STATUS miiPhyMonitorStart
  1794.     (
  1795.     )
  1796.     {
  1797.     netJobAdd ((FUNCPTR) miiPhyMonitor, (int) NULL, 0, 0, 0, 0);
  1798.     return (OK);
  1799.     }
  1800. /**************************************************************************
  1801. *
  1802. * miiPhyMonitor - monitor all the PHYs to detect a link down event
  1803. *
  1804. * This routine monitors all the PHYs to detect a link down event.
  1805. *
  1806. * RETURNS: OK or ERROR.
  1807. */
  1808.  
  1809. LOCAL STATUS miiPhyMonitor
  1810.     (
  1811.     )
  1812.     {
  1813.     UINT16 phyStatus; /* holder for the PHY status */
  1814.     int retVal = OK; /* convenient holder for return value */
  1815.     PHY_INFO * pPhyInfo; /* PHY info pointer */
  1816.     MII_PHY_NODE * pMiiPhyNode = NULL; /* pointer to phy node */
  1817.     /* protect it from other MII routines */
  1818.     MII_SEM_TAKE (WAIT_FOREVER);
  1819.     /* loop through all the PHYs */
  1820.     for (pMiiPhyNode = (MII_PHY_NODE *) lstFirst (&miiList);
  1821.  pMiiPhyNode != NULL;
  1822.  pMiiPhyNode = (MII_PHY_NODE *) lstNext ((NODE *) pMiiPhyNode))
  1823. {
  1824. pPhyInfo = pMiiPhyNode->pPhyInfo;
  1825. if ((pPhyInfo != NULL) && (MII_PHY_FLAGS_ARE_SET (MII_PHY_INIT))
  1826.     && (MII_PHY_FLAGS_ARE_SET (MII_PHY_MONITOR)))
  1827.     {
  1828.     MII_READ (pPhyInfo->phyAddr, MII_STAT_REG, &phyStatus, retVal);
  1829.     if (retVal == ERROR)
  1830. goto miiMonitorExit;
  1831.     MII_READ (pPhyInfo->phyAddr, MII_STAT_REG, &phyStatus, retVal);
  1832.     if (retVal == ERROR)
  1833. goto miiMonitorExit;
  1834.     /* is the PHY's status link changed? */
  1835.             if ((pPhyInfo->miiRegs.phyStatus & MII_SR_LINK_STATUS) !=
  1836. (phyStatus & MII_SR_LINK_STATUS))
  1837. {
  1838. MII_LOG (MII_DBG_ANY, ("miiPhyMonitor link down stat=0x%xn"),
  1839.        phyStatus, 0, 0, 0, 0, 0);
  1840. /* let the driver know */
  1841. if (pPhyInfo->phyLinkDownRtn != NULL)
  1842.     netJobAdd ((FUNCPTR) (pPhyInfo->phyLinkDownRtn), 
  1843. (int) (pPhyInfo->pDrvCtrl), 0, 0, 0, 0);
  1844. /* record the state so we don't repeatedly tell the driver */
  1845. pPhyInfo->miiRegs.phyStatus = phyStatus;
  1846. }
  1847.     }
  1848. }
  1849. miiMonitorExit:
  1850.     MII_SEM_GIVE ();
  1851.     if ((wdStart ((WDOG_ID) miiWd, (MII_MONITOR_DELAY * sysClkRateGet ()),
  1852.   (FUNCPTR) miiPhyMonitorStart, (int) 0)) == ERROR)
  1853. return (ERROR);
  1854.     return (retVal);
  1855.     }
  1856. /**************************************************************************
  1857. *
  1858. * miiLibInit - initialize the MII library
  1859. *
  1860. * This routine initializes the MII library.
  1861. *
  1862. * PROTECTION DOMAINS
  1863. * (VxAE) This function can only be called from within the kernel protection
  1864. * domain.
  1865. *
  1866. * RETURNS: OK or ERROR.
  1867. */
  1868.  
  1869. STATUS miiLibInit (void)
  1870.     {
  1871.     if (miiLibInitialized)
  1872. return (OK);
  1873.     /* Create the mutex semaphore */
  1874.  
  1875.     miiMutex = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE |
  1876.    SEM_INVERSION_SAFE);
  1877.     /* create the watchdog, do not start it */
  1878.     if ((miiWd = wdCreate ()) == NULL)
  1879. return (ERROR);
  1880.     /* initialize the linked list */
  1881.     lstInit (&miiList);
  1882.     miiLibInitialized = TRUE;
  1883.     MII_LOG (MII_DBG_ANY, ("miiLibInit endn"),
  1884.    0, 0, 0, 0, 0, 0);
  1885.     return (OK);
  1886.     }
  1887. /**************************************************************************
  1888. *
  1889. * miiLibUnInit - uninitialize the MII library
  1890. *
  1891. * This routine uninitializes the MII library. Previously allocated resources
  1892. * are reclaimed back to the system.
  1893. *
  1894. * RETURNS: OK or ERROR.
  1895. */
  1896.  
  1897. STATUS miiLibUnInit
  1898.     (
  1899.     )
  1900.     {
  1901.     if (!miiLibInitialized)
  1902. return (OK);
  1903.     /* are there any PHYs still being used? */
  1904.     if (miiList.count > 0)
  1905. return (ERROR);
  1906.     /* delete the watchdog */
  1907.     if (wdDelete (miiWd) == ERROR)
  1908. return (ERROR);
  1909.     /* delete the mutex @@@ should we take it first? */
  1910.     if (semDelete (miiMutex) == ERROR)
  1911. return (ERROR);
  1912.     miiLibInitialized = FALSE;
  1913.     return (OK);
  1914.     }
  1915. /**************************************************************************
  1916. *
  1917. * miiPhyListAdd - add a PHY to the MII linked list
  1918. *
  1919. * This routine adds the PHY specified in <pPhyInfo> to the MII linked list.
  1920. *
  1921. * RETURNS: OK or ERROR.
  1922. */
  1923.  
  1924. LOCAL STATUS miiPhyListAdd
  1925.     (
  1926.     PHY_INFO *  pPhyInfo       /* pointer to PHY_INFO structure */
  1927.     )
  1928.     {
  1929.     MII_PHY_NODE * pMiiPhyNode = NULL; /* pointer to phy node */
  1930.     MII_LOG (MII_DBG_ANY, ("miiPhyListAdd start n"),
  1931.    0, 0, 0, 0, 0, 0);
  1932.     /* allocate memory for this node, and populate it */
  1933.     pMiiPhyNode = (MII_PHY_NODE *) calloc (1, sizeof (MII_PHY_NODE));
  1934.     pMiiPhyNode->pPhyInfo = pPhyInfo;
  1935.     /* protect it from other MII routines */
  1936.     MII_SEM_TAKE (WAIT_FOREVER);
  1937.     /* add it to the list */
  1938.     lstAdd (&miiList, (NODE *) pMiiPhyNode);
  1939.     /* we're done, release the mutex */
  1940.     MII_SEM_GIVE ();
  1941.     /* record this node */
  1942.     pPhyInfo->pMiiPhyNode = pMiiPhyNode;
  1943.     if ((wdStart (miiWd, MII_MONITOR_DELAY * sysClkRateGet (),
  1944.   (FUNCPTR) miiPhyMonitorStart, (int) 0)) == ERROR)
  1945. return (ERROR);
  1946.     MII_LOG (MII_DBG_ANY, ("miiPhyListAdd end n"),
  1947.    0, 0, 0, 0, 0, 0);
  1948.     return (OK);
  1949.     }
  1950. #ifdef MII_DBG
  1951. /**************************************************************************
  1952. *
  1953. * miiShow - show routine for MII library
  1954. *
  1955. * This is a show routine for the MII library
  1956. *
  1957. * RETURNS: OK, always.
  1958. */
  1959.  
  1960. void miiShow
  1961.     (
  1962.     PHY_INFO    * pPhyInfo      /* pointer to PHY_INFO structure */
  1963.     )
  1964.     {
  1965.     MII_LOG (MII_DBG_ANY, ("miiShow phyCtrl=0x%x phyStat =0x%x phyAds=0x%x "
  1966.                            "phyPrtn=0x%x phyExp=0x%x phyNpt=0x%xn"),
  1967.                            pPhyInfo->miiRegs.phyCtrl,
  1968.                            pPhyInfo->miiRegs.phyStatus,
  1969.                            pPhyInfo->miiRegs.phyAds,
  1970.                            pPhyInfo->miiRegs.phyPrtn,
  1971.                            pPhyInfo->miiRegs.phyExp,
  1972.                            pPhyInfo->miiRegs.phyNext);
  1973.  
  1974.     MII_LOG (MII_DBG_ANY, ("miiShow phyAddr=0x%x phyFlags=0x%x phySpeed=%d "
  1975.                            "phyMode=%sn pDrvCtrl=0x%x n"),
  1976.                            pPhyInfo->phyAddr,
  1977.                            pPhyInfo->phyFlags,
  1978.                            pPhyInfo->phySpeed,
  1979.                            pPhyInfo->phyMode,
  1980.                            pPhyInfo->pDrvCtrl,
  1981.                            0);
  1982.     }
  1983.  
  1984.  
  1985. /**************************************************************************
  1986. *
  1987. * miiRegsGet - get the contents of MII registers
  1988. *
  1989. * This routine gets the contents of the first <regNum> MII registers,
  1990. * and, if <buff> is not NULL, copies them to the space pointed to
  1991. * by <buff>.
  1992. *
  1993. * RETURNS: OK, or ERROR if could not perform the read.
  1994. */
  1995.  
  1996. STATUS miiRegsGet
  1997.     (
  1998.     PHY_INFO    * pPhyInfo,     /* pointer to PHY_INFO structure */
  1999.     UINT        regNum,         /* number of registers to display */
  2000.     UCHAR * buff          /* where to read registers to */
  2001.     )
  2002.     {
  2003.     int         retVal;         /* convenient holder for return value */
  2004.     int         i;              /* a counter */
  2005.  
  2006.     if (buff == NULL)
  2007.         return (OK);
  2008.  
  2009.     regNum = (regNum > MII_MAX_REG_NUM) ? MII_MAX_REG_NUM : regNum;
  2010.  
  2011.     /* Read all the registers the user specified */
  2012.  
  2013.     for (i = 0; i < regNum; i++)
  2014.         {
  2015.         MII_READ (pPhyInfo->phyAddr, i, (UINT16 *) &buff [2 * i], retVal);
  2016.         if (retVal != OK)
  2017.             return (ERROR);
  2018.         }
  2019.  
  2020.     return (OK);
  2021.     }
  2022. #endif /* MII_DBG */