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

VxWorks

开发平台:

C/C++

  1. MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive: bad rbdn"),
  2.       1, 2, 3, 4, 5, 6);
  3.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  4. #ifdef MOT_FEC_DBG
  5. if ((rbdStatus & MOT_FEC_RBD_LG) == MOT_FEC_RBD_LG)
  6.     {
  7.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive: len violationn"),
  8.   1, 2, 3, 4, 5, 6);
  9.     MOT_FEC_RX_LG_ADD;
  10.     }
  11. if ((rbdStatus & MOT_FEC_RBD_NO) == MOT_FEC_RBD_NO)
  12.     {
  13.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive: not alignedn"),
  14.   1, 2, 3, 4, 5, 6);
  15.     MOT_FEC_RX_NO_ADD;
  16.     }
  17. if ((rbdStatus & MOT_FEC_RBD_CRC) == MOT_FEC_RBD_CRC)
  18.     {
  19.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive: CRC errorn"),
  20.   1, 2, 3, 4, 5, 6);
  21.     MOT_FEC_RX_CRC_ADD;
  22.     }
  23. if ((rbdStatus & MOT_FEC_RBD_OV) == MOT_FEC_RBD_OV)
  24.     {
  25.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive: rx overrunn"),
  26.   1, 2, 3, 4, 5, 6);
  27.     MOT_FEC_RX_OV_ADD;
  28.     }
  29. if ((rbdStatus & MOT_FEC_RBD_TR) == MOT_FEC_RBD_TR)
  30.     {
  31.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive: trunc frame n"),
  32.   1, 2, 3, 4, 5, 6);
  33.     MOT_FEC_RX_TR_ADD;
  34.     }
  35. #endif /* MOT_FEC_DBG */
  36. /* put the errored RBD on the RBD queue */
  37. motFecRbdClean (pDrvCtrl, pBuf);
  38. return;
  39. }
  40.     /* get the actual amount of received data */
  41.     MOT_FEC_BD_WORD_RD (pUsedRbd, MOT_FEC_BD_LEN_OFF,
  42. rbdLen);
  43.     if (rbdLen < ETHERSMALL)
  44. {
  45. MOT_FEC_RX_LS_ADD;
  46. /* put the errored RBD on the RBD queue */
  47. motFecRbdClean (pDrvCtrl, pBuf);
  48. return;
  49. }
  50.     /* Allocate an MBLK, and a replacement buffer */
  51.     pMblk = NET_MBLK_ALLOC();
  52.     pBuf = NET_BUF_ALLOC ();
  53.     pClBlk = NET_CL_BLK_ALLOC();
  54.     if ((pMblk == NULL) || (pBuf == NULL) ||
  55. (pClBlk == NULL))
  56. {
  57. MOT_FEC_RX_MEM_ADD;
  58. MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive mem problemn"),
  59.       0, 0, 0, 0, 0, 0);
  60. goto motFecRecvError;
  61. }
  62.     MOT_FEC_BD_LONG_RD (pUsedRbd, MOT_FEC_BD_ADDR_OFF, pData);
  63.     NET_CL_BLK_JOIN (pClBlk, (char *) (pDrvCtrl->rxBuf [pDrvCtrl->rbdIndex]),
  64.      MOT_FEC_MAX_CL_LEN, retVal);
  65.     if (retVal == NULL)
  66. {
  67.         goto motFecRecvError;
  68. }
  69.     NET_MBLK_CL_JOIN(pMblk, pClBlk, retVal);
  70.     if (retVal == NULL)
  71. {
  72.         goto motFecRecvError;
  73. }
  74.     /* set up the mBlk properly */
  75.     pMblk->mBlkHdr.mFlags   |= M_PKTHDR;
  76.     pMblk->mBlkHdr.mData    = pData;
  77.     pMblk->mBlkHdr.mLen = (rbdLen - ETHER_CRC_LEN) & ~0xc000;
  78.     pMblk->mBlkPktHdr.len   = pMblk->mBlkHdr.mLen;
  79.     /* Make cache consistent with memory */
  80.     MOT_FEC_CACHE_INVAL ((char *) pData, pMblk->mBlkHdr.mLen);
  81.     /* up-date statistics */
  82.     if ((*pData ) & (UINT8) 0x01)
  83.         {
  84.         pDrvCtrl->endObj.mib2Tbl.ifInNUcastPkts += 1;
  85.         }
  86.     else
  87.         {
  88.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  89.         }
  90.     /* put the new RBD on the RBD queue */
  91.     motFecRbdClean (pDrvCtrl, pBuf);
  92.     END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);
  93.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecReceive... Done, n"),
  94.   0, 0, 0, 0, 0, 0);
  95.     return;
  96. motFecRecvError:
  97.     /* free buffers/clusters, clean the RBD */
  98.     if (pMblk != NULL)
  99. NET_MBLK_FREE (pMblk);
  100.     if (pClBlk != NULL)
  101. NET_CL_BLK_FREE (pClBlk);
  102.     if (pBuf != NULL)
  103. NET_BUF_FREE ((UCHAR *) pBuf);
  104.     /* put the errored RBD on the RBD queue */
  105.     motFecRbdClean (pDrvCtrl, pBuf);
  106.     }
  107. /**************************************************************************
  108. *
  109. * motFecRbdClean - clean a receive buffer descriptor
  110. *
  111. * This routine cleans a receive buffer descriptor and initializes it
  112. * with the data pointer <pBuf>.
  113. *
  114. * RETURNS: N/A
  115. *
  116. */
  117. LOCAL void motFecRbdClean
  118.     (
  119.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  120.     char * pBuf /* pointer to a new data buffer */
  121.     )
  122.     {
  123.     MOT_FEC_RBD_ID      pUsedRbd; /* pointer to a RBD */
  124.     char * pData = NULL; /* a rx data pointer */
  125.     /* get the first used RBD */
  126.     MOT_FEC_NEXT_RBD (pDrvCtrl, pUsedRbd);
  127.     /* up-date the data pointer with the one provided by the pool */
  128.     if (pBuf != NULL)
  129. {
  130. pDrvCtrl->rxBuf [(pDrvCtrl->rbdIndex)] = (UCHAR *) pBuf;
  131. pData = (char *) NET_TO_MOT_FEC_BUF (pBuf);
  132. MOT_FEC_BD_LONG_WR (pUsedRbd, MOT_FEC_BD_ADDR_OFF, (UINT32) pData);
  133. }
  134.     MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_LEN_OFF, 0);
  135.     /* up-date the status word: treat the last RBD in the ring differently */
  136.     if ((pDrvCtrl->rbdIndex) == (pDrvCtrl->rbdNum - 1))
  137. {
  138. MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_STAT_OFF,
  139.     (MOT_FEC_RBD_WRAP | MOT_FEC_RBD_EMPTY));
  140. }
  141. else
  142. {
  143. MOT_FEC_BD_WORD_WR (pUsedRbd, MOT_FEC_BD_STAT_OFF,
  144.     MOT_FEC_RBD_EMPTY);
  145. }
  146.     /* let's move on to the next used RBD */
  147.     pDrvCtrl->rbdIndex = (pDrvCtrl->rbdIndex + 1) % (pDrvCtrl->rbdNum);
  148.     MOT_FEC_LOG (MOT_FEC_DBG_RX, ("motFecRbdClean... Done, n"),
  149.   0, 0, 0, 0, 0, 0);
  150.     }
  151. /**************************************************************************
  152. *
  153. * motFecRbdInit - initialize the receive buffer ring
  154. *
  155. * This routine initializes the receive buffer descriptors ring.
  156. *
  157. * SEE ALSO: motFecTbdInit()
  158. *
  159. * RETURNS: OK, or ERROR if not enough clusters were available.
  160. */
  161. LOCAL STATUS motFecRbdInit
  162.     (
  163.     DRV_CTRL *  pDrvCtrl        /* pointer to DRV_CTRL structure */
  164.     )
  165.     {
  166.     char * pData = NULL; /* a rx data pointer */
  167.     char * pBuf = NULL; /* a rx data pointer */
  168.     MOT_FEC_RBD_ID pRbd = NULL; /* generic rbd pointer */
  169.     UINT16 ix; /* a counter */
  170.     /* the receive ring is located right after the transmit one */
  171.     pDrvCtrl->rbdBase = pRbd = (MOT_FEC_RBD_ID) (pDrvCtrl->pBufBase
  172.  + MOT_FEC_TBD_MEM (pDrvCtrl));
  173.     for (ix = 0; ix < pDrvCtrl->rbdNum; ix++)
  174. {
  175. /* get a cluster buffer from the pool */
  176. if ((pBuf = NET_BUF_ALLOC()) == NULL)
  177.     return (ERROR);
  178. /*
  179.  * fill each buffer with en entire frame and make it available
  180.  * for the receiver. Do not activate the receiver yet.
  181.  */
  182. MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF,
  183.     MOT_FEC_RBD_EMPTY);
  184. MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_LEN_OFF, 0);
  185. /*
  186.  * what we need to do here is to save the cluster pointer
  187.  * for use by the net pool later. We won't be using that
  188.  * cluster as is, because the FEC requires receive buffers
  189.  * being aligned by 16. So we move that cluster pointer to
  190.  * the next 16-byte aligned boundary, and program the chip
  191.  * with that value. When we receive the packet, we'll have
  192.  * to join the saved cluster pointer to the mBlk.
  193.  */
  194. pDrvCtrl->rxBuf [ix] = (UCHAR *) pBuf;
  195. pData = (char *) NET_TO_MOT_FEC_BUF (pBuf);
  196. MOT_FEC_BD_LONG_WR (pRbd, MOT_FEC_BD_ADDR_OFF, (UINT32) pData);
  197. /* move on to the next RBD */
  198. pRbd += MOT_FEC_RBD_SZ;
  199. }
  200.     /* have the last RBD to close the ring */
  201.     pRbd -= MOT_FEC_RBD_SZ;
  202.     MOT_FEC_BD_WORD_WR (pRbd, MOT_FEC_BD_STAT_OFF,
  203. (MOT_FEC_RBD_WRAP | MOT_FEC_RBD_EMPTY));
  204.     return (OK);
  205.     }
  206. /**************************************************************************
  207. *
  208. * motFecBdFree - free the receive buffers
  209. *
  210. * This routine frees the netpool clusters associated with the receive
  211. * buffer descriptors ring. It is called by motFecStop(), in order to
  212. * properly release the driver's resources when the device is stopped.
  213. *
  214. * SEE ALSO: motFecStop()
  215. *
  216. * RETURNS: OK, always.
  217. */
  218. LOCAL STATUS motFecBdFree
  219.     (
  220.     DRV_CTRL *  pDrvCtrl        /* pointer to DRV_CTRL structure */
  221.     )
  222.     {
  223.     MOT_FEC_RBD_ID pRbd = NULL; /* generic rbd pointer */
  224.     UINT16 ix; /* a counter */
  225.     pRbd = (MOT_FEC_RBD_ID) (pDrvCtrl->rbdBase);
  226.     for (ix = 0; ix < pDrvCtrl->rbdNum; ix++)
  227. {
  228. /* return the cluster buffer to the pool */
  229. if ((pDrvCtrl->rxBuf [ix]) != NULL)
  230.     NET_BUF_FREE ((pDrvCtrl->rxBuf [ix]));
  231. pRbd += MOT_FEC_RBD_SZ;
  232. }
  233.     /* free the transmit poll buffer */
  234.     if ((pDrvCtrl->pTxPollBuf) != NULL)
  235. NET_BUF_FREE ((UCHAR *) (pDrvCtrl->pTxPollBuf));
  236.     return (OK);
  237.     }
  238. /**************************************************************************
  239. *
  240. * motFecPrePhyConfig - configure the chip before the PHY is initialized
  241. *
  242. * This routine programs all the CSRs that are not concerned with the
  243. * PHY configuration. It follows closely but not entirely the
  244. * initialization sequence recommended in the FEC User's Manual.
  245. *
  246. * SEE ALSO: motFecPostPhyConfig()
  247. *
  248. * RETURNS: OK, always.
  249. */
  250. LOCAL STATUS motFecPrePhyConfig
  251.     (
  252.     DRV_CTRL *  pDrvCtrl        /* pointer to DRV_CTRL structure */
  253.     )
  254.     {
  255.     UINT32 csrVal = 0; /* holder for the CSR value */
  256.     UINT32 csr0Val = 0; /* holder for the CSR0 value */
  257.     UINT32 csr1Val = 0; /* holder for the CSR1 value */
  258.     static BOOL first = TRUE; /* first initialization */
  259.     UINT32      miiSpeed; /* calculated value for MII_SPEED */
  260.     /*
  261.      * we enable the following event interrupts:
  262.      * heartbeat check fail, only if the user requested it;
  263.      * tx and rx babbling errors;
  264.      * tx and rx frame completion;
  265.      * graceful transmit command;
  266.      * mii management interface frame completion;
  267.      * U-bus access error.
  268.      */
  269.     if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_HBC))
  270. {
  271. csrVal |= MOT_FEC_EVENT_HB;
  272. MOT_FEC_LOG (MOT_FEC_DBG_START,
  273.      ("motFecPrePhyConfig: heartbeat control n"),
  274.      0, 0, 0, 0, 0, 0);
  275. }
  276.     else
  277. csrVal &= ~MOT_FEC_EVENT_HB;
  278.     csrVal |= (MOT_FEC_EVENT_GRA | MOT_FEC_EVENT_MII | MOT_FEC_EVENT_TXF |
  279.        MOT_FEC_EVENT_RXF | MOT_FEC_EVENT_BABR | MOT_FEC_EVENT_BABT |
  280.        MOT_FEC_EVENT_BERR);
  281.     MOT_FEC_CSR_WR (MOT_FEC_MASK_OFF, csrVal);
  282.     /* save the interrupt mask register */
  283.     pDrvCtrl->intMask = csrVal;
  284.     /* clear all interrupts */
  285.     MOT_FEC_CSR_WR (MOT_FEC_EVENT_OFF, MOT_FEC_EVENT_MSK);
  286.     /* set the interrupt level */
  287.     MOT_FEC_CSR_WR (MOT_FEC_VEC_OFF, (pDrvCtrl->ilevel << MOT_FEC_LVL_SHIFT));
  288.     if (pDrvCtrl->fifoTxBase != NONE)
  289. MOT_FEC_CSR_WR (MOT_FEC_TX_FIFO_OFF, pDrvCtrl->fifoTxBase);
  290.     if (pDrvCtrl->fifoRxBase != NONE)
  291. MOT_FEC_CSR_WR (MOT_FEC_RX_FIFO_OFF, pDrvCtrl->fifoRxBase);
  292.     /* program the individual enet address */
  293.     if (motFecAddrRegValGet (pDrvCtrl, &csr0Val, &csr1Val) != OK)
  294. return (ERROR);
  295.     MOT_FEC_CSR_WR (MOT_FEC_ADDR_L_OFF, csr0Val);
  296.     MOT_FEC_CSR_WR (MOT_FEC_ADDR_H_OFF, csr1Val);
  297.     /* reset the hash table */
  298.     /* question: does muxDevStop/Start re-init the multi table? */
  299.     if (first)
  300. {
  301. first = FALSE;
  302. MOT_FEC_CSR_WR (MOT_FEC_HASH_L_OFF, 0);
  303. MOT_FEC_CSR_WR (MOT_FEC_HASH_H_OFF, 0);
  304. }
  305.     /*
  306.      * if no clock speed is defined, assume a clock speed of 50 MHz.
  307.      * Otherwise, derive the MII clock speed according to the formula
  308.      * MII_SPEED = ceil(pDrvCtrl->clockSpeed / (2 * MII_CLOCK_MAX))
  309.      */
  310.     if (pDrvCtrl->clockSpeed == 0)
  311. miiSpeed = MOT_FEC_MII_SPEED_50;
  312.     else
  313. miiSpeed = (pDrvCtrl->clockSpeed + (2 * MOT_FEC_MII_CLOCK_MAX) - 1) /
  314.    (2 * MOT_FEC_MII_CLOCK_MAX);
  315.     /* MII_SPEED is left-shifted in the MII_SPEED register */
  316.     MOT_FEC_CSR_WR (MOT_FEC_MII_SPEED_OFF, miiSpeed << MOT_FEC_MII_SPEED_SHIFT);
  317.     /* program the max receive buffer length */
  318.     MOT_FEC_CSR_WR (MOT_FEC_RX_BUF_OFF, MOT_FEC_MAX_RX_BUF);
  319.     /* program the receive and transmit rings registers */
  320.     MOT_FEC_CSR_WR (MOT_FEC_RX_START_OFF, (UINT32) (pDrvCtrl->rbdBase));
  321.     MOT_FEC_CSR_WR (MOT_FEC_TX_START_OFF, (UINT32) (pDrvCtrl->tbdBase));
  322.     MOT_FEC_CSR_WR (MOT_FEC_SDMA_OFF, MOT_FEC_SDMA_DATA_BE |
  323.       MOT_FEC_SDMA_BD_BE |
  324.       MOT_FEC_SDMA_FUNC_0);
  325.     MOT_FEC_CSR_WR (MOT_FEC_RX_FR_OFF, MOT_FEC_BUF_V_LEN);
  326.     return (OK);
  327.     }
  328. /**************************************************************************
  329. *
  330. * motFecPostPhyConfig - configure the chip after the PHY is initialized
  331. *
  332. * This routine programs all the CSRs that are concerned with the
  333. * PHY configuration.
  334. *
  335. * SEE ALSO: motFecPrePhyConfig()
  336. *
  337. * RETURNS: OK, always.
  338. */
  339. LOCAL STATUS motFecPostPhyConfig
  340.     (
  341.     DRV_CTRL *  pDrvCtrl        /* pointer to DRV_CTRL structure */
  342.     )
  343.     {
  344.     UINT32 rxCtrlVal; /* holder for the rx CSR value */
  345.     UINT32 txCtrlVal; /* holder for the tx CSR value */
  346.     /* get the proper value for the rx CSR and program it accordingly */
  347.     if (motFecRxCtrlRegValGet (pDrvCtrl, &rxCtrlVal) == ERROR)
  348. return (ERROR);
  349.     MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF, rxCtrlVal);
  350.     /*
  351.      * get the proper value for the tx CSR and program it accordingly.
  352.      * At this point we do not have to check whether the FEC is
  353.      * active, as we already know.
  354.      */
  355.     if (motFecTxCtrlRegValGet (pDrvCtrl, &txCtrlVal) == ERROR)
  356. return (ERROR);
  357.     MOT_FEC_CSR_WR (MOT_FEC_TX_CTRL_OFF, txCtrlVal);
  358.     /*
  359.      * disable the MII management interface, as we do not
  360.      * need to change the MII setting at any time.
  361.      */
  362.     MOT_FEC_CSR_WR (MOT_FEC_MII_SPEED_OFF, MOT_FEC_MII_MAN_DIS);
  363.     return (OK);
  364.     }
  365. /**************************************************************************
  366. *
  367. * motFecRxCtrlRegValGet - get the proper value for the receive CSR
  368. *
  369. * This routine finds out the proper value to be programmed in the
  370. * receive CSR by looking at some of the user/driver flags. It deals
  371. * with options like promiscous mode, full duplex, loopback and
  372. * the physical serial interface.
  373. *
  374. * This routine does not program the receive CSR.
  375. *
  376. * SEE ALSO: motFecTxCtrlRegValGet(), motFecPostPhyConfig()
  377. *
  378. * RETURNS: OK or ERROR if rxCtrlVal is NULL pointer.
  379. */
  380. LOCAL STATUS motFecRxCtrlRegValGet
  381.     (
  382.     DRV_CTRL *  pDrvCtrl, /* pointer to DRV_CTRL structure */
  383.     UINT32 * rxCtrlVal /* holder for the rx CSR value */
  384.     )
  385.     {
  386.     /* Initialize holder for the rx CSR value */
  387.     if (rxCtrlVal == NULL)
  388.         {
  389.         MOT_FEC_LOG (MOT_FEC_DBG_START,
  390.                      ("motFecRxCtrlRegValGet: rxCtrlVal is NULL n"),
  391.                      0, 0, 0, 0, 0, 0);
  392.         return (ERROR);
  393.         }
  394.     else
  395.         *rxCtrlVal = 0;
  396.     /* deal with promiscous mode */
  397.     if (MOT_FEC_FLAG_ISSET (MOT_FEC_PROM))
  398. {
  399. *rxCtrlVal |= MOT_FEC_RX_CTRL_PROM;
  400. MOT_FEC_LOG (MOT_FEC_DBG_START,
  401.      ("motFecRxCtrlRegValGet: promiscous mode n"),
  402.      0, 0, 0, 0, 0, 0);
  403. }
  404.     else
  405. *rxCtrlVal &= ~MOT_FEC_RX_CTRL_PROM;
  406.     /*
  407.      * enable full duplex mode if the PHY was configured
  408.      * to work in full duplex mode.
  409.      */
  410.     if (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD))
  411. {
  412. *rxCtrlVal &= ~MOT_FEC_RX_CTRL_DRT;
  413. MOT_FEC_LOG (MOT_FEC_DBG_START,
  414.      ("motFecRxCtrlRegValGet: full duplex n"),
  415.      0, 0, 0, 0, 0, 0);
  416. }
  417.     else
  418. *rxCtrlVal |= MOT_FEC_RX_CTRL_DRT;
  419.     /*
  420.      * enable the 7-wire serial interface if the
  421.      * related user flag was set.
  422.      */
  423.     if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_SER))
  424. {
  425. *rxCtrlVal &= ~MOT_FEC_RX_CTRL_MII;
  426. MOT_FEC_LOG (MOT_FEC_DBG_START,
  427.      ("motFecRxCtrlRegValGet: serial interface n"),
  428.      0, 0, 0, 0, 0, 0);
  429. }
  430.     else
  431. *rxCtrlVal |= MOT_FEC_RX_CTRL_MII;
  432.     /*
  433.      * if the user wishes to go in loopback mode,
  434.      * enable it. Also enable receiver and transmitter
  435.      * to work independently from each other.
  436.      */
  437.     if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_LOOP))
  438. {
  439. *rxCtrlVal |= MOT_FEC_RX_CTRL_LOOP;
  440. *rxCtrlVal &= ~MOT_FEC_RX_CTRL_DRT;
  441. MOT_FEC_LOG (MOT_FEC_DBG_START,
  442.      ("motFecRxCtrlRegValGet: loopback mode n"),
  443.      0, 0, 0, 0, 0, 0);
  444. }
  445.     else
  446. *rxCtrlVal &= ~MOT_FEC_RX_CTRL_LOOP;
  447.     return (OK);
  448.     }
  449. /**************************************************************************
  450. *
  451. * motFecTxCtrlRegValGet - get the proper value for the transmit CSR
  452. *
  453. * This routine finds out the proper value to be programmed in the
  454. * transmit CSR by looking at some of the user/driver flags. It deals
  455. * with options like full duplex mode and the heartbeat control.
  456. *
  457. * This routine does not program the transmit CSR.
  458. *
  459. * RETURNS: OK or ERROR if txCtrlVal is NULL pointer.
  460. *
  461. * SEE ALSO: motFecRxCtrlRegValGet(), motFecPostPhyConfig()
  462. *
  463. */
  464. LOCAL STATUS motFecTxCtrlRegValGet
  465.     (
  466.     DRV_CTRL *  pDrvCtrl, /* pointer to DRV_CTRL structure */
  467.     UINT32 * txCtrlVal /* holder for the tx CSR value */
  468.     )
  469.     {
  470.     /* Initialize holder for the tx CSR value */
  471.     if (txCtrlVal == NULL)
  472.         {
  473.         MOT_FEC_LOG (MOT_FEC_DBG_START,
  474.                      ("motFecTxCtrlRegValGet: txCtrlVal is NULL n"),
  475.                      0, 0, 0, 0, 0, 0);
  476.         return (ERROR);
  477.         }
  478.     else
  479.         *txCtrlVal = 0;
  480.     /* deal with the heartbeat control */
  481.     if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_HBC))
  482. {
  483. *txCtrlVal |= MOT_FEC_TX_CTRL_HBC;
  484. MOT_FEC_LOG (MOT_FEC_DBG_START,
  485.      ("motFecTxCtrlRegValGet: heartbeat control n"),
  486.      0, 0, 0, 0, 0, 0);
  487. }
  488.     else
  489. *txCtrlVal &= ~MOT_FEC_TX_CTRL_HBC;
  490.     /*
  491.      * enable full duplex mode if the PHY was configured
  492.      * to work in full duplex mode.
  493.      */
  494.     if (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD))
  495. {
  496. *txCtrlVal |= MOT_FEC_TX_CTRL_FD;
  497. MOT_FEC_LOG (MOT_FEC_DBG_START,
  498.      ("motFecTxCtrlRegValGet: full duplex n"),
  499.      0, 0, 0, 0, 0, 0);
  500. }
  501.     else
  502. *txCtrlVal &= ~MOT_FEC_TX_CTRL_FD;
  503.     return (OK);
  504.     }
  505. /**************************************************************************
  506. *
  507. * motFecAddrRegValGet - get the values to program in CSR0 and CSR1
  508. *
  509. * This routine finds out the proper values to be programmed in the
  510. * two 32-bit perfect match address registers (CSR0 and CSR1).
  511. *
  512. * This routine does not program neither CSR0 nor CSR1.
  513. *
  514. * RETURNS: OK, always.
  515. */
  516. LOCAL STATUS motFecAddrRegValGet
  517.     (
  518.     DRV_CTRL *  pDrvCtrl, /* pointer to DRV_CTRL structure */
  519.     UINT32 * csr0Val, /* holder for the CSR0 value */
  520.     UINT32 * csr1Val /* holder for the CSR1 value */
  521.     )
  522.     {
  523.     char * enetAddr = NULL; /* holder for the enet address */
  524.     /*
  525.      * programming the enet address is done by writing
  526.      * its low-order 4 bytes to CSR0 and its high-order
  527.      * 2 bytes to the MSW of CSR1.
  528.      */
  529.     enetAddr = (char *) MOT_FEC_ADDR_GET (&pDrvCtrl->endObj);
  530.     *csr0Val = * (UINT32 *) enetAddr;
  531.     /*
  532.      * this way we'll zero-out the low-order 16 bits in the
  533.      * CSR, as recommended in the documentation.
  534.      */
  535.     *csr1Val = ((UINT32) (* (UINT16 *) (enetAddr + 4)) << 16);
  536.     return (OK);
  537.     }
  538. /*******************************************************************************
  539. *
  540. * motFecIoctl - interface ioctl procedure
  541. *
  542. * Process an interface ioctl request.
  543. *
  544. * RETURNS: OK, or ERROR.
  545. */
  546. LOCAL int motFecIoctl
  547.     (
  548.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  549.     int         cmd, /* command to process */
  550.     caddr_t     data            /* pointer to data */
  551.     )
  552.     {
  553.     int         error = OK;
  554.     INT8        savedFlags;
  555.     long        value;
  556.     END_OBJ *   pEndObj=&pDrvCtrl->endObj;
  557.     MOT_FEC_LOG (MOT_FEC_DBG_IOCTL,
  558.  ("Ioctl unit=0x%x cmd=%d data=0x%xn"),
  559.  pDrvCtrl->unit, cmd, (int)data, 0, 0, 0);
  560.     switch (cmd)
  561.         {
  562.         case EIOCSADDR:
  563.             if (data == NULL)
  564.                 error = EINVAL;
  565.             else
  566.                 {
  567. UINT32 csr0Val; /* holder for the CSR0 value */
  568. UINT32 csr1Val; /* holder for the CSR1 value */
  569.                 /* Copy and install the new address */
  570. bcopy ((char *) data,
  571.        (char *) MOT_FEC_ADDR_GET (&pDrvCtrl->endObj),
  572.        MOT_FEC_ADDR_LEN_GET (&pDrvCtrl->endObj));
  573. /* stop the FEC */
  574. if (motFecStop (pDrvCtrl) != OK)
  575.     return (ERROR);
  576. /* program the individual enet address */
  577. if (motFecAddrRegValGet (pDrvCtrl, &csr0Val, &csr1Val) != OK)
  578.     return (ERROR);
  579. MOT_FEC_CSR_WR (MOT_FEC_ADDR_L_OFF, csr0Val);
  580. MOT_FEC_CSR_WR (MOT_FEC_ADDR_H_OFF, csr1Val);
  581. /* restart the FEC */
  582. if (motFecStart (pDrvCtrl) != OK)
  583.     return (ERROR);
  584.                 }
  585.             break;
  586.         case EIOCGADDR:
  587.             if (data == NULL)
  588.                 error = EINVAL;
  589.             else
  590. bcopy ((char *) MOT_FEC_ADDR_GET (&pDrvCtrl->endObj),
  591.        (char *) data,
  592.        MOT_FEC_ADDR_LEN_GET (&pDrvCtrl->endObj));
  593.             break;
  594.         case EIOCSFLAGS:
  595.             value = (long) data;
  596.             if (value < 0)
  597.                 {
  598.                 value = -value;
  599.                 value--;
  600.                 END_FLAGS_CLR (pEndObj, value);
  601.                 }
  602.             else
  603.                 END_FLAGS_SET (pEndObj, value);
  604.             MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("endFlags=0x%x n"),
  605.      END_FLAGS_GET(pEndObj),
  606.      0, 0, 0, 0, 0);
  607.             /* handle IFF_PROMISC */
  608.             savedFlags = MOT_FEC_FLAG_GET();
  609.             if (END_FLAGS_ISSET (IFF_PROMISC))
  610. {
  611.                 MOT_FEC_FLAG_SET (MOT_FEC_PROM);
  612. if ((MOT_FEC_FLAG_GET () != savedFlags) &&
  613.     (END_FLAGS_GET (pEndObj) & IFF_UP))
  614.     {
  615.     UINT32 rxCtrlVal;
  616.     /* config down */
  617.     END_FLAGS_CLR (pEndObj, IFF_UP | IFF_RUNNING);
  618.     /* program the rx CSR to promiscous mode */
  619.     if (motFecRxCtrlRegValGet (pDrvCtrl, &rxCtrlVal) == ERROR)
  620. return (ERROR);
  621.     MOT_FEC_CSR_WR (MOT_FEC_RX_CTRL_OFF, rxCtrlVal);
  622.     /* config up */
  623.     END_FLAGS_SET (pEndObj, IFF_UP | IFF_RUNNING);
  624.     }
  625. }
  626.             else
  627.                 MOT_FEC_FLAG_CLEAR (MOT_FEC_PROM);
  628.             /* handle IFF_MULTICAST */
  629.             if (END_FLAGS_GET(pEndObj) & (IFF_MULTICAST))
  630.                 MOT_FEC_FLAG_SET (MOT_FEC_MCAST);
  631.             else
  632.                 MOT_FEC_FLAG_CLEAR (MOT_FEC_MCAST);
  633.             MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("EIOCSFLAGS: 0x%x: 0x%xn"),
  634.      pEndObj->flags, savedFlags,
  635.      0, 0, 0, 0);
  636.             break;
  637.         case EIOCGFLAGS:
  638.             MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("EIOCGFLAGS: 0x%x: 0x%xn"),
  639.     pEndObj->flags, *(long *)data,
  640.     0, 0, 0, 0);
  641.             if (data == NULL)
  642.                 error = EINVAL;
  643.             else
  644.                 *(long *)data = END_FLAGS_GET(pEndObj);
  645.             break;
  646.         case EIOCMULTIADD:
  647.             error = motFecMCastAddrAdd (pDrvCtrl, (char *) data);
  648.             break;
  649.         case EIOCMULTIDEL:
  650.             error = motFecMCastAddrDel (pDrvCtrl, (char *) data);
  651.             break;
  652.         case EIOCMULTIGET:
  653.             error = motFecMCastAddrGet (pDrvCtrl, (MULTI_TABLE *) data);
  654.             break;
  655.         case EIOCPOLLSTART:
  656.     MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("IOCTL call motFecPollStartn"),
  657.     0, 0, 0, 0, 0, 0);
  658.             motFecPollStart (pDrvCtrl);
  659.             break;
  660.         case EIOCPOLLSTOP:
  661.     MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("IOCTL call motFecPollStopn"),
  662.     0, 0, 0, 0, 0, 0);
  663.             motFecPollStop (pDrvCtrl);
  664.             break;
  665.         case EIOCGMIB2:
  666.             if (data == NULL)
  667.                 error=EINVAL;
  668.             else
  669. bcopy ((char *) &pEndObj->mib2Tbl, (char *) data,
  670. sizeof (pEndObj->mib2Tbl));
  671.             break;
  672.         default:
  673.             MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("INVALID IO COMMAND!! n"),
  674.      0, 0, 0, 0, 0, 0);
  675.             error = EINVAL;
  676.         }
  677.     return (error);
  678.     }
  679. /**************************************************************************
  680. *
  681. * motFecPhyInit - initialize and configure the PHY devices
  682. *
  683. * This routine scans, initializes and configures PHY devices.
  684. *
  685. * This routine is called from the driver's Start routine to
  686. * perform media inialization and configuration. To access the PHY
  687. * device, it uses the routines: motFecPhyRead(), motFecPhyWrite(),
  688. * which exploit the support to the MII interface built-in in the
  689. * FEC.
  690. *
  691. * Before it attempts to bring the link up, this routine checks the
  692. * phyInfo structure in the driver control structure for a device that
  693. * needs to be electrically isolated by the MII interface; if a valid
  694. * device is found it is isolated.
  695. *
  696. * The routine then scans for all possible PHY addresses in the range 0-31,
  697. * checking for an MII-compliant PHY, and attempts to  establish a
  698. * valid link for it. If none is found, ERROR is returned.
  699. * Typically PHYs are scanned from address 0, but if the user specifies
  700. * an alternative start PHY address via the parameter phyAddr in the
  701. * driver's load string, all (32) PHYs are scanned in order starting
  702. * with the specified PHY address.
  703. *
  704. * This routine offers two strategies to select a PHY and establish a
  705. * valid link. The default strategy is to use the standard 802.3 style
  706. * auto-negotiation, where both link partners negotiate all their
  707. * technology abilities at the same time, and the highest common
  708. * denominator ability is chosen. Before the auto-negotiation
  709. * is started, the next-page exchange mechanism is disabled.
  710. *
  711. * The user can prevent the PHY from negotiating certain abilities via
  712. * userFlags -- <MOT_FEC_USR_PHY_NO_FD>, <MOT_FEC_USR_PHY_NO_100>,
  713. * <MOT_FEC_USR_PHY_NO_HD>, and <MOT_FEC_USR_PHY_NO_10>. When
  714. * <MOT_FEC_USR_PHY_NO_FD> is specified, full duplex will not be
  715. * negotiated; when <MOT_FEC_USR_PHY_NO_HD> is specified half duplex
  716. * will not be negotiated, when <MOT_FEC_USR_PHY_NO_100> is specified,
  717. * 100Mbps ability will not negotiated; when <MOT_FEC_USR_PHY_NO_10>
  718. * 10Mbps ability will not be negotiated.
  719. *
  720. * When <MOT_FEC_USR_PHY_TBL> is set in the user flags, the BSP specific
  721. * table <motFecPhyAnOrderTbl> is used to obtain the list, and the order
  722. * of technology abilities to be negotiated.
  723. * The entries in this table are ordered such that entry 0 is the
  724. * highest priority, entry 1 in next and so on. Entries in this table
  725. * may be repeated, and multiple technology abilities can
  726. * be OR'd to create a single  entry. If a PHY cannot support a
  727. * ability in an entry, that entry is ignored. Currently, only one
  728. * table per driver is supported.
  729. *
  730. * If no PHY provides a valid link, the PHYs are scanned again in the
  731. * same order, and the first PHY that supports the default abilities
  732. * defined in the <phyDefMode> of the Load string will be selected,
  733. * regardless of the link status.
  734. *
  735. * RETURNS: OK or ERROR if the PHY could not be initialised.
  736. *
  737. */
  738. LOCAL STATUS motFecPhyInit
  739.     (
  740.     DRV_CTRL *  pDrvCtrl       /* pointer to DRV_CTRL structure */
  741.     )
  742.     {
  743.     UINT8 phyAddr; /* address of a PHY */
  744.     UINT8 isoPhyAddr; /* address of a PHY to be isolated */
  745.     UINT8 ix; /* an index */
  746.     int retVal; /* convenient holder for return value */
  747.     BOOL found = FALSE; /* no PHY has been found */
  748.     /* isolate the PHY in the phyInfo structure */
  749.     isoPhyAddr = pDrvCtrl->phyInfo->isoPhyAddr;
  750.     if (isoPhyAddr != MOT_FEC_PHY_NULL)
  751. {
  752. /* check the PHY is there */
  753. retVal = motFecMiiProbe (pDrvCtrl, isoPhyAddr);
  754. if (retVal == ERROR)
  755.     return (ERROR);
  756. if (retVal == OK)
  757.     if (motFecMiiIsolate (pDrvCtrl, isoPhyAddr) == ERROR)
  758. return (ERROR);
  759. }
  760.     /*
  761.      * there may be several PHYs, with distinct logical addresses
  762.      * and these can be as high as 31. Start with the one the
  763.      * user suggested and, in case of failure, scan the whole range.
  764.      */
  765.     for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
  766. {
  767. phyAddr = (ix + pDrvCtrl->phyInfo->phyAddr) % MII_MAX_PHY_NUM;
  768. /* check this is not the isolated PHY */
  769. if (phyAddr == isoPhyAddr)
  770.     continue;
  771. /* check the PHY is there */
  772. retVal = motFecMiiProbe (pDrvCtrl, phyAddr);
  773. if (retVal == ERROR)
  774.     return (ERROR);
  775. if (retVal == MOT_FEC_PHY_NULL)
  776.     continue;
  777. found = TRUE;
  778. /* run some diagnostics */
  779. if (motFecMiiDiag (pDrvCtrl, phyAddr) != OK)
  780.     return (ERROR);
  781. /*
  782.  * start the auto-negotiation process,
  783.  * unless the user dictated the contrary.
  784.  */
  785. if (pDrvCtrl->phyInfo->phyFlags & MOT_FEC_PHY_AUTO)
  786.     if (motFecMiiAnRun (pDrvCtrl, phyAddr) == OK)
  787. return (OK);
  788. /*
  789.  * the auto-negotiation process did not succeed
  790.  * in establishing a valid link: try to do it
  791.  * manually, enabling as high priority abilities
  792.  * as you can.
  793.  */
  794. if (motFecMiiModeForce (pDrvCtrl, phyAddr) == OK)
  795.     return (OK);
  796. /*
  797.  * Trying to force a specific operating mode was
  798.  * unsuccessful, too. Force default parameters:
  799.  * field phyDefMode in the PHY info structure.
  800.  */
  801. if (motFecMiiDefForce (pDrvCtrl, phyAddr) == OK)
  802.     return (OK);
  803. }
  804.     if (!(found))
  805. return (ERROR);
  806.     /* if we're here, none of the PHYs could be initialized */
  807.        logMsg ("motFecPhyInit check cable connection n",
  808.         0, 0, 0, 0, 0, 0);
  809.     /* try to establish a default operating mode, do not check the link! */
  810.     for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
  811. {
  812. phyAddr = (ix + pDrvCtrl->phyInfo->phyAddr) % MII_MAX_PHY_NUM;
  813. /* check this is not the isolated PHY */
  814. if (phyAddr == isoPhyAddr)
  815.     continue;
  816. /* check the PHY is there */
  817. retVal = motFecMiiProbe (pDrvCtrl, phyAddr);
  818. if (retVal == ERROR)
  819.     return (ERROR);
  820. if (retVal == MOT_FEC_PHY_NULL)
  821.     continue;
  822. /* return OK even if the link is not up */
  823. retVal = motFecMiiDefForce (pDrvCtrl, phyAddr);
  824. if (retVal == ERROR)
  825.     return (ERROR);
  826. /* if the PHY does not have the default abilities... */
  827. if (retVal == MOT_FEC_PHY_NO_ABLE)
  828.     continue;
  829. return (OK);
  830. }
  831.     return (ERROR);
  832.     }
  833. /**************************************************************************
  834. *
  835. * motFecMiiProbe - probe the PHY device
  836. *
  837. * This routine probes the PHY device by reading its control register.
  838. *
  839. * RETURNS: OK, ERROR in case of fatal errors, or MOT_FEC_PHY_NULL, if
  840. * the device was not found.
  841. */
  842. LOCAL STATUS motFecMiiProbe
  843.     (
  844.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  845.     UINT8 phyAddr /* the PHY being read */
  846.     )
  847.     {
  848.     UINT8 regAddr; /* the PHY's register being read */
  849.     UINT16 data; /* data to be written to the control reg */
  850.     regAddr = MII_CTRL_REG;
  851.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &data) != OK)
  852. return (ERROR);
  853.     if (data == 0xffff)
  854. return (MOT_FEC_PHY_NULL);
  855.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiProbe... endsn"),
  856.    0, 0, 0, 0, 0, 0);
  857.     return (OK);
  858.     }
  859. /**************************************************************************
  860. *
  861. * motFecPhyPreInit - initialize some fields in the phy info structure
  862. *
  863. * This routine initializes some fields in the phy info structure,
  864. * for use of the motFecPhyInit() routine.
  865. *
  866. * RETURNS: OK, always.
  867. */
  868. LOCAL STATUS motFecPhyPreInit
  869.     (
  870.     DRV_CTRL *  pDrvCtrl       /* pointer to DRV_CTRL structure */
  871.     )
  872.     {
  873.     /* set some default values */
  874.     pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
  875.     pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
  876.     pDrvCtrl->phyInfo->phyFlags = 0;
  877.     /* handle some user-to-physical flags */
  878.     if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_AN)))
  879. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_AUTO);
  880.     else
  881. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_AUTO);
  882.     if (MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_TBL))
  883. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_TBL);
  884.     else
  885. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_TBL);
  886.     if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_100)))
  887. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_100);
  888.     else
  889. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
  890.     if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_FD)))
  891. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_FD);
  892.     else
  893. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
  894.     if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_10)))
  895. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_10);
  896.     else
  897. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_10);
  898.     if (!(MOT_FEC_USR_FLAG_ISSET (MOT_FEC_USR_PHY_NO_HD)))
  899. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_HD);
  900.     else
  901. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_HD);
  902.     /* mark it as pre-initilized */
  903.     MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_PRE_INIT);
  904.     return (OK);
  905.     }
  906. /**************************************************************************
  907. *
  908. * motFecMiiRead - read the MII register
  909. *
  910. * This routine reads the register specified by <phyReg> in the PHY device
  911. * whose address is <phyAddr>. The value read is returned in the location
  912. * pointed to by <retVal>.
  913. *
  914. * SEE ALSO: motFecMiiWrite()
  915. *
  916. * RETURNS: OK, always.
  917. *
  918. */
  919. LOCAL STATUS motFecMiiRead
  920.     (
  921.     DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
  922.     UINT8 phyAddr, /* the PHY being read */
  923.     UINT8 regAddr, /* the PHY's register being read */
  924.     UINT16 *retVal /* the value read */
  925.     )
  926.     {
  927.     UINT32 reg; /* convenient holder for the PHY register */
  928.     UINT32 phy; /* convenient holder for the PHY */
  929.     UINT32 miiVal; /* value written/read to/from the FEC's MII register */
  930.     /*
  931.      * reading from any PHY's register is done by properly
  932.      * programming the FEC's MII data register.
  933.      */
  934.     reg = regAddr << MOT_FEC_MII_RA_SHIFT;
  935.     phy = phyAddr << MOT_FEC_MII_PA_SHIFT;
  936.     miiVal = (MOT_FEC_MII_ST | MOT_FEC_MII_OP_RD | MOT_FEC_MII_TA |
  937.       phy | reg);
  938.     MOT_FEC_CSR_WR (MOT_FEC_MII_DATA_OFF, miiVal);
  939.     /* wait for the related interrupt */
  940.     MOT_FEC_MII_SEM_TAKE;
  941.     /* it's now safe to read the PHY's register */
  942.     MOT_FEC_CSR_RD (MOT_FEC_MII_DATA_OFF, miiVal);
  943.     *retVal = (UINT16) miiVal;
  944.     return (OK);
  945.     }
  946. /**************************************************************************
  947. *
  948. * motFecMiiWrite - write to the MII register
  949. *
  950. * This routine writes the register specified by <phyReg> in the PHY device,
  951. * whose address is <phyAddr>, with the 16-bit value included in <data>.
  952. *
  953. * SEE ALSO: motFecMiiRead()
  954. *
  955. * RETURNS: OK, always.
  956. */
  957. LOCAL STATUS motFecMiiWrite
  958.     (
  959.     DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
  960.     UINT8 phyAddr, /* the PHY being written */
  961.     UINT8 regAddr, /* the PHY's register being written */
  962.     UINT16 data /* the value written to the PHY register */
  963.     )
  964.     {
  965.     UINT32 reg; /* convenient holder for the PHY register */
  966.     UINT32 phy; /* convenient holder for the PHY */
  967.     UINT32 miiVal; /* value written to the mii reg */
  968.     reg = regAddr << MOT_FEC_MII_RA_SHIFT;
  969.     phy = phyAddr << MOT_FEC_MII_PA_SHIFT;
  970.     miiVal = (MOT_FEC_MII_ST | MOT_FEC_MII_OP_WR | MOT_FEC_MII_TA |
  971.       phy | reg | data);
  972.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiWrite reg=%d n
  973.    PHY=%d data=0x%xn"),
  974.    regAddr, phyAddr, miiVal, 0, 0, 0);
  975.     MOT_FEC_CSR_WR (MOT_FEC_MII_DATA_OFF, miiVal);
  976.     /* wait for the related interrupt */
  977.     MOT_FEC_MII_SEM_TAKE;
  978.     return (OK);
  979.     }
  980. /*******************************************************************************
  981. *
  982. * motFecMiiDiag - run some diagnostics
  983. *
  984. * This routine runs some diagnostics on the PHY whose address is
  985. * specified in the parameter <phyAddr>.
  986. *
  987. * RETURNS: OK or ERROR.
  988. */
  989. LOCAL STATUS motFecMiiDiag
  990.     (
  991.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  992.     UINT8 phyAddr /* address of a PHY */
  993.     )
  994.     {
  995.     UINT16 data; /* data to be written to the control reg */
  996.     UINT8 regAddr; /* PHY register */
  997.     UINT16 ix = 0; /*  a counter */
  998.     /* reset the PHY */
  999.     regAddr = MII_CTRL_REG;
  1000.     data = MII_CR_RESET;
  1001.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
  1002. return (ERROR);
  1003.     while (ix++ < MOT_FEC_PHY_MAX_WAIT)
  1004. {
  1005. taskDelay (1);
  1006. if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &data) != OK)
  1007.     return (ERROR);
  1008. if (!(data & MII_CR_RESET))
  1009.     break;
  1010. }
  1011.     if (ix >= MOT_FEC_PHY_MAX_WAIT)
  1012. {
  1013. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDiag reset failn"),
  1014.        0, 0, 0, 0, 0, 0);
  1015. return (ERROR);
  1016. }
  1017.     /* isolate the PHY */
  1018.     if (motFecMiiIsolate (pDrvCtrl, phyAddr) == ERROR)
  1019. return (ERROR);
  1020.     /* re-enable the chip */
  1021.     data = MII_CR_NORM_EN;
  1022.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
  1023. return (ERROR);
  1024.     /* check isolate bit is deasserted */
  1025.     ix = 0;
  1026.     while (ix++ < MOT_FEC_PHY_MAX_WAIT)
  1027. {
  1028. taskDelay (1);
  1029. if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &data) != OK)
  1030.     return (ERROR);
  1031. if (!(data & MII_CR_ISOLATE))
  1032.     break;
  1033. }
  1034.     if (ix >= MOT_FEC_PHY_MAX_WAIT)
  1035. {
  1036. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDiag de-isolate failn"),
  1037.        0, 0, 0, 0, 0, 0);
  1038. return (ERROR);
  1039. }
  1040.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDiag... endsn"),
  1041.    0, 0, 0, 0, 0, 0);
  1042.     return (OK);
  1043.     }
  1044. /*******************************************************************************
  1045. *
  1046. * motFecMiiIsolate - isolate the PHY device
  1047. *
  1048. * This routine isolates the PHY device whose address is specified in
  1049. * the parameter <isoPhyAddr>.
  1050. *
  1051. * RETURNS: OK or ERROR.
  1052. */
  1053. LOCAL STATUS motFecMiiIsolate
  1054.     (
  1055.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1056.     UINT8 isoPhyAddr /* address of a PHY to be isolated */
  1057.     )
  1058.     {
  1059.     UINT8 regAddr; /* PHY register */
  1060.     UINT16 ix = 0; /*  a counter */
  1061.     UINT16 data; /* data to be written to the control reg */
  1062.     if (isoPhyAddr == MOT_FEC_PHY_NULL)
  1063. return (OK);
  1064.     data = MII_CR_ISOLATE;
  1065.     regAddr = MII_CTRL_REG;
  1066.     if (motFecMiiWrite (pDrvCtrl, isoPhyAddr, regAddr, data) != OK)
  1067. return (ERROR);
  1068.     /* check isolate bit is asserted */
  1069.     ix = 0;
  1070.     while (ix++ < MOT_FEC_PHY_MAX_WAIT)
  1071. {
  1072. taskDelay (1);
  1073. if (motFecMiiRead (pDrvCtrl, isoPhyAddr, regAddr, &data) != OK)
  1074.     return (ERROR);
  1075. if ((data & MII_CR_ISOLATE))
  1076.     break;
  1077. }
  1078.     if (ix >= MOT_FEC_PHY_MAX_WAIT)
  1079. {
  1080. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiIsolate failn"),
  1081.        0, 0, 0, 0, 0, 0);
  1082. return (ERROR);
  1083. }
  1084.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiIsolate... endsn"),
  1085.    0, 0, 0, 0, 0, 0);
  1086.     return (OK);
  1087.     }
  1088. /*******************************************************************************
  1089. *
  1090. * motFecMiiAnRun - run the auto-negotiation process
  1091. *
  1092. * This routine runs the auto-negotiation process for the PHY whose
  1093. * address is specified in the parameter <phyAddr>, without enabling the
  1094. * next page function. It also calls motFecMiiAnCheck() to ensure
  1095. * a valid link has been established.
  1096. *
  1097. * RETURNS: OK or ERROR.
  1098. */
  1099. LOCAL STATUS motFecMiiAnRun
  1100.     (
  1101.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1102.     UINT8 phyAddr /* address of a PHY */
  1103.     )
  1104.     {
  1105.     UINT8 regAddr; /* PHY register */
  1106.     UINT16 phyAds; /* holder for the PHY ads register value */
  1107.     UINT16 status; /* PHY auto-negotiation status */
  1108.     UINT16 ix; /* a counter */
  1109.     int retVal; /* holder for return value */
  1110.     regAddr = MII_AN_ADS_REG;
  1111.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyAds) != OK)
  1112. return (ERROR);
  1113.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnRun phyAds=0x%xn"),
  1114.    phyAds, 0, 0, 0, 0, 0);
  1115.     /* disable the next page function */
  1116.     phyAds &= (~MII_NP_NP);
  1117.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, phyAds)
  1118. != OK)
  1119. return (ERROR);
  1120.     /* Read ANER to clear status from previous operations */
  1121.     regAddr = MII_AN_EXP_REG;
  1122.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &status) != OK)
  1123. return (ERROR);
  1124.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnRun expStat=0x%xn"),
  1125.    status, 0, 0, 0, 0, 0);
  1126.     /* Read ANAR */
  1127.     regAddr = MII_AN_ADS_REG;
  1128.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyAds) != OK)
  1129. return (ERROR);
  1130.     /* store the current registers values */
  1131.     pDrvCtrl->phyInfo->miiRegs.phyAds = phyAds;
  1132.     /*
  1133.      * start the auto-negotiation process, possibly
  1134.      * following the order the user dictated.
  1135.      */
  1136.     for (ix = 0; ; ix++)
  1137. {
  1138. if (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_TBL))
  1139.     {
  1140.     /* check we're not at the end of the user table */
  1141.     if ((motFecPhyAnOrderTbl [ix]) == -1)
  1142. return (ERROR);
  1143.     /* just negotiate one ability at a time */
  1144.     phyAds &= ~MII_TECH_MASK;
  1145.     /* translate user settings */
  1146.     phyAds |= miiAnLookupTbl [(motFecPhyAnOrderTbl [ix])];
  1147.     /* check the PHY has the desidered ability */
  1148.     if (!(phyAds & pDrvCtrl->phyInfo->miiRegs.phyAds))
  1149. continue;
  1150.     /* set the ANAR accordingly */
  1151.     regAddr = MII_AN_ADS_REG;
  1152.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, phyAds)
  1153. != OK)
  1154. return (ERROR);
  1155.     }
  1156. else
  1157.     {
  1158.     /* check the PHY flags and possibly mask some abilities off */
  1159.     if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD)))
  1160. phyAds &= ~(MII_TECH_10BASE_FD | MII_TECH_100BASE_TX_FD
  1161.     | MII_TECH_100BASE_T4);
  1162.     if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_HD)))
  1163. phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_100BASE_TX);
  1164.     if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_100)))
  1165. phyAds &= ~(MII_TECH_100BASE_TX | MII_TECH_100BASE_TX_FD
  1166.     | MII_TECH_100BASE_T4);
  1167.     if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_10)))
  1168. phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_10BASE_FD);
  1169.     /* Write ANAR */
  1170.     regAddr = MII_AN_ADS_REG;
  1171.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, phyAds) != OK)
  1172. return (ERROR);
  1173.     /* store the current registers values */
  1174.     pDrvCtrl->phyInfo->miiRegs.phyAds = phyAds;
  1175.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnRun phyAds=0x%xn"),
  1176.    phyAds, 0, 0, 0, 0, 0);
  1177.     }
  1178. /*
  1179.  * start the auto-negotiation process: return
  1180.  * only in case of fatal error.
  1181.  */
  1182. retVal = motFecMiiAnStart (pDrvCtrl, phyAddr);
  1183. if (retVal == ERROR)
  1184.     return (ERROR);
  1185. /*
  1186.  * in case of failure, we return only if we're using
  1187.  * the standard auto-negotiation process.
  1188.  */
  1189. if (retVal == MII_AN_FAIL)
  1190.             {
  1191.     if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_TBL)))
  1192. return (retVal);
  1193.     else
  1194. continue;
  1195.             }
  1196. /* check the negotiation was successful */
  1197. if (motFecMiiAnCheck (pDrvCtrl, phyAddr) == OK)
  1198.     return (OK);
  1199. /*
  1200.  * we are here if the negotiation went wong:
  1201.  * if the user did not force any priority order,
  1202.  * we return ERROR, as all the PHY abilities
  1203.  * were negotiated at once.
  1204.  */
  1205. if (!(MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_TBL)))
  1206.     return (ERROR);
  1207. }
  1208.     return (OK);
  1209.     }
  1210. /*******************************************************************************
  1211. *
  1212. * motFecMiiAnStart - start the auto-negotiation process
  1213. *
  1214. * This routine starts the auto-negotiation process for the PHY whose
  1215. * address is specified in the parameter <phyAddr>.
  1216. *
  1217. * RETURNS: OK, ERROR in case of fatal errors or MII_AN_FAIL, if the
  1218. * auto-negotiation did not complete within a reasonable amount of time.
  1219. */
  1220. LOCAL STATUS motFecMiiAnStart
  1221.     (
  1222.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1223.     UINT8 phyAddr /* address of a PHY */
  1224.     )
  1225.     {
  1226.     UINT16 data; /* data to be written to the control reg */
  1227.     UINT8 regAddr; /* PHY register */
  1228.     UINT16 phyStatus; /* holder for the PHY status */
  1229.     UINT16 ix = 0; /* a counter */
  1230.     regAddr = MII_STAT_REG;
  1231.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1232. return (ERROR);
  1233.     /* check the PHY has this ability */
  1234.     if ((phyStatus & MII_SR_AUTO_SEL) != MII_SR_AUTO_SEL)
  1235. {
  1236. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnStart phy not n
  1237.        auto neg capablen"),
  1238.        0, 0, 0, 0, 0, 0);
  1239. return (ERROR);
  1240. }
  1241.     /* restart the auto-negotiation process */
  1242.     regAddr = MII_CTRL_REG;
  1243.     data = (MII_CR_RESTART | MII_CR_AUTO_EN);
  1244.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
  1245. return (ERROR);
  1246.     /* save status info */
  1247.     pDrvCtrl->phyInfo->miiRegs.phyCtrl = data;
  1248.     /* let's check the PHY status */
  1249.     regAddr = MII_STAT_REG;
  1250.     /* spin until it is done */
  1251.     do
  1252. {
  1253. taskDelay (1);
  1254. if (ix++ == MOT_FEC_PHY_MAX_WAIT)
  1255.     break;
  1256. if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus)
  1257.     != OK)
  1258.     return (ERROR);
  1259. } while ((phyStatus & MII_SR_AUTO_NEG) != MII_SR_AUTO_NEG);
  1260.     if (ix >= MOT_FEC_PHY_MAX_WAIT)
  1261. {
  1262. MOT_FEC_LOG (MOT_FEC_DBG_MII,
  1263.      ("motFecMiiAnStart auto neg failn"),
  1264.      0, 0, 0, 0, 0, 0);
  1265. return (MII_AN_FAIL);
  1266. }
  1267.     else
  1268. {
  1269. MOT_FEC_LOG (MOT_FEC_DBG_MII,
  1270.      ("motFecMiiAnStart auto neg done phyStat=0x%xn"),
  1271.      phyStatus, 0, 0, 0, 0, 0);
  1272. }
  1273.     return (OK);
  1274.     }
  1275. /*******************************************************************************
  1276. *
  1277. * motFecMiiBasicCheck - run a basic check on the PHY status register
  1278. *
  1279. * This routine runs a basic check on the PHY status register to
  1280. * ensure a valid link has been established and no faults have been
  1281. * detected.
  1282. *
  1283. * RETURNS: OK, MII_STAT_FAIL, if an error was reported in the PHY's
  1284. * status register, or ERROR, in case of unrecoverable errors.
  1285. */
  1286. LOCAL STATUS motFecMiiBasicCheck
  1287.     (
  1288.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1289.     UINT8 phyAddr /* address of a PHY */
  1290.     )
  1291.     {
  1292.     UINT8 regAddr; /* PHY register */
  1293.     UINT16 phyStatus; /* holder for the PHY status */
  1294.     /* let's check the PHY status */
  1295.     regAddr = MII_STAT_REG;
  1296.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1297. return (ERROR);
  1298.     if ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
  1299. {
  1300. /* wait for a while */
  1301. taskDelay (10);
  1302. /* we need to read it twice, as this's a latched function */
  1303. if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1304.     return (ERROR);
  1305. if ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
  1306.     {
  1307.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiBasicCheck n
  1308.    phy stat=0x%xn"),
  1309.    phyStatus, 0, 0, 0, 0, 0);
  1310.     return (MII_STAT_FAIL);
  1311.     }
  1312. }
  1313.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiBasicCheckn
  1314.    Link up! status=0x%xn"),
  1315.    phyStatus, 0, 0, 0, 0, 0);
  1316.     /* check for remote fault condition */
  1317.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1318. return (ERROR);
  1319.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1320. return (ERROR);
  1321.     if ((phyStatus & MII_SR_REMOTE_FAULT) == MII_SR_REMOTE_FAULT)
  1322. {
  1323. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiBasicCheck remote faultn"),
  1324.        0, 0, 0, 0, 0, 0);
  1325. return (MII_STAT_FAIL);
  1326. }
  1327.     /* store the current registers values */
  1328.     pDrvCtrl->phyInfo->miiRegs.phyStatus = phyStatus;
  1329.     return (OK);
  1330.     }
  1331. /*******************************************************************************
  1332. *
  1333. * motFecMiiAnCheck - check the auto-negotiation process result
  1334. *
  1335. * This routine checks the auto-negotiation process has completed
  1336. * successfully and no faults have been detected by any of the PHYs
  1337. * engaged in the process.
  1338. *
  1339. * RETURNS: OK or ERROR.
  1340. */
  1341. LOCAL STATUS motFecMiiAnCheck
  1342.     (
  1343.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1344.     UINT8 phyAddr /* address of a PHY */
  1345.     )
  1346.     {
  1347.     UINT8 regAddr; /* PHY register */
  1348.     UINT16 phyAds; /* PHY advertisement register value */
  1349.     UINT16 phyPrtn; /* PHY partner ability register value */
  1350.     UINT16 phyExp; /* PHY expansion register value */
  1351.     UINT16 negAbility; /* abilities after negotiation */
  1352.     int retVal; /* convenient holder for return value */
  1353.     /* run a check on the status bits of basic registers only */
  1354.     retVal = motFecMiiBasicCheck (pDrvCtrl, phyAddr);
  1355.     if (retVal != OK)
  1356. return (retVal);
  1357.     /* we know the auto-negotiation process has terminated */
  1358.     regAddr = MII_AN_EXP_REG;
  1359.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyExp) != OK)
  1360. return (ERROR);
  1361.     /* check for faults detected by the parallel function */
  1362.     if ((phyExp & MII_EXP_FAULT) == MII_EXP_FAULT)
  1363. {
  1364. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck:n
  1365.        fault expStat=0x%xn"),
  1366.        phyExp, 0, 0, 0, 0, 0);
  1367. return (ERROR);
  1368. }
  1369.     /* check for remote faults */
  1370.     regAddr = MII_AN_PRTN_REG;
  1371.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyPrtn) != OK)
  1372. return (ERROR);
  1373.     if ((phyPrtn & MII_BP_FAULT) == MII_BP_FAULT)
  1374. {
  1375. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck partner stat=0x%xn"),
  1376.        phyPrtn, 0, 0, 0, 0, 0);
  1377. return (ERROR);
  1378. }
  1379.     regAddr = MII_AN_ADS_REG;
  1380.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyAds) != OK)
  1381. return (ERROR);
  1382.     /* store the current registers values */
  1383.     pDrvCtrl->phyInfo->miiRegs.phyAds = phyAds;
  1384.     pDrvCtrl->phyInfo->miiRegs.phyPrtn = phyPrtn;
  1385.     pDrvCtrl->phyInfo->miiRegs.phyExp = phyExp;
  1386.     /* find out the max common abilities */
  1387.     negAbility = phyPrtn & phyAds & MII_TECH_MASK;
  1388.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck phyAds=0x%xn
  1389.    phyPrtn=0x%x common=0x%x phyExp=0x%xn"),
  1390.    phyAds,
  1391.    phyPrtn,
  1392.    negAbility,
  1393.    phyExp, 0, 0);
  1394.     if (negAbility & MII_TECH_100BASE_TX_FD)
  1395. {
  1396. pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
  1397. pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
  1398. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%sn"),
  1399.        pDrvCtrl->phyInfo->phySpeed,
  1400.        (int) "full duplex", 0, 0, 0, 0);
  1401. }
  1402.     else if ((negAbility & MII_TECH_100BASE_T4) ||
  1403.      (negAbility & MII_TECH_100BASE_TX))
  1404. {
  1405. pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
  1406. pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
  1407. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%sn"),
  1408.        pDrvCtrl->phyInfo->phySpeed,
  1409.        (int) "half duplex", 0, 0, 0, 0);
  1410. }
  1411.     else if (negAbility & MII_TECH_10BASE_FD)
  1412. {
  1413. pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
  1414. pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
  1415. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%sn"),
  1416.        pDrvCtrl->phyInfo->phySpeed,
  1417.        (int) "full duplex", 0, 0, 0, 0);
  1418. }
  1419.     else if (negAbility & MII_TECH_10BASE_T)
  1420. {
  1421. pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
  1422. pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
  1423. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck speed=%d mode=%sn"),
  1424.        pDrvCtrl->phyInfo->phySpeed,
  1425.        (int) "half duplex", 0, 0, 0, 0);
  1426. }
  1427.     else
  1428. {
  1429. MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck fail!n"),
  1430.        0, 0, 0, 0, 0, 0);
  1431. return (ERROR);
  1432. }
  1433.     /* handle some flags */
  1434.     if (pDrvCtrl->phyInfo->phySpeed == MOT_FEC_100MBS)
  1435. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_100);
  1436.     else
  1437. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
  1438.     if (pDrvCtrl->phyInfo->phyMode == MOT_FEC_PHY_FD)
  1439. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_FD);
  1440.     else
  1441. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
  1442.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiAnCheck OKn"),
  1443.    0, 0, 0, 0, 0, 0);
  1444.     return (OK);
  1445.     }
  1446. /*******************************************************************************
  1447. *
  1448. * motFecMiiModeForce - force an operating mode for the PHY
  1449. *
  1450. * This routine forces an operating mode for the PHY whose address is
  1451. * specified in the parameter <phyAddr>. It also calls motFecMiiBasicCheck()
  1452. * to ensure a valid link has been established.
  1453. *
  1454. * RETURNS: OK or ERROR.
  1455. */
  1456. LOCAL STATUS motFecMiiModeForce
  1457.     (
  1458.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1459.     UINT8 phyAddr /* address of a PHY */
  1460.     )
  1461.     {
  1462.     UINT16 data; /* data to be written to the control reg */
  1463.     UINT8 regAddr; /* PHY register */
  1464.     UINT16 phyStatus; /* holder for the PHY status */
  1465.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiModeForce n"),
  1466.    0, 0, 0, 0, 0, 0);
  1467.     /* find out what abilities the PHY features */
  1468.     regAddr = MII_STAT_REG;
  1469.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1470.         return (ERROR);
  1471.     /*
  1472.      * force as a high priority as possible operating
  1473.      * mode, not overlooking what the user dictated.
  1474.      */
  1475.     data = MII_CR_NORM_EN;
  1476.     if ((phyStatus & (MII_SR_TX_FULL_DPX | MII_SR_TX_HALF_DPX))
  1477.         && (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_100)))
  1478.         {
  1479.         data |= MII_CR_100;
  1480.         pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
  1481.         }
  1482.     if ((phyStatus & (MII_SR_TX_FULL_DPX | MII_SR_10T_FULL_DPX | MII_SR_T4))
  1483.         && (MOT_FEC_PHY_FLAGS_ISSET (MOT_FEC_PHY_FD)))
  1484.         {
  1485.         pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
  1486.         data |= MII_CR_FDX;
  1487.         }
  1488.     pDrvCtrl->phyInfo->miiRegs.phyCtrl = data;
  1489.     regAddr = MII_CTRL_REG;
  1490.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
  1491.         return (ERROR);
  1492.     /* run a check on the status bits of basic registers only */
  1493.     if (motFecMiiBasicCheck (pDrvCtrl, phyAddr) != OK)
  1494. return (ERROR);
  1495.     /* handle some flags */
  1496.     if (pDrvCtrl->phyInfo->phySpeed == MOT_FEC_100MBS)
  1497. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_100);
  1498.     else
  1499. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
  1500.     if (pDrvCtrl->phyInfo->phyMode == MOT_FEC_PHY_FD)
  1501. MOT_FEC_PHY_FLAGS_SET (MOT_FEC_PHY_FD);
  1502.     else
  1503. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
  1504.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiModeForce speed=%d mode=%dn"),
  1505.    pDrvCtrl->phyInfo->phySpeed,
  1506.    pDrvCtrl->phyInfo->phyMode,
  1507.    0, 0, 0, 0);
  1508.     return (OK);
  1509.     }
  1510. /*******************************************************************************
  1511. *
  1512. * motFecMiiDefForce - force a default operating mode for the PHY
  1513. *
  1514. * This routine forces a default operating mode for the PHY whose address is
  1515. * specified in the parameter <phyAddr>. It also calls motFecMiiBasicCheck()
  1516. * to ensure a valid link has been established.
  1517. *
  1518. * RETURNS: OK or ERROR.
  1519. */
  1520. LOCAL STATUS motFecMiiDefForce
  1521.     (
  1522.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1523.     UINT8 phyAddr /* address of a PHY */
  1524.     )
  1525.     {
  1526.     UINT16 data; /* data to be written to the control reg */
  1527.     UINT8 regAddr; /* PHY register */
  1528.     int retVal; /* convenient holder for return value */
  1529.     UINT16 phyStatus; /* holder for the PHY status */
  1530.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDefForce n"),
  1531.    0, 0, 0, 0, 0, 0);
  1532.     /* translate user settings */
  1533.     data = miiCrLookupTbl [(pDrvCtrl->phyInfo->phyDefMode)];
  1534.     /* find out what abilities the PHY features */
  1535.     regAddr = MII_STAT_REG;
  1536.     if (motFecMiiRead (pDrvCtrl, phyAddr, regAddr, &phyStatus) != OK)
  1537.         return (ERROR);
  1538.     if (data & MII_CR_100)
  1539. {
  1540. if (!(phyStatus & (MII_SR_TX_HALF_DPX
  1541.  | MII_SR_TX_FULL_DPX
  1542.  | MII_SR_T4)))
  1543.     return (MOT_FEC_PHY_NO_ABLE);
  1544. pDrvCtrl->phyInfo->phySpeed = MOT_FEC_100MBS;
  1545. }
  1546.     else
  1547. {
  1548. if (!(phyStatus & (MII_SR_10T_HALF_DPX
  1549.  | MII_SR_10T_FULL_DPX)))
  1550.     return (MOT_FEC_PHY_NO_ABLE);
  1551. /* handle phy flags */
  1552. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_100);
  1553. pDrvCtrl->phyInfo->phySpeed = MOT_FEC_10MBS;
  1554. }
  1555.     if (data & MII_CR_FDX)
  1556. {
  1557. if (!(phyStatus & (MII_SR_10T_FULL_DPX
  1558.  | MII_SR_TX_FULL_DPX
  1559.  | MII_SR_T4)))
  1560.     return (MOT_FEC_PHY_NO_ABLE);
  1561. pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_FD;
  1562. }
  1563.     else
  1564. {
  1565. if (!(phyStatus & (MII_SR_10T_HALF_DPX
  1566.  | MII_SR_TX_HALF_DPX)))
  1567.     return (MOT_FEC_PHY_NO_ABLE);
  1568. /* handle phy flags */
  1569. MOT_FEC_PHY_FLAGS_CLEAR (MOT_FEC_PHY_FD);
  1570. pDrvCtrl->phyInfo->phyMode = MOT_FEC_PHY_HD;
  1571. }
  1572.     pDrvCtrl->phyInfo->miiRegs.phyCtrl = data;
  1573.     regAddr = MII_CTRL_REG;
  1574.     if (motFecMiiWrite (pDrvCtrl, phyAddr, regAddr, data) != OK)
  1575. return (ERROR);
  1576.     /* run a check on the status bits of basic registers only */
  1577.     retVal = motFecMiiBasicCheck (pDrvCtrl, phyAddr);
  1578.     MOT_FEC_LOG (MOT_FEC_DBG_MII, ("motFecMiiDefForce speed=%d mode=%dn"),
  1579.    pDrvCtrl->phyInfo->phySpeed,
  1580.    pDrvCtrl->phyInfo->phyMode,
  1581.    0, 0, 0, 0);
  1582.     return (retVal);
  1583.     }
  1584. /*******************************************************************************
  1585. *
  1586. * motFecMCastAddrAdd - add a multicast address for the device
  1587. *
  1588. * This routine adds a multicast address to whatever the driver
  1589. * is already listening for.
  1590. *
  1591. * SEE ALSO: motFecMCastAddrDel() motFecMCastAddrGet()
  1592. *
  1593. * RETURNS: OK or ERROR.
  1594. */
  1595. LOCAL STATUS motFecMCastAddrAdd
  1596.     (
  1597.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1598.     char *      pAddr /* address to be added */
  1599.     )
  1600.     {
  1601.     int retVal; /* convenient holder for return value */
  1602.     MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecMCastAddrAdd addr = 0x%x 0x%xn
  1603.      0x%x 0x%x 0x%x 0x%xn"),
  1604.      (int) (*pAddr + 0), (int) (*pAddr + 1),
  1605.      (int) (*pAddr + 2), (int) (*pAddr + 3),
  1606.      (int) (*pAddr + 4), (int) (*pAddr + 5));
  1607.     retVal = etherMultiAdd (&pDrvCtrl->endObj.multiList, pAddr);
  1608.     if (retVal == ENETRESET)
  1609. {
  1610.         pDrvCtrl->endObj.nMulti++;
  1611. return (motFecHashTblAdd (pDrvCtrl, pAddr));
  1612. }
  1613.     return ((retVal == OK) ? OK : ERROR);
  1614.     }
  1615. /*****************************************************************************
  1616. *
  1617. * motFecMCastAddrDel - delete a multicast address for the device
  1618. *
  1619. * This routine deletes a multicast address from the current list of
  1620. * multicast addresses.
  1621. *
  1622. * SEE ALSO: motFecMCastAddrAdd() motFecMCastAddrGet()
  1623. *
  1624. * RETURNS: OK or ERROR.
  1625. */
  1626. LOCAL STATUS motFecMCastAddrDel
  1627.     (
  1628.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1629.     char *      pAddr /* address to be deleted */
  1630.     )
  1631.     {
  1632.     int retVal; /* convenient holder for return value */
  1633.     MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecMCastAddrDel addr = 0x%x 0x%xn
  1634.      0x%x 0x%x 0x%x 0x%xn"),
  1635.      (int) (*pAddr + 0), (int) (*pAddr + 1),
  1636.      (int) (*pAddr + 2), (int) (*pAddr + 3),
  1637.      (int) (*pAddr + 4), (int) (*pAddr + 5));
  1638.     retVal = etherMultiDel (&pDrvCtrl->endObj.multiList, pAddr);
  1639.     if (retVal == ENETRESET)
  1640. {
  1641. pDrvCtrl->endObj.nMulti--;
  1642. /* stop the FEC */
  1643. if (motFecStop (pDrvCtrl) != OK)
  1644.     return (ERROR);
  1645. /* populate the hash table */
  1646. retVal = motFecHashTblPopulate (pDrvCtrl);
  1647. /* restart the FEC */
  1648. if (motFecStart (pDrvCtrl) != OK)
  1649.     return (ERROR);
  1650. }
  1651.     return ((retVal == OK) ? OK : ERROR);
  1652.     }
  1653. /*******************************************************************************
  1654. *
  1655. * motFecMCastAddrGet - get the current multicast address list
  1656. *
  1657. * This routine returns the current multicast address list in <pTable>
  1658. *
  1659. * SEE ALSO: motFecMCastAddrAdd() motFecMCastAddrDel()
  1660. *
  1661. * RETURNS: OK or ERROR.
  1662. */
  1663. LOCAL STATUS motFecMCastAddrGet
  1664.     (
  1665.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1666.     MULTI_TABLE *pTable /* table into which to copy addresses */
  1667.     )
  1668.     {
  1669.     MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecMCastAddrGetn"),
  1670.      0, 0, 0, 0, 0, 0);
  1671.     return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
  1672.     }
  1673. /*******************************************************************************
  1674. *
  1675. * motFecHashTblAdd - add an entry to the hash table
  1676. *
  1677. * This routine adds an entry to the hash table for the address pointed to
  1678. * by <pAddr>.
  1679. *
  1680. * RETURNS: OK, or ERROR.
  1681. */
  1682. LOCAL STATUS motFecHashTblAdd
  1683.     (
  1684.     DRV_CTRL *  pDrvCtrl,       /* pointer to DRV_CTRL structure */
  1685.     char *      pAddr /* address to be added */
  1686.     )
  1687.     {
  1688.     UINT32 crcVal; /* convenient holder for the CRC value */
  1689.     UINT32 csrOldVal; /* current value in the hash register */
  1690.     UINT16 offset; /* offset into the Internal RAM */
  1691.     UINT32  csrVal; /* value to be written to the hash register */
  1692.     MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecHashTblAdd addr = 0x%x 0x%xn
  1693.      0x%x 0x%x 0x%x 0x%xn"),
  1694.      (int) (*pAddr + 0), (int) (*pAddr + 1),
  1695.      (int) (*pAddr + 2), (int) (*pAddr + 3),
  1696.      (int) (*pAddr + 4), (int) (*pAddr + 5));
  1697.     /* get the CRC for the given address */
  1698.     crcVal = motFecCrcGet (pAddr);
  1699.     /* get the value to be written to the proper hash register */
  1700.     if (motFecHashRegValGet (pDrvCtrl, crcVal, &csrVal, &offset) != OK)
  1701. return (ERROR);
  1702.     MOT_FEC_LOG (MOT_FEC_DBG_IOCTL, ("motFecHashTblAdd hashReg=0x%xn"),
  1703.      (int) csrVal,
  1704.      0, 0, 0, 0, 0);
  1705.     /*
  1706.      * write to the proper hash register: be careful not
  1707.      * to override the current value.
  1708.      */
  1709.     MOT_FEC_CSR_RD (offset, csrOldVal);
  1710.     MOT_FEC_CSR_WR (offset, (csrOldVal | csrVal));
  1711.     return (OK);
  1712.     }
  1713. /*******************************************************************************
  1714. *
  1715. * motFecHashTblPopulate - populate the hash table
  1716. *
  1717. * This routine populates the hash table with the entries found in the
  1718. * multicast table. We have to reset the hash registers first, and
  1719. * populate them again, as more than one address may be mapped to
  1720. * the same bit.
  1721. *
  1722. * RETURNS: OK, or ERROR.
  1723. */
  1724. LOCAL STATUS motFecHashTblPopulate
  1725.     (
  1726.     DRV_CTRL *  pDrvCtrl       /* pointer to DRV_CTRL structure */
  1727.     )
  1728.     {
  1729.     UINT32 crcVal; /* convenient holder for the CRC value */
  1730.     UINT16 offset; /* offset into the Internal RAM */
  1731.     UINT32  csrVal; /* value to be written to the hash register */
  1732.     UINT32 csrOldVal; /* current value in the hash register */
  1733.     ETHER_MULTI * mCastNode = NULL;
  1734.     /* reset the hash table registers first */
  1735.     MOT_FEC_CSR_WR (MOT_FEC_HASH_H_OFF, 0);
  1736.     MOT_FEC_CSR_WR (MOT_FEC_HASH_L_OFF, 0);
  1737.     /* scan the multicast address list */
  1738.     for (mCastNode = (ETHER_MULTI *) lstFirst (&pDrvCtrl->endObj.multiList);
  1739.  mCastNode != NULL;
  1740.  mCastNode = (ETHER_MULTI *) lstNext (&mCastNode->node))
  1741. {
  1742. /* get the CRC for the current address in the list */
  1743. crcVal = motFecCrcGet ((char *) mCastNode->addr);
  1744. /* get the value to be written to the proper hash register */
  1745. if (motFecHashRegValGet (pDrvCtrl, crcVal, &csrVal, &offset) != OK)
  1746.             {
  1747.             return (ERROR);
  1748.             }
  1749. /*
  1750.  * write to the proper hash register: be careful not
  1751.  * to override the current value.
  1752.  */
  1753. MOT_FEC_CSR_RD (offset, csrOldVal);
  1754. MOT_FEC_CSR_WR (offset, (csrOldVal | csrVal));
  1755. }
  1756.     return (OK);
  1757.     }
  1758. /*******************************************************************************
  1759. *
  1760. * motFecCrcGet - compute the cyclic redoundant code
  1761. *
  1762. * This routine computes the 32-bit cyclic redoundant code (CRC) for the
  1763. * 6-byte array pointed to by <pAddr>. For details on the polynomium used,
  1764. * see:
  1765. * .I "MPC860T Fast Ethernet Controller (Supplement to MPC860 User's Manual)"
  1766. *
  1767. * RETURNS: The 32-bit value representing the CRC.
  1768. */
  1769. LOCAL UINT32 motFecCrcGet
  1770.     (
  1771.     char * pAddr
  1772.     )
  1773.     {
  1774.     UINT32 crc = INIT_REFLECTED;
  1775.     UINT32 len = 6;
  1776.     while (len--)
  1777.         crc = crctable[(crc ^ *pAddr++) & 0xFFL] ^ (crc >> 8);
  1778.     return crc ^ XOROT;
  1779.     }
  1780. /*******************************************************************************
  1781. *
  1782. * motFecHashRegValGet - get the value to be written to the hash register
  1783. *
  1784. * This routine computes the value to be written to the hash register
  1785. * for the 4-byte value specified by <crcVal>. It also figures out which
  1786. * of the two 32-bit hash register that value should be written to, and
  1787. * returns its offset into the internal RAM in the variable pointed to
  1788. * by <offset>.
  1789. *
  1790. * RETURNS: OK, always.
  1791. */
  1792. LOCAL STATUS motFecHashRegValGet
  1793.     (
  1794.     DRV_CTRL *  pDrvCtrl, /* pointer to DRV_CTRL structure */
  1795.     UINT32 crcVal, /* CRC value */
  1796.     UINT32 * csrVal, /* value to be written to the hash register */
  1797.     UINT16 * offset /* offset into the Internal RAM */
  1798.     )
  1799.     {
  1800.     UINT32 hashIndex; /* index into the hash register */
  1801.     /*
  1802.      * bits 26-30 in the CRC value determine the index in the
  1803.      * hash register specified by bit 31.
  1804.      */
  1805.     hashIndex = ((crcVal & MOT_FEC_HASH_MASK) >> MOT_FEC_HASH_SHIFT);
  1806.     *csrVal = (0x80000000 >> hashIndex);
  1807.     /* It appears that starting at register 0x0E08 HASH_TABLE_HIGH high
  1808.      * order bit is really bit 0 of the hash table and low order bit
  1809.      * of 0x0E0C HASH_TABLE_LOW is bit 63 of the hash table.
  1810.      *
  1811.      * 0x0E0C  HASH_TABLE_LOW  [32:64]   ==>   hash_index[63:32]
  1812.      * 0x0E08  HASH_TABLE_HIGH [0 :31]   ==>   hash_index[31: 0]
  1813.      *
  1814.      * So this means that bit 31 of the CRC if 1 points to
  1815.      * the HASH_TABLE_LOW register, not the HASH_TABLE_HIGH.
  1816.      */
  1817.     *offset = (crcVal & 0x80000000) ? MOT_FEC_HASH_L_OFF : MOT_FEC_HASH_H_OFF;
  1818.     return (OK);
  1819.     }
  1820. /*****************************************************************************
  1821. *
  1822. * motFecPollSend - transmit a packet in polled mode
  1823. *
  1824. * This routine is called by a user to try and send a packet on the
  1825. * device. It sends a packet directly on the network, without having to
  1826. * go through the normal process of queuing a packet on an output queue
  1827. * and then waiting for the device to decide to transmit it.
  1828. *
  1829. * These routine should not call any kernel functions.
  1830. *
  1831. * SEE ALSO: motFecPollReceive()
  1832. *
  1833. * RETURNS: OK or EAGAIN.
  1834. */
  1835. LOCAL STATUS motFecPollSend
  1836.     (
  1837.     DRV_CTRL    *pDrvCtrl, /* pointer to DRV_CTRL structure */
  1838.     M_BLK_ID    pMblk /* pointer to the mBlk/cluster pair */
  1839.     )
  1840.     {
  1841.     UINT16 pktType = 0; /* packet type (unicast or multicast) */
  1842.     int retVal; /* holder for return value */
  1843.     char * pBuf = NULL; /* pointer to data to be sent */
  1844.     MOT_FEC_TBD_ID pTbd = NULL; /* pointer to the current ready TBD */
  1845.     int  ix = 0; /* a counter */
  1846.     int len = 0; /* length of data to be sent */
  1847.     UINT16 tbdStatus; /* holder for the TBD status */
  1848.     MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollSendn"), 0, 0, 0, 0, 0, 0);
  1849.     if (pMblk == NULL)
  1850. {
  1851. goto motFecPollSendError;
  1852. }
  1853.     /* set the packet type to multicast or unicast */
  1854.     if (pMblk->mBlkHdr.mData[0] & (UINT8) 0x01)
  1855.         {
  1856.         pktType = PKT_TYPE_MULTI;
  1857.         }
  1858.     else
  1859.         {
  1860.         pktType = PKT_TYPE_UNI;
  1861.         }
  1862.     /* get the current free TBD */
  1863.     pTbd = motFecTbdGet (pDrvCtrl);
  1864.     /* get our own cluster */
  1865.     pBuf = (char *)pDrvCtrl->pTxPollBuf;
  1866.     if ((pTbd == NULL) || (pBuf == NULL))
  1867. {
  1868. goto motFecPollSendError;
  1869. }
  1870.     /* copy data but do not free the Mblk */
  1871.     len = netMblkToBufCopy (pMblk, pBuf, NULL);
  1872.     len = max (ETHERSMALL, len);
  1873.     /* flush the cache, if necessary */
  1874.     MOT_FEC_CACHE_FLUSH (pBuf, len);
  1875.     /* set up the current TBD */
  1876.     MOT_FEC_BD_LONG_WR (pTbd, MOT_FEC_BD_ADDR_OFF, (UINT32) pBuf);
  1877.     MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_LEN_OFF, (UINT32) len);
  1878.     MOT_FEC_BD_WORD_RD (pTbd, MOT_FEC_BD_STAT_OFF, tbdStatus);
  1879.     MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF,
  1880. (MOT_FEC_TBD_LAST | MOT_FEC_TBD_CRC
  1881. | MOT_FEC_TBD_RDY | tbdStatus));
  1882.     /* kick the transmitter */
  1883.     MOT_FEC_TX_ACTIVATE;
  1884.     /* Flush the write pipe */
  1885.     CACHE_PIPE_FLUSH ();
  1886.     /* up-date statistics */
  1887.     if (pktType == PKT_TYPE_MULTI)
  1888.         {
  1889.         pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts += 1;
  1890.         }
  1891.     else
  1892.         {
  1893.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1894.         }
  1895.     do
  1896. {
  1897. retVal = motFecTbdCheck (pDrvCtrl, pTbd);
  1898. if (ix++ == MOT_FEC_WAIT_MAX)
  1899.     break;
  1900. } while (retVal == MOT_FEC_TBD_BUSY);
  1901.     /* correct statistics, if necessary */
  1902.     if ((retVal == MOT_FEC_TBD_ERROR) || (ix == MOT_FEC_WAIT_MAX))
  1903. {
  1904. END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  1905. if (pktType == PKT_TYPE_MULTI)
  1906.     {
  1907.     pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts -= 1;
  1908.     }
  1909. else
  1910.     {
  1911.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
  1912.     }
  1913. }
  1914.     /* clean this buffer descriptor, mirror motFecTbdInit() */
  1915.     if (pDrvCtrl->tbdIndex == (pDrvCtrl->tbdNum - 1))
  1916. {
  1917. MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF,
  1918.     MOT_FEC_TBD_WRAP);
  1919. }
  1920.     else
  1921. {
  1922. MOT_FEC_BD_WORD_WR (pTbd, MOT_FEC_BD_STAT_OFF, 0);
  1923. }
  1924.     /* Flush the write pipe */
  1925.     CACHE_PIPE_FLUSH ();
  1926.     /* update some indeces for a correct handling of the TBD ring */
  1927.     pDrvCtrl->tbdIndex = (pDrvCtrl->tbdIndex + 1)
  1928.   % (pDrvCtrl->tbdNum);
  1929.     pDrvCtrl->usedTbdIndex = (pDrvCtrl->usedTbdIndex + 1)
  1930.       % (pDrvCtrl->tbdNum);
  1931.     if (ix == MOT_FEC_WAIT_MAX)
  1932. return (EAGAIN);
  1933.     return (OK);
  1934. motFecPollSendError:
  1935.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  1936.     return (EAGAIN);
  1937.     }
  1938. /*******************************************************************************
  1939. *
  1940. * motFecPollReceive - receive a packet in polled mode
  1941. *
  1942. * This routine is called by a user to try and get a packet from the
  1943. * device. It returns EAGAIN if no packet is available. The caller must
  1944. * supply a M_BLK_ID with enough space to contain the received packet. If
  1945. * enough buffer is not available then EAGAIN is returned.
  1946. *
  1947. * These routine should not call any kernel functions.
  1948. *
  1949. * SEE ALSO: motFecPollSend()
  1950. *
  1951. * RETURNS: OK or EAGAIN.
  1952. */
  1953. LOCAL STATUS motFecPollReceive
  1954.     (
  1955.     DRV_CTRL    *pDrvCtrl,      /* pointer to DRV_CTRL structure */
  1956.     M_BLK_ID    pMblk           /* pointer to the mBlk/cluster pair */
  1957.     )
  1958.     {
  1959.     int retVal = OK; /* holder for return value */
  1960.     MOT_FEC_RBD_ID pRbd = NULL; /* generic rbd pointer */
  1961.     UINT16 rbdStatus = 0; /* holder for the status of this RBD */
  1962.     UINT16 rbdLen = 0; /* number of bytes received */
  1963.     char * pBuf = NULL; /* a rx data pointer */
  1964.     char * pData = NULL; /* a rx data pointer */
  1965.     MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollReceiven"), 0, 0, 0, 0, 0, 0);
  1966.     if ((pMblk->mBlkHdr.mFlags & M_EXT) != M_EXT)
  1967.         return (EAGAIN);
  1968.     /* get the first available RBD */
  1969.     MOT_FEC_NEXT_RBD (pDrvCtrl, pRbd);
  1970.     /* Make cache consistent with memory */
  1971.     MOT_FEC_BD_CACHE_INVAL (pRbd, MOT_FEC_RBD_SZ);
  1972.     /* read the RBD status word */
  1973.     MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_STAT_OFF,
  1974. rbdStatus);
  1975.     /* if it's not ready, don't touch it! */
  1976.     if ((rbdStatus & MOT_FEC_RBD_EMPTY) == MOT_FEC_RBD_EMPTY)
  1977. {
  1978. return (EAGAIN);
  1979. }
  1980.     /* pass the packet up only if reception was Ok */
  1981.     if (rbdStatus & MOT_FEC_RBD_ERR)
  1982. {
  1983. MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecReceive: bad rbdn"),
  1984.         1, 2, 3, 4, 5, 6);
  1985. goto motFecPollReceiveEnd;
  1986. }
  1987.     /* get the actual amount of received data */
  1988.     MOT_FEC_BD_WORD_RD (pRbd, MOT_FEC_BD_LEN_OFF,
  1989. rbdLen);
  1990.     if (rbdLen < ETHERSMALL)
  1991. {
  1992. MOT_FEC_RX_LS_ADD;
  1993. goto motFecPollReceiveEnd;
  1994. }
  1995.     /*
  1996.      * Upper layer provides the buffer. If buffer is not large enough,
  1997.      * we do not copy the received buffer.
  1998.      */
  1999.     if (pMblk->mBlkHdr.mLen < rbdLen)
  2000. {
  2001. goto motFecPollReceiveEnd;
  2002. }
  2003.     MOT_FEC_BD_LONG_RD (pRbd, MOT_FEC_BD_ADDR_OFF, pData);
  2004.     /* up-date statistics */
  2005.     if ((*pData ) & (UINT8) 0x01)
  2006.         {
  2007.         pDrvCtrl->endObj.mib2Tbl.ifInNUcastPkts += 1;
  2008.         }
  2009.     else
  2010.         {
  2011.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  2012.         }
  2013.     /* set up the mBlk properly */
  2014.     pMblk->mBlkHdr.mFlags   |= M_PKTHDR;
  2015.     pMblk->mBlkHdr.mLen = (rbdLen - ETHER_CRC_LEN) & ~0xc000;
  2016.     pMblk->mBlkPktHdr.len   = pMblk->mBlkHdr.mLen;
  2017.     /* Make cache consistent with memory */
  2018.     MOT_FEC_CACHE_INVAL ((char *) pData, pMblk->mBlkHdr.mLen);
  2019.     bcopy ((char *) pData, (char *) pMblk->mBlkHdr.mData,
  2020.    ((rbdLen - ETHER_CRC_LEN) & ~0xc000));
  2021.     /* put the used RBD on the RBD queue */
  2022.     motFecRbdClean (pDrvCtrl, pBuf);
  2023.     return (retVal);
  2024. motFecPollReceiveEnd:
  2025.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  2026.     /* put the errored RBD on the RBD queue */
  2027.     motFecRbdClean (pDrvCtrl, pBuf);
  2028.     return (EAGAIN);
  2029.     }
  2030. /*******************************************************************************
  2031. *
  2032. * motFecPollStart - start polling mode
  2033. *
  2034. * This routine starts polling mode by disabling ethernet interrupts and
  2035. * setting the polling flag in the END_CTRL stucture.
  2036. *
  2037. * SEE ALSO: motFecPollStop()
  2038. *
  2039. * RETURNS: OK, or ERROR if polling mode could not be started.
  2040. */
  2041. LOCAL STATUS motFecPollStart
  2042.     (
  2043.     DRV_CTRL    *pDrvCtrl       /* pointer to DRV_CTRL structure */
  2044.     )
  2045.     {
  2046.     int         intLevel; /* current intr level */
  2047.     int retVal; /* convenient holder for return value */
  2048.     MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollStartn"), 0, 0, 0, 0, 0, 0);
  2049.     intLevel = intLock();
  2050.     /* disable system interrupt: reset relevant bit in SIMASK */
  2051.     SYS_FEC_INT_DISABLE (pDrvCtrl, retVal);
  2052.     if (retVal == ERROR)
  2053. return (ERROR);
  2054.     /* mask chip interrupts   */
  2055.     MOT_FEC_INT_DISABLE;
  2056.     MOT_FEC_FLAG_SET (MOT_FEC_POLLING);
  2057.     intUnlock (intLevel);
  2058.     return (OK);
  2059.     }
  2060. /*******************************************************************************
  2061. *
  2062. * motFecPollStop - stop polling mode
  2063. *
  2064. * This routine stops polling mode by enabling ethernet interrupts and
  2065. * resetting the polling flag in the END_CTRL structure.
  2066. *
  2067. * SEE ALSO: motFecPollStart()
  2068. *
  2069. * RETURNS: OK, or ERROR if polling mode could not be stopped.
  2070. */
  2071. LOCAL STATUS motFecPollStop
  2072.     (
  2073.     DRV_CTRL    *pDrvCtrl       /* pointer to DRV_CTRL structure */
  2074.     )
  2075.     {
  2076.     int         intLevel;
  2077.     int retVal; /* convenient holder for return value */
  2078.     intLevel = intLock();
  2079.     /* enable system interrupt: set relevant bit in SIMASK */
  2080.     SYS_FEC_INT_ENABLE (pDrvCtrl, retVal);
  2081.     if (retVal == ERROR)
  2082. return (ERROR);
  2083.     /* enable chip interrupts */
  2084.     MOT_FEC_INT_ENABLE;
  2085.     /* set flags */
  2086.     MOT_FEC_FLAG_CLEAR (MOT_FEC_POLLING);
  2087.     intUnlock (intLevel);
  2088.     MOT_FEC_LOG (MOT_FEC_DBG_POLL, ("motFecPollStop... endn"),
  2089.     0, 0, 0, 0, 0, 0);
  2090.     return (OK);
  2091.     }
  2092. #ifdef MOT_FEC_DBG
  2093. void motFecCsrShow
  2094.     (
  2095.     )
  2096.     {
  2097.     UINT32 csrVal;
  2098.     DRV_CTRL * pDrvCtrl = pDrvCtrlDbg;
  2099.     MOT_FEC_CSR_RD (MOT_FEC_ADDR_L_OFF, csrVal);
  2100.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Addr low:      0x%xn"),
  2101.       csrVal, 0, 0, 0, 0, 0);
  2102.     MOT_FEC_CSR_RD (MOT_FEC_ADDR_H_OFF, csrVal);
  2103.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Addr high:      0x%xn"),
  2104.       csrVal, 0, 0, 0, 0, 0);
  2105.     MOT_FEC_CSR_RD (MOT_FEC_HASH_H_OFF, csrVal);
  2106.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Hash table high:      0x%xn"),
  2107.       csrVal, 0, 0, 0, 0, 0);
  2108.     MOT_FEC_CSR_RD (MOT_FEC_HASH_L_OFF, csrVal);
  2109.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Hash table low:      0x%xn"),
  2110.       csrVal, 0, 0, 0, 0, 0);
  2111.     MOT_FEC_CSR_RD (MOT_FEC_RX_START_OFF, csrVal);
  2112.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx ring start:      0x%xn"),
  2113.       csrVal, 0, 0, 0, 0, 0);
  2114.     MOT_FEC_CSR_RD (MOT_FEC_TX_START_OFF, csrVal);
  2115.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx ring start:      0x%xn"),
  2116.       csrVal, 0, 0, 0, 0, 0);
  2117.     MOT_FEC_CSR_RD (MOT_FEC_RX_BUF_OFF, csrVal);
  2118.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx max buffer:      0x%xn"),
  2119.       csrVal, 0, 0, 0, 0, 0);
  2120.     MOT_FEC_CSR_RD (MOT_FEC_CTRL_OFF, csrVal);
  2121.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Ethernet Controller:      0x%xn"),
  2122.    (csrVal & MOT_FEC_CTRL_MASK),
  2123.    0, 0, 0, 0, 0);
  2124.     MOT_FEC_CSR_RD (MOT_FEC_EVENT_OFF, csrVal);
  2125.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Interrupt event:      0x%xn"),
  2126.    (csrVal & MOT_FEC_EVENT_MSK),
  2127.    0, 0, 0, 0, 0);
  2128.     MOT_FEC_CSR_RD (MOT_FEC_MASK_OFF, csrVal);
  2129.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Interrupt mask:      0x%xn"),
  2130.    (csrVal & MOT_FEC_EVENT_MSK),
  2131.    0, 0, 0, 0, 0);
  2132.     MOT_FEC_CSR_RD (MOT_FEC_VEC_OFF, csrVal);
  2133.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Interrupt vector/level:      0x%xn"),
  2134.    (csrVal & MOT_FEC_VEC_MSK),
  2135.    0, 0, 0, 0, 0);
  2136.     MOT_FEC_CSR_RD (MOT_FEC_RX_ACT_OFF, csrVal);
  2137.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx active:      0x%xn"),
  2138.    csrVal, 0, 0, 0, 0, 0);
  2139.     MOT_FEC_CSR_RD (MOT_FEC_TX_ACT_OFF, csrVal);
  2140.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx active:      0x%xn"),
  2141.    csrVal, 0, 0, 0, 0, 0);
  2142.     MOT_FEC_CSR_RD (MOT_FEC_MII_DATA_OFF, csrVal);
  2143.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("MII data :      0x%xn"),
  2144.    csrVal, 0, 0, 0, 0, 0);
  2145.     MOT_FEC_CSR_RD (MOT_FEC_MII_SPEED_OFF, csrVal);
  2146.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("MII speed :      0x%xn"),
  2147.    csrVal, 0, 0, 0, 0, 0);
  2148.     MOT_FEC_CSR_RD (MOT_FEC_RX_BOUND_OFF, csrVal);
  2149.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx FIFO bound:      0x%xn"),
  2150.    csrVal, 0, 0, 0, 0, 0);
  2151.     MOT_FEC_CSR_RD (MOT_FEC_RX_FIFO_OFF, csrVal);
  2152.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx FIFO base:      0x%xn"),
  2153.    csrVal, 0, 0, 0, 0, 0);
  2154.     MOT_FEC_CSR_RD (MOT_FEC_TX_FIFO_OFF, csrVal);
  2155.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx FIFO base:      0x%xn"),
  2156.    csrVal, 0, 0, 0, 0, 0);
  2157.     MOT_FEC_CSR_RD (MOT_FEC_SDMA_OFF, csrVal);
  2158.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("SDMA Function Code:      0x%xn"),
  2159.    csrVal, 0, 0, 0, 0, 0);
  2160.     MOT_FEC_CSR_RD (MOT_FEC_RX_CTRL_OFF, csrVal);
  2161.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx Control Register:      0x%xn"),
  2162.    csrVal, 0, 0, 0, 0, 0);
  2163.     MOT_FEC_CSR_RD (MOT_FEC_RX_FR_OFF, csrVal);
  2164.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Rx Max frame length:      0x%xn"),
  2165.    (csrVal & MOT_FEC_RX_FR_MSK),
  2166.    0, 0, 0, 0, 0);
  2167.     MOT_FEC_CSR_RD (MOT_FEC_TX_CTRL_OFF, csrVal);
  2168.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("Tx Control Register:      0x%xn"),
  2169.    csrVal, 0, 0, 0, 0, 0);
  2170.     }
  2171. void motFecRbdShow
  2172.     (
  2173.     int rbdNum
  2174.     )
  2175.     {
  2176.     UINT16 status;
  2177.     UINT16 length;
  2178.     UINT32 buffer;
  2179.     MOT_FEC_WORD_RD ((UINT32 *)(pDrvCtrlDbg->rbdBase +
  2180.      (rbdNum * MOT_FEC_RBD_SZ) +
  2181.      MOT_FEC_BD_STAT_OFF), status);
  2182.     MOT_FEC_WORD_RD ((UINT32 *)(pDrvCtrlDbg->rbdBase +
  2183.      (rbdNum * MOT_FEC_RBD_SZ) +
  2184.      MOT_FEC_BD_LEN_OFF), length);
  2185.     MOT_FEC_LONG_RD ((UINT32 *)(pDrvCtrlDbg->rbdBase +
  2186.      (rbdNum * MOT_FEC_RBD_SZ) +
  2187.      MOT_FEC_BD_ADDR_OFF), buffer);
  2188.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("rbdStatus=0x%x rbdLen=0x%x rbdBuf=0x%xn"),
  2189.    status, length, buffer, 0, 0, 0);
  2190.     }
  2191. void motFecErrorShow
  2192.     (
  2193.     )
  2194.     {
  2195.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("TxBab=0x%x RxBab=0x%xn"),
  2196.    motFecBabTxErr,
  2197.    motFecBabRxErr,
  2198.    0, 0, 0, 0);
  2199.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("TxLc=0x%x TxUr=0x%x TxCsl=0x%x n
  2200.    TxRl=0x%xn"),
  2201.    motFecTxLcErr,
  2202.    motFecTxUrErr,
  2203.    motFecTxCslErr,
  2204.    motFecTxRlErr,
  2205.    0, 0);
  2206.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("RxLg=0x%x RxNo=0x%x RxCrc=0x%x n
  2207.    RxOv=0x%x RxTr=0x%xn"),
  2208.    motFecRxLgErr,
  2209.    motFecRxNoErr,
  2210.    motFecRxCrcErr,
  2211.    motFecRxOvErr,
  2212.    motFecRxTrErr,
  2213.    0);
  2214.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("RxLs=0x%x RxMem=0x%xn"),
  2215.    motFecRxLsErr,
  2216.    motFecRxMemErr,
  2217.    0, 0, 0, 0);
  2218.     }
  2219. void motFecDrvShow
  2220.     (
  2221.     )
  2222.     {
  2223.     DRV_CTRL * pDrvCtrl = pDrvCtrlDbg;
  2224.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("pDrvCtrl=0x%x pNetPool=0x%x n
  2225.    pClPool=0x%xn"),
  2226.    (int) pDrvCtrl,
  2227.    (int) pDrvCtrl->endObj.pNetPool,
  2228.    (int) pDrvCtrl->pClPoolId, 0, 0, 0);
  2229.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("bufBase=0x%x bufSize=0x%x pClBlkArea=0x%xn
  2230.    clBlkSize=0x%x pMBlkArea=0x%x n
  2231.    mBlkSize=0x%xn"),
  2232.    (int) pDrvCtrl->pBufBase,
  2233.    pDrvCtrl->bufSize,
  2234.    (int) pDrvCtrl->pClBlkArea,
  2235.    pDrvCtrl->clBlkSize,
  2236.    (int) pDrvCtrl->pMBlkArea,
  2237.    pDrvCtrl->mBlkSize);
  2238.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("tbdNum=%d tbdBase=0x%xtbdIndex=%d n
  2239.    usedTbdIndex=%d n
  2240.    cleanTbdNum=%d txStall=%d n"),
  2241.    pDrvCtrl->tbdNum,
  2242.    (int) pDrvCtrl->tbdBase,
  2243.    pDrvCtrl->tbdIndex,
  2244.    pDrvCtrl->usedTbdIndex,
  2245.    pDrvCtrl->cleanTbdNum,
  2246.    pDrvCtrl->txStall);
  2247.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("rbdNum=%d rbdBase=0x%x rbdIndex=%d n"),
  2248.    pDrvCtrl->rbdNum,
  2249.    (int) pDrvCtrl->rbdBase,
  2250.    pDrvCtrl->rbdIndex,
  2251.    0, 0, 0);
  2252.     }
  2253. void motFecMiiShow
  2254.     (
  2255.     )
  2256.     {
  2257.     DRV_CTRL *  pDrvCtrl = pDrvCtrlDbg;
  2258.     UCHAR       speed [20];
  2259.     UCHAR       mode [20];
  2260.     strcpy ((char *) speed, (pDrvCtrl->phyInfo->phySpeed == MOT_FEC_100MBS) ?
  2261.                     "100Mbit/s" : "10Mbit/s");
  2262.     strcpy ((char *) mode, (pDrvCtrl->phyInfo->phyMode == MOT_FEC_PHY_FD) ?
  2263.                    "full duplex" : "half duplex");
  2264.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("phySpeed=%s phyMode=%s phyAddr=0x%xn
  2265.                                    isoPhyAddr=0x%x phyFlags=0x%xn
  2266.                                    phyDefMode=0x%xn"),
  2267.                                    (int) &speed[0],
  2268.                                    (int) &mode[0],
  2269.                                    pDrvCtrl->phyInfo->phyAddr,
  2270.                                    pDrvCtrl->phyInfo->isoPhyAddr,
  2271.                                    pDrvCtrl->phyInfo->phyFlags,
  2272.                                    pDrvCtrl->phyInfo->phyDefMode);
  2273.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("phyStatus=0x%x phyCtrl=0x%x phyAds=0x%xn
  2274.                                    phyPrtn=0x%x phyExp=0x%x phyNext=0x%xn"),
  2275.                                    pDrvCtrl->phyInfo->miiRegs.phyStatus,
  2276.                                    pDrvCtrl->phyInfo->miiRegs.phyCtrl,
  2277.                                    pDrvCtrl->phyInfo->miiRegs.phyAds,
  2278.                                    pDrvCtrl->phyInfo->miiRegs.phyPrtn,
  2279.                                    pDrvCtrl->phyInfo->miiRegs.phyExp,
  2280.                                    pDrvCtrl->phyInfo->miiRegs.phyNext);
  2281.     }
  2282. void motFecMibShow
  2283.     (
  2284.     )
  2285.     {
  2286.     DRV_CTRL *  pDrvCtrl = pDrvCtrlDbg;
  2287.     MOT_FEC_LOG (MOT_FEC_DBG_ANY, ("ifOutNUcastPkts=%d ifOutUcastPkts=%dn
  2288.                                    ifInNUcastPkts=%dn
  2289.                                    ifInUcastPkts=%d ifOutErrors=%dn"),
  2290.                                    pDrvCtrl->endObj.mib2Tbl.ifOutNUcastPkts,
  2291.                                    pDrvCtrl->endObj.mib2Tbl.ifOutUcastPkts,
  2292.                                    pDrvCtrl->endObj.mib2Tbl.ifInNUcastPkts,
  2293.                                    pDrvCtrl->endObj.mib2Tbl.ifInUcastPkts,
  2294.                                    pDrvCtrl->endObj.mib2Tbl.ifOutErrors,
  2295.                                    0);
  2296.     }
  2297. #endif /* MOT_FEC_DBG */
  2298. /*******************************************************************************
  2299. *
  2300. * motRevNumGet - Get the processor revision number
  2301. *
  2302. * This routine will return the lower 16 bits of the IMMR (SPR #638)
  2303. * which will contain the processor revision number.
  2304. #
  2305. * RETURNS: processor revision number (in r3)
  2306. *
  2307. * NOMANUAL
  2308. */
  2309. LOCAL int motRevNumGet(void)
  2310.     {
  2311.     int rev;
  2312.     rev = vxImmrDevGet();
  2313.     return(rev);
  2314.     }