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

VxWorks

开发平台:

C/C++

  1. /* if_fei.c - Intel 82557 Ethernet network interface driver */
  2. /* Copyright 1998 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01q,28apr99,dat  Merge from 2_0_0
  8. 01s,09mar99,cn   added support for shared PCI interrupts (SPR# 24379).
  9. 01r,14dec98,n_s  fixed feiInit to properly set promiscuous mode. spr 24000.
  10. 01q,16oct98,cn   changed default to be BSD44_DRIVER, as 01o did not do it.
  11.  Suppressed warning in feiIoctl() (SPR# 21880).
  12. 01p,30sep98,cn   moved call to I82557_INT_DISABLE after sys557Init() 
  13.  (SPR# 21879). Also suppressed some warnings (SPR# 21880).
  14. 01o,16apr98,dat  changed default to be BSD44_DRIVER
  15. 01n,14apr98,sbs  added global variable feiIntConnect.
  16.                  changed SYS_PCI_INT_CONNECT to SYS_INT_CONNECT.
  17.                  added documentation on how to use feiIntConnect.
  18. 01m,18mar98,dat  changed default to be BSD43_DRIVER. fixed compatibility
  19. 01l,12mar98,sbs  changed intConnect() to SYS_PCI_INT_CONNECT.
  20. 01k,15jul97,spm  removed driver initialization from ioctl support (SPR #8831)
  21. 01j,25apr97,gnn  added multicast by turning on promiscous mode.
  22. 01i,03mar97,myz  fixed spr 7663
  23. 01h,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  24. 01h,10dec96,jdi  doc: correct statement about # of external support functions.
  25. 01g,20nov96,myz  doc: removed the document for the sys557Intxxx functions
  26. 01f,20nov96,myz  correct the DOC problem in feiDumpPrint and feiErrCounterDump
  27. 01e,20nov96,jdi  doc: mangen fixes and general cleanup.
  28. 01d,20nov96,hdn  removed CSR_ADDR_GET() and ENET_ADDR_GET().
  29. 01c,25oct96,myz  added system memory interface and MDI control 
  30. 01b,10oct96,dzb  clean-up and bug fixes.
  31. 01a,31aug96,dzb  written, based on v03g of src/drv/netif/if_ei.c.
  32. */
  33. /*
  34. This module implements the Intel 82557 Ethernet network interface driver.
  35. This driver is designed to be moderately generic, operating unmodified
  36. across the entire range of architectures and targets supported by VxWorks.
  37. This driver must be given several target-specific parameters, and some
  38. external support routines must be provided.  These parameters, and the
  39. mechanisms used to communicate them to the driver, are detailed below.
  40. This driver supports up to four individual units.
  41. EXTERNAL INTERFACE
  42. The user-callable routine is feiattach(), which publishes the `fei'
  43. interface and performs some initialization.
  44. After calling feiattach() to publish the interface, an initialization
  45. routine must be called to bring the device up to an operational state.
  46. The initialization routine is not a user-callable routine; upper layers
  47. call it when the interface flag is set to `UP', or when the interface's
  48. IP address is set.
  49. There is a global variable 'feiIntConnect' which specifies the interrupt
  50. connect routine to be used depending on the BSP. This is by default set 
  51. to intConnect() and the user can override this to use any other interrupt 
  52. connect routine ( say pciIntConnect() ) in sysHwInit() or any device 
  53. specific initialization routine called in sysHwInit().
  54. TARGET-SPECIFIC PARAMETERS
  55. .iP "shared memory address"
  56. This parameter is passed to the driver via feiattach().
  57. The Intel 82557 device is a DMA-type device and typically shares
  58. access to some region of memory with the CPU.  This driver is designed
  59. for systems that directly share memory between the CPU and the 82557.
  60. This parameter can be used to specify an explicit memory region for use
  61. by the 82557.  This should be done on targets that restrict the 82557
  62. to a particular memory region.  The constant `NONE' can be used to indicate
  63. that there are no memory limitations, in which case the driver
  64. attempts to allocate the shared memory from the system space.
  65. .iP "number of Command, Receive, and Loanable-Receive Frame Descriptors"
  66. These parameters are passed to the driver via feiattach().
  67. The Intel 82557 accesses frame descriptors (and their associated buffers)
  68. in memory for each frame transmitted or received.  The number of frame
  69. descriptors can be configured at run-time using these parameters.
  70. .iP "Ethernet address"
  71. This parameter is obtained by a call to an external support routine.
  72. .LP
  73. EXTERNAL SUPPORT REQUIREMENTS
  74. This driver requires the following external support function:
  75. .CS
  76.     STATUS sys557Init (int unit, BOARD_INFO *pBoard)
  77. .CE
  78. This routine performs any target-specific initialization
  79. required before the 82557 device is initialized by the driver.
  80. The driver calls this routine every time it wants to [re]initialize
  81. the device.  This routine returns OK, or ERROR if it fails.
  82. SYSTEM RESOURCE USAGE
  83. The driver uses cacheDmaMalloc() to allocate memory to share with the 82557.
  84. The size of this area is affected by the configuration parameters specified
  85. in the feiattach() call.  The size of one RFD (Receive Frame Descriptor) is
  86. is the same as one CFD (Command Frame Descriptor): 1536 bytes.  For more
  87. information about RFDs and CFDs, see the
  88. .I "Intel 82557 User's Manual."
  89. Either the shared memory region must be non-cacheable, or else
  90. the hardware must implement bus snooping.  The driver cannot maintain
  91. cache coherency for the device because fields within the command
  92. structures are asynchronously modified by both the driver and the device,
  93. and these fields may share the same cache line.
  94. Additionally, this version of the driver does not handle virtual-to-physical
  95. or physical-to-virtual memory mapping.
  96. TUNING HINTS
  97. The only adjustable parameters are the number of Frame Descriptors that will be
  98. created at run-time.  These parameters are given to the driver when feiattach()
  99. is called.  There is one CFD and one RFD associated with each transmitted
  100. frame and each received frame, respectively.  For memory-limited applications,
  101. decreasing the number of CFDs and RFDs may be desirable.  Increasing the number
  102. of CFDs will provide no performance benefit after a certain point.
  103. Increasing the number of RFDs will provide more buffering before packets are
  104. dropped.  This can be useful if there are tasks running at a higher priority
  105. than the net task.
  106. SEE ALSO: ifLib,
  107. .I "Intel 82557 User's Manual"
  108. */
  109. #include "vxWorks.h"
  110. #include "wdLib.h"
  111. #include "sockLib.h"
  112. #include "memLib.h"
  113. #include "intLib.h"
  114. #include "iosLib.h"
  115. #include "errnoLib.h"
  116. #include "cacheLib.h"
  117. #include "netLib.h"
  118. #include "stdio.h"
  119. #include "stdlib.h"
  120. #include "string.h"
  121. #include "ioctl.h"
  122. #include "net/if.h"
  123. #include "netinet/in.h"
  124. #include "netinet/in_var.h"
  125. #include "net/unixLib.h"
  126. #include "net/if_subr.h"
  127. #include "iv.h"
  128. #include "sysLib.h"
  129. #include "etherLib.h"
  130. #include "vxLib.h"
  131. #include "logLib.h"
  132. #include "taskLib.h"
  133. #include "drv/netif/netifDev.h"
  134. #include "drv/netif/if_fei.h"
  135. #include "drv/pci/pciIntLib.h"
  136. /* defines */
  137. /* Change default to BSD44_DRIVER */
  138.  
  139. #ifndef BSD43_DRIVER
  140. #ifndef BSD44_DRIVER
  141. #   define BSD44_DRIVER
  142. #endif /* BSD44_DRIVER */
  143. #endif /* BSD43_DRIVER */
  144. #undef FEI_DEBUG /* turns on debug output */
  145. #ifdef  FEI_DEBUG
  146. #undef  LOCAL
  147. #define LOCAL
  148. LOCAL BOOL feiDebug = 1;
  149. #endif  /* FEI_DEBUG */
  150. #define FEI_ACTION_TMO 1 /* action command timeout in seconds */
  151. #define FEI_SCB_TMO 1 /* SCB command timeout in seconds */
  152. #define FEI_INIT_TMO 1 /* 557 init timeout in seconds */
  153. #define FEI_TX_RESTART_TMO      1       /* tx restart watchdog timeout */
  154. #define TCB_TX_THRESH 0x10 /* Tx threshold value */
  155. #define BOARD_INT_ENABLE(unit) if ((int)pDrvCtrl->board.intEnable) 
  156. (*pDrvCtrl->board.intEnable)(unit)
  157. #define BOARD_INT_DISABLE(unit) if ((int)pDrvCtrl->board.intDisable) 
  158. (*pDrvCtrl->board.intDisable)(unit)
  159. #define BOARD_INT_ACK(unit) if ((int)pDrvCtrl->board.intAck) 
  160. (*pDrvCtrl->board.intAck)(unit)
  161. #define LOCAL_TO_SYS_ADDR(unit,localAddr) ((int)pDrvCtrl->board.sysLocalToBus? 
  162. (*pDrvCtrl->board.sysLocalToBus)(unit,localAddr):localAddr)
  163. #define SYS_TO_LOCAL_ADDR(unit,sysAddr) ((int)pDrvCtrl->board.sysBusToLocal? 
  164.         (*pDrvCtrl->board.sysBusToLocal)(unit,sysAddr):sysAddr)
  165. #define SYS_INT_CONNECT(vector, routine, parameter) (feiIntConnect 
  166.         ((VOIDFUNCPTR *) vector, routine, (int) parameter)) 
  167. #define I82557_INT_ENABLE pDrvCtrl->pCSR->scbCommand = 0
  168. #define I82557_INT_DISABLE  pDrvCtrl->pCSR->scbCommand = SCB_C_M
  169. /* typedefs */
  170. typedef struct mbuf MBUF;
  171. typedef struct arpcom IDR;
  172. typedef struct ifnet IFNET;
  173. typedef struct sockaddr SOCK;
  174. typedef struct drv_ctrl /* DRV_CTRL */
  175.     {
  176.     IDR idr; /* interface data record */
  177.     BOOL attached; /* interface has been attached */
  178.     CSR * pCSR; /* Control/Status Register ptr */
  179.     CFD * pCFD; /* current Command Frame Descriptor */
  180.     RFD * pRFD; /* current Receive Frame Descriptor */
  181.     RFD * pRFDL; /* first loanable RFD */
  182.  
  183.     WDOG_ID             txRestart;      /* tx restart watchdog */
  184.     BOOL rxHandle; /* rx handler scheduled */
  185.     BOOL                txStall;        /* tx handler stalled - no CFDs */
  186.     /* Board specific routines to manupalate this device */
  187.     BOARD_INFO board;
  188.     } DRV_CTRL;
  189. /* globals */
  190. FUNCPTR feiIntConnect = (FUNCPTR) intConnect; 
  191. IMPORT STATUS sys557Init (int unit, BOARD_INFO *pBoard);
  192. /* locals */
  193. LOCAL DRV_CTRL drvCtrl [FEI_MAX_UNITS];
  194. LOCAL int feiClkRate = 0;
  195. /* forward declarations */
  196. LOCAL STATUS feiInit (int unit);
  197. LOCAL void feiReset (int unit);
  198. LOCAL int feiIoctl (IFNET *pIfNet, int cmd, caddr_t data);
  199. #ifdef BSD43_DRIVER
  200. LOCAL int feiOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDestAddr);
  201. LOCAL void feiTxStartup (int unit);
  202. #else
  203. LOCAL void feiTxStartup (DRV_CTRL *pDrvCtrl);
  204. #endif
  205. LOCAL void      feiTxRestart (int unit);
  206. LOCAL void feiInt (DRV_CTRL *pDrvCtrl);
  207. LOCAL void feiHandleRecvInt (DRV_CTRL *pDrvCtrl);
  208. LOCAL STATUS feiReceive (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  209. LOCAL void feiLoanFree (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  210. LOCAL STATUS feiNOP (int unit);
  211. LOCAL STATUS feiDiag (int unit);
  212. LOCAL STATUS feiConfig (int unit);
  213. LOCAL STATUS feiIASetup (int unit);
  214. LOCAL UINT16 feiAction (int unit, UINT16 action);
  215. LOCAL STATUS feiSCBCommand (DRV_CTRL *pDrvCtrl, UINT8 cmd, BOOL addrValid,
  216.     UINT32 *addr);
  217. #ifdef  FEI_DEBUG
  218. LOCAL STATUS feiErrCounterDump ( int unit, UINT32 *memAddr);
  219. LOCAL STATUS feiDumpPrint (int unit);
  220. #endif /* FEI_DEBUG */
  221. static int feiMDIWrite ( int unit, int regAddr, int phyAddr, UINT16 writeData);
  222. static int feiMDIRead ( int unit, int regAddr, int phyAddr, UINT16 *retVal);
  223. static int feiPhyInit (int unit);
  224. static int feiMDIPhyConfig ( int unit, int phyAddr);
  225. static int feiMDIPhyLinkSet ( int unit, int phyAddr);
  226. /*******************************************************************************
  227. *
  228. * feiattach - publish the `fei' network interface
  229. *
  230. * This routine publishes the `fei' interface by filling in a network interface
  231. * record and adding the record to the system list.
  232. *
  233. * The 82557 shares a region of main memory with the CPU.  The caller of this
  234. * routine can specify the address of this shared memory region through the
  235. * <memBase> parameter; if <memBase> is set to the constant `NONE', the
  236. * driver will allocate the shared memory region.
  237. *
  238. * If the caller provides the shared memory region, the driver assumes
  239. * that this region does not require cache coherency operations.
  240. *
  241. * If the caller indicates that feiattach() must allocate the shared memory
  242. * region, feiattach() will use cacheDmaMalloc() to obtain a block
  243. * of non-cacheable memory.  The attributes of this memory will be checked,
  244. * and if the memory is not both read and write coherent, feiattach() will
  245. * abort and return ERROR.
  246. *
  247. * A default number of 32 command (transmit) and 32 receive frames can be
  248. * selected by passing zero in the parameters <nCFD> and <nRFD>, respectively.
  249. * If <nCFD> or <nRFD> is used to select the number of frames, the values
  250. * should be greater than two.
  251. *
  252. * A default number of 8 loanable receive frames can be selected by passing
  253. * zero in the parameters <nRFDLoan>, else set <nRFDLoan> to the desired
  254. * number of loanable receive frames.  If <nRFDLoan> is set to -1, no
  255. * loanable receive frames will be allocated/used.
  256. *
  257. * RETURNS: OK, or ERROR if the driver could not be published and initialized.
  258. *
  259. * SEE ALSO: ifLib,
  260. * .I "Intel 82557 User's Manual"
  261. */
  262. STATUS feiattach
  263.     (
  264.     int unit, /* unit number */
  265.     char * memBase, /* address of shared memory (NONE = malloc) */
  266.     int         nCFD,           /* command frames (0 = default) */
  267.     int         nRFD,           /* receive frames (0 = default) */
  268.     int         nRFDLoan        /* loanable rx frames (0 = default, -1 = 0) */
  269.     )
  270.     {
  271.     DRV_CTRL * pDrvCtrl; /* driver control structure pointer */
  272.     WDOG_ID     txWd = NULL;            /* tx restart watchdog */
  273.     CFD * pCFD; /* pointer to CFDs */
  274.     RFD * pRFD; /* pointer to RFDs */
  275.     UINT32 size; /* temporary size holder */
  276.     UINT32 sizeCFD = ROUND_UP (sizeof (CFD), 4);
  277.     UINT32 sizeRFD = ROUND_UP (sizeof (RFD), 4);
  278.     int ix; /* counter */
  279.     char  bucket[2];
  280.     BOOL        memAlloc = FALSE;
  281.     /* sanity check the unit number */
  282.     if (unit < 0 || unit >= FEI_MAX_UNITS)
  283.         return (ERROR);
  284.     pDrvCtrl = &drvCtrl [unit];
  285.     if (pDrvCtrl->attached) /* already attached ? */
  286.         return (ERROR);
  287.     /* initialize the default parameter for the Physical medium layer control*/
  288.     /* user has his chance to override in the BSP, just be CAREFUL */
  289.     pDrvCtrl->board.phyAddr  = 1;
  290.     pDrvCtrl->board.phySpeed = PHY_AUTO_SPEED;
  291.     pDrvCtrl->board.phyDpx   = PHY_AUTO_DPX;
  292.     pDrvCtrl->board.others   = 0;
  293.     pDrvCtrl->board.tcbTxThresh = TCB_TX_THRESH;
  294.     
  295.     /* callout to perform adapter init */
  296.     if (sys557Init (unit, &pDrvCtrl->board) == ERROR)
  297.         return (ERROR);
  298.     /* get CSR address from PCI config space base register */
  299.     if ((int)(pDrvCtrl->pCSR = (CSR *)pDrvCtrl->board.baseAddr) == NULL)
  300.         return (ERROR);
  301.     /* probe for memory-mapped CSR */
  302.     if (vxMemProbe ((char *) &pDrvCtrl->pCSR->scbStatus, VX_READ, 2,
  303. &bucket[0]) != OK)
  304.         {
  305.         printf ("feiattach(): need MMU mapping for address 0x%xn", (UINT32)
  306.     pDrvCtrl->pCSR);
  307. return (ERROR);
  308. }
  309.     I82557_INT_DISABLE; 
  310.     /* initialize the Physical medium layer */
  311.     if (feiPhyInit(unit) != OK)
  312. {
  313. printf("LINK FAILS, Check line connectionn");
  314. }
  315.     if (feiClkRate == 0)
  316. feiClkRate = sysClkRateGet ();
  317.     /* determine number of Command and Receive Frame descriptors to use */
  318.     nCFD     = nCFD ? nCFD : FEI_CFD_DEF;
  319.     nRFD     = nRFD ? nRFD : FEI_RFD_DEF;
  320.     nRFDLoan = nRFDLoan ? nRFDLoan : FEI_RFD_LOAN;
  321.     if (nRFDLoan == -1)
  322.         nRFDLoan = 0;
  323.     /* publish the interface record */
  324. #ifdef BSD43_DRIVER
  325.     ether_attach ((IFNET *) & pDrvCtrl->idr, unit, "fei", (FUNCPTR) feiInit,
  326.         (FUNCPTR) feiIoctl, (FUNCPTR) feiOutput, (FUNCPTR) feiReset);
  327. #else
  328.     ether_attach (
  329.                  (IFNET *) & pDrvCtrl->idr, 
  330.                  unit, 
  331.                  "fei", 
  332.                  (FUNCPTR) feiInit,
  333.                  (FUNCPTR) feiIoctl, 
  334.                  (FUNCPTR) ether_output,
  335.                  (FUNCPTR) feiReset
  336.                  );
  337.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)feiTxStartup;
  338. #endif
  339.     /* calculate the total size of 82557 memory pool */
  340.     size = (sizeRFD * (nRFD + nRFDLoan)) + (sizeCFD * nCFD);
  341.     /*
  342.      * Establish the memory area that we will share with the device.  If
  343.      * the caller has provided an area, then we assume it is non-cacheable.
  344.      * If the caller did not provide an area, then we must obtain it from
  345.      * the system, using the cache savvy allocation routine.
  346.      */
  347.     if (memBase == (char *) NONE) /* allocate on our own */
  348. {
  349.         /* this driver doesn't handle incoherent caches */
  350.         if (!CACHE_DMA_IS_WRITE_COHERENT () || !CACHE_DMA_IS_READ_COHERENT ())
  351.             {
  352.             printf ("feiattach: shared memory not cache coherentn");
  353.             goto error;
  354.             }
  355.         if ((memBase = cacheDmaMalloc (size)) == NULL)
  356.             {
  357.             printf ("feiattach: could not obtain memoryn");
  358.             goto error;
  359.             }
  360.         memAlloc = TRUE;
  361.         }
  362.     bzero (memBase, size);              /* zero out entire region */
  363.     /* carve up the shared-memory region */
  364.     /*
  365.      * N.B.
  366.      * We are setting up the CFD list as a ring of TxCBs, tied off with a
  367.      * CFD_C_SUSP as frames are copied into the data buffers.  The
  368.      * susp/resume model is used because the links to the next CFDs do
  369.      * not change -- it is a fixed ring.  Also note that if a CFD is needed
  370.      * for anything else (e.g., DIAG, NOP, DUMP, CONFIG, or IASETUP comands),
  371.      * then the commands will use the current CFD in the list.  After the
  372.      * command is complete, it will be set back to a TxCB by feiAction().
  373.      */
  374.     /* First ready CFD pointer */
  375.     pDrvCtrl->pCFD = pCFD = (CFD *) memBase;
  376.     /* initialize the CFD ring */
  377.     for (ix = 0; ix < nCFD; ix++, pCFD++)
  378. {
  379. pCFD->cfdStatus = CFD_S_COMPLETE | CFD_S_OK;  
  380.         /* System bus address to link field */
  381. LINK_WR (&pCFD->link, 
  382.             LOCAL_TO_SYS_ADDR(unit,((UINT32) pCFD + sizeCFD)) );
  383. /* Previous CFD pointer */
  384.         pCFD->pPrev = (CFD *) ((UINT32) pCFD - sizeCFD);
  385. LINK_WR (&pCFD->cfdTcb.pTBD, 0xffffffff); /* no TBDs used */
  386. pCFD->cfdTcb.txThresh = pDrvCtrl->board.tcbTxThresh;
  387. pCFD->cfdTcb.tbdNum = 0;
  388. }
  389.     pCFD--;
  390.     LINK_WR (&pCFD->link, LOCAL_TO_SYS_ADDR(unit,(UINT32)pDrvCtrl->pCFD) )
  391.         ; /* tie end of CFD ring, use system bus address */
  392.     pDrvCtrl->pCFD->pPrev = pCFD;
  393.     /*
  394.      * N.B.
  395.      * Use RFD_C_EL to tie the end of the RBD ring, and not RFD_C_SUSP
  396.      * This is because we want the option of inserting a new RFD into
  397.      * the ring on the fly (i.e., via an SCB_RUSTART command).  Why would
  398.      * we do this?  Buffer loaning....  A suspend/resume reception model
  399.      * will not allow us to do this, so we must use an idle/start model.
  400.      */
  401.     /* first ready RFD pointer */
  402.     pDrvCtrl->pRFD = pRFD = (RFD *) ((UINT32) pCFD + sizeCFD);
  403.     /*initialize the RFD ring,some of the fields will be done later in feiInit*/
  404.     for (ix = 0; ix < nRFD; ix++, pRFD++)
  405. {
  406. /* system bus address to link field */
  407. LINK_WR (&pRFD->link,
  408.             LOCAL_TO_SYS_ADDR(unit, ((UINT32) pRFD + sizeRFD)) );
  409.         /* previous RFD pointer */
  410.         pRFD->pPrev = (RFD *) ((UINT32) pRFD - sizeRFD);
  411. LINK_WR (&pRFD->pRBD, 0xffffffff); /* no RBDs used */
  412. pRFD->bufSize = ETHERMTU + EH_SIZE;
  413. pRFD->refCnt = 0;
  414.         pRFD->actualCnt = 0;
  415.         }
  416.     pRFD--;
  417.     LINK_WR (&pRFD->link,LOCAL_TO_SYS_ADDR(unit,(UINT32)pDrvCtrl->pRFD) )
  418.         ; /* tie end of RFD ring, use system bus address */
  419.     pDrvCtrl->pRFD->pPrev = pRFD;
  420.     /* initialize the RFD loanable buffers  */
  421.     pDrvCtrl->pRFDL = NULL;
  422.     pRFD++;
  423.     for (ix = 0; ix < nRFDLoan; ix++, pRFD++)
  424. {
  425. pRFD->rfdStatus = 0;
  426. pRFD->rfdCommand = 0;
  427. LINK_WR (&pRFD->pRBD, 0xffffffff); /* no RBDs used */
  428. pRFD->bufSize = ETHERMTU + EH_SIZE;
  429. pRFD->refCnt = 0;
  430. pRFD->actualCnt = 0;
  431.         pRFD->pPrev = pDrvCtrl->pRFDL;          /* link into head of list */
  432.         pDrvCtrl->pRFDL = pRFD;
  433.         }
  434.     if ((pDrvCtrl->txRestart = txWd = wdCreate ()) == NULL)
  435.         goto error;
  436.     feiReset (unit); /* reset the chip */
  437.     /* CU and RU should be idle following feiReset() */
  438.     if (feiSCBCommand (pDrvCtrl, SCB_C_CULDBASE, TRUE, 0x0) == ERROR)
  439.         goto error;
  440.     if (feiSCBCommand (pDrvCtrl, SCB_C_RULDBASE, TRUE, 0x0) == ERROR)
  441.         goto error;
  442.      /* connect the interrupt handler */
  443.     if (pDrvCtrl->board.vector)
  444.         {
  445.         if (SYS_INT_CONNECT(INUM_TO_IVEC (pDrvCtrl->board.vector), 
  446.                                 feiInt, pDrvCtrl) == ERROR)
  447.             goto error;
  448.         }
  449.     /* get our ethernet hardware address */
  450.     bcopy ((char *)pDrvCtrl->board.enetAddr, (char *) pDrvCtrl->idr.ac_enaddr, 
  451.    sizeof (pDrvCtrl->board.enetAddr));
  452.     if (feiDiag (unit) == ERROR) /* run diagnostics */
  453. goto error;
  454.     if (feiIASetup (unit) == ERROR) /* setup address */
  455. goto error;
  456.     if (feiConfig (unit) == ERROR) /* configure chip */
  457. goto error;
  458.     pDrvCtrl->rxHandle = FALSE;
  459.     pDrvCtrl->txStall = FALSE;
  460.     pDrvCtrl->attached = TRUE;
  461.     if (feiInit (unit) == ERROR)
  462.         goto error;
  463.  
  464.     return (OK);
  465. error: /* error cleanup */
  466.         {
  467.         if (memAlloc)
  468.             cacheDmaFree (memBase);
  469.         if (txWd)
  470.             wdDelete (txWd);
  471.         return (ERROR);
  472.         }
  473.     }
  474. /*******************************************************************************
  475. *
  476. * feiInit - initialize the 82557 device
  477. *
  478. * This routine initializes the 82557 device and brings it up to an operational
  479. * state.  The driver must have already been attached with the feiattach()
  480. * routine.
  481. *
  482. * This routine is called at boot time and by feiWatchDog() if a reset is
  483. * required.
  484. *
  485. * RETURNS: OK, or ERROR if the device could not be initialized.
  486. */
  487. LOCAL STATUS feiInit 
  488.     (
  489.     int unit /* unit number */
  490.     )
  491.     {
  492.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  493.     RFD *       pRFD;
  494.     UINT16      event;
  495.     int         ix;
  496.     if (!pDrvCtrl->attached)            /* must have been attached */
  497.         return (ERROR);
  498.     /* wait for the receive handler to catch up to the [reset] 557 */
  499.     for (ix = (FEI_INIT_TMO * feiClkRate); --ix;)
  500.         {
  501.         if (!pDrvCtrl->rxHandle)
  502.             break;
  503.         taskDelay (1);
  504.         }
  505.     if (!ix)
  506.         return (ERROR);
  507.     /* initiailize RFD ring */
  508.     pRFD = pDrvCtrl->pRFD;
  509.     do {
  510.         pRFD->rfdStatus = 0;
  511.         pRFD->rfdCommand = 0;
  512.         pRFD = (RFD *) SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD (&pRFD->link));
  513.         } while (pRFD != pDrvCtrl->pRFD);
  514.     pRFD->pPrev->rfdCommand = RFD_C_EL;
  515.     if (feiNOP (unit) == ERROR)         /* put CU into suspended state */
  516.         return (ERROR);
  517.     event = pDrvCtrl->pCSR->scbStatus;  /* save int events */
  518.     pDrvCtrl->pCSR->scbStatus = event;
  519.     BOARD_INT_ACK(unit);   /* acknowledge interrupts */
  520.     I82557_INT_ENABLE;
  521.     BOARD_INT_ENABLE(unit);         /* enable interrupts at system */
  522.     /* mark the interface as up */
  523. #ifdef BSD43_DRIVER
  524.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  525. #else
  526.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_MULTICAST| IFF_UP | IFF_RUNNING
  527.     | IFF_NOTRAILERS);
  528. #endif
  529.     /* startup the receiver */
  530.     if (feiSCBCommand (pDrvCtrl, SCB_C_RUSTART, TRUE,
  531.         (UINT32 *)LOCAL_TO_SYS_ADDR(unit, (UINT32) pRFD) ) == ERROR)
  532.         return (ERROR);
  533.     return (OK);
  534.     }
  535. /*******************************************************************************
  536. *
  537. * feiReset - reset the `fei' interface
  538. *
  539. * This routine marks the interface as inactive and resets the chip.  It brings
  540. * down the interface to a non-operational state.  To bring the interface back
  541. * up, feiInit() must be called.
  542. *
  543. * RETURNS: N/A
  544. */
  545. LOCAL void feiReset
  546.     (
  547.     int unit /* unit number of interface */
  548.     )
  549.     {
  550.     DRV_CTRL * pDrvCtrl = &drvCtrl [unit];
  551.     BOARD_INT_DISABLE(unit);     /* disable system interrupt */
  552.     I82557_INT_DISABLE;          /* disable chip interrupt   */
  553.     /* mark the interface as down */
  554.     pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
  555.     /* issue a selective reset to the 82557 chip */
  556.     PORT_WR (&pDrvCtrl->pCSR->port, FEI_PORT_SELRESET);
  557.     taskDelay (2); /* wait for the reset... */
  558.     }
  559. /*******************************************************************************
  560. *
  561. * feiIoctl - interface control request routine
  562. *
  563. * This routine processes the interface's ioctl() request.
  564. *
  565. * RETURNS: OK, or EINVAL if <cmd> is not recognized.
  566. */
  567. LOCAL int feiIoctl
  568.     (
  569.     IFNET * pIfNet, /* interface to act upon */
  570.     int cmd, /* command to process */
  571.     caddr_t data /* command-specific data */
  572.     )
  573.     {
  574.     DRV_CTRL *  pDrvCtrl = & drvCtrl [pIfNet->if_unit];
  575.     int retVal = OK;
  576.     int s = splimp (); /* not taken in some calling funcs */
  577.     switch (cmd)
  578.         {
  579.         case SIOCSIFADDR: /* set interface address */
  580. #ifdef BSD43_DRIVER
  581.             retVal = set_if_addr (pIfNet, data, pDrvCtrl->idr.ac_enaddr);
  582. #else
  583.             ((struct arpcom *)pIfNet)->ac_ipaddr = IA_SIN (data)->sin_addr;
  584.             arpwhohas ((struct arpcom *) pIfNet, &IA_SIN (data)->sin_addr);
  585. #endif
  586.             break;
  587.         case SIOCSIFFLAGS: /* set interface flags */
  588.             break;
  589. #ifdef BSD44_DRIVER
  590.         case SIOCADDMULTI:
  591.         case SIOCDELMULTI:
  592.             pDrvCtrl->idr.ac_if.if_flags |= IFF_PROMISC;
  593.             retVal = OK;
  594.             break;
  595. #endif
  596.             
  597.         default:
  598.             retVal = EINVAL;
  599.         }
  600.     splx (s);
  601.     return (retVal);
  602.     }
  603. #ifdef BSD43_DRIVER
  604. /*******************************************************************************
  605. *
  606. * feiOutput - interface output routine
  607. *
  608. * This routine simply calls ether_output().  ether_output() resolves
  609. * the hardware addresses and calls feiTxStartup() with the unit number
  610. * passed as an argument.
  611. *
  612. * RETURNS: OK if successful, otherwise `errno'.
  613. */
  614. LOCAL int feiOutput
  615.     (
  616.     IDR * pIDR,
  617.     MBUF * pMbuf,
  618.     SOCK * pDestAddr
  619.     )
  620.     {
  621.     return (ether_output ((IFNET *) pIDR, pMbuf, pDestAddr,
  622. (FUNCPTR) feiTxStartup, pIDR));
  623.     }
  624. #endif
  625. /*******************************************************************************
  626. *
  627. * feiTxStartup - transmit frames on the device
  628. *
  629. * Look for packets on the IP output queue; output frames if there is anything
  630. * there.
  631. *
  632. * This routine is called from several possible threads.  Each will be described
  633. * below.
  634. *
  635. * The first (and most common thread) is when a user task requests the
  636. * transmission of data.  Under BSD 4.3, this will cause feiOutput() to be  
  637. * called, which will cause ether_output() to be called, which will cause this 
  638. * routine to be called (usually). This routine will not be called if  
  639. * ether_output() finds that our interface output queue is full.  In this case, 
  640. * the outgoing data will be thrown out. BSD 4.4 uses a slight different model
  641. * in which the generic ether_output() is called directly, followed by a call 
  642. * to this routine.
  643. *
  644. * The second, and most obscure thread, is when the reception of certain
  645. * packets causes an immediate (attempted) response.  For example, ICMP echo
  646. * packets (ping), and ICMP "no listener on that port" notifications.  All
  647. * functions in this driver that handle the reception side are executed in the
  648. * context of netTask().  Always.  So, in the case being discussed, netTask()
  649. * will receive these certain packets, cause IP to be stimulated, and cause the
  650. * generation of a response to be sent.  We then find ourselves following the
  651. * first thread explained above, with the important distinction that the
  652. * context is that of netTask().
  653. *
  654. * The third thread occurs when this routine runs out of CFDs and returns.  If
  655. * this occurs when our output queue is not empty, this routine would typically
  656. * not get called again until new output was requested.  Even worse, if the
  657. * output queue was also full, this routine would never get called again and
  658. * we would have a lock state.  It DOES happen.  To guard against this,
  659. * we turn on a watchdog timer to scedule us again after an appropriate timeout.
  660. *
  661. * Note that this function is ALWAYS called between an splnet() and an splx().
  662. * This is true because netTask(), and ether_output() take care of
  663. * this when calling this function.  Therefore, no calls to these spl functions
  664. * are needed anywhere in this output thread.  Thus, mutual exclusion is
  665. * guaranteed.
  666. *
  667. * RETURNS: N/A
  668. */
  669. LOCAL void feiTxStartup
  670.     (
  671. #ifdef BSD43_DRIVER
  672.     int unit
  673. #else
  674.     DRV_CTRL *  pDrvCtrl 
  675. #endif
  676.     )
  677.     {
  678. #ifdef BSD43_DRIVER
  679.     DRV_CTRL * pDrvCtrl = &drvCtrl [unit];
  680. #else
  681.     int unit = pDrvCtrl->idr.ac_if.if_unit;
  682. #endif
  683.     CFD *pCFD = pDrvCtrl->pCFD;
  684.     CFD *pCFDNext;
  685.     MBUF * pMbuf;
  686.     int length;
  687.     int status = OK;
  688.     /* loop until no more tx packets or we are out of tx resources */
  689.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  690.         {
  691.         pCFDNext = (CFD *) SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD(&pCFD->link));
  692.         if (!(pCFDNext->cfdStatus & CFD_S_COMPLETE)) /* next CFD free ? */
  693.             {
  694.             pDrvCtrl->txStall = TRUE;
  695.             wdStart (pDrvCtrl->txRestart, FEI_TX_RESTART_TMO * feiClkRate,
  696.                 (FUNCPTR) feiTxRestart, unit);
  697.             break;
  698.             }
  699.         if (pDrvCtrl->txStall)
  700.             wdCancel (pDrvCtrl->txRestart);
  701.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf); /* dequeue a packet */
  702.         copy_from_mbufs (pCFD->cfdTcb.enetHdr, pMbuf, length);
  703.         length = max (ETHERSMALL, length); /* short frames are padded */
  704.         if ((etherOutputHookRtn != NULL) && (*etherOutputHookRtn)
  705.             (&pDrvCtrl->idr, pCFD->cfdTcb.enetHdr, length))
  706.             continue; /* hook routine ate packet */
  707. /* get frame ready for transmission */
  708.         pCFD->cfdTcb.count = (length & 0x3fff) | TCB_CNT_EOF;
  709. pCFD->cfdStatus = 0;
  710. pCFD->cfdCommand = CFD_C_XMIT | CFD_C_SUSP;
  711. pCFD->pPrev->cfdCommand &= ~CFD_C_SUSP; /* hook frame into CBL */
  712. /* undates the first ready RFD pointer */
  713. pDrvCtrl->pCFD =
  714.     (CFD *)SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD(&pCFD->link) );
  715.         /* Bump the statistic counter. */
  716.         pDrvCtrl->idr.ac_if.if_opackets++;
  717. /* resume CU operation ? (check suspended, not sent yet, cmd return) */
  718. if (((pDrvCtrl->pCSR->scbStatus & SCB_S_CUMASK) == SCB_S_CUSUSP) &&
  719.     (pCFD->cfdStatus == 0) )
  720.     {
  721.     status =feiSCBCommand (pDrvCtrl, SCB_C_CURESUME, FALSE, 0);
  722.     if (status == ERROR)
  723.         break;
  724.             }
  725.         }
  726.         /* make sure the last CFD is  transmitted */            
  727.         if (pCFD->cfdStatus == 0)
  728.             feiSCBCommand (pDrvCtrl, SCB_C_CURESUME, FALSE, 0);
  729.     }
  730. /*******************************************************************************
  731. *
  732. * feiTxRestart - reschedule transmit processing
  733. *
  734. * Reschedule transmit processing because we previously had no available
  735. * CFDs.
  736. *
  737. * RETURNS: N/A
  738. */
  739. LOCAL void feiTxRestart
  740.     (
  741.     int         unit
  742.     )
  743.     {
  744.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  745.     pDrvCtrl->txStall = FALSE;
  746. #ifdef BSD43_DRIVER
  747.     (void) netJobAdd ((FUNCPTR) feiTxStartup, unit, 0, 0, 0, 0);
  748. #else
  749.     (void) netJobAdd ((FUNCPTR) feiTxStartup, (int)pDrvCtrl, 0, 0, 0, 0);
  750. #endif
  751.     }
  752. /*******************************************************************************
  753. *
  754. * feiInt - entry point for handling interrupts from the 82557
  755. *
  756. * The interrupting events are acknowledged to the device, so that the device
  757. * will de-assert its interrupt signal.  The amount of work done here is kept
  758. * to a minimum; the bulk of the work is defered to the netTask.
  759. *
  760. * RETURNS: N/A
  761. */
  762. LOCAL void feiInt
  763.     (
  764.     DRV_CTRL * pDrvCtrl
  765.     )
  766.     {
  767.     UINT16 event;
  768.     int unit = pDrvCtrl->idr.ac_if.if_unit;
  769.     event = pDrvCtrl->pCSR->scbStatus; /* save int events */
  770.     if ((event & SCB_S_STATMASK) == 0)
  771.         {
  772.         /* This device was not the cause of the shared int */
  773.  
  774.         return; 
  775.         }
  776.  
  777.     /* clear chip level interrupt pending */
  778.     pDrvCtrl->pCSR->scbStatus = (event&SCB_S_STATMASK); 
  779.     /* board level interrupt acknowledge */
  780.     BOARD_INT_ACK(unit);
  781. #ifdef FEI_DEBUG
  782.     if (feiDebug)
  783.         logMsg ("feiInt: event 0x%x, scbStatus 0x%xn", event, 
  784.      pDrvCtrl->pCSR->scbStatus, 0, 0, 0, 0);
  785. #endif /* FEI_DEBUG */
  786.     /* handle receive interrupts */
  787.     if ( (event & SCB_S_FR) && !(pDrvCtrl->pCSR->scbCommand & SCB_C_M)) 
  788. {
  789.         I82557_INT_DISABLE;
  790.         pDrvCtrl->rxHandle = TRUE;
  791.         (void) netJobAdd ((FUNCPTR) feiHandleRecvInt, (int) pDrvCtrl,
  792.             0, 0, 0, 0);
  793.         }
  794.     }
  795.     
  796. /*******************************************************************************
  797. *
  798. * feiHandleRecvInt - service task-level interrupts for receive frames
  799. *
  800. * This routine is run in netTask's context.  The ISR scheduled
  801. * this routine so that it could handle receive packets at task level.
  802. *
  803. * RETURNS: N/A
  804. */
  805. LOCAL void feiHandleRecvInt
  806.     (
  807.     DRV_CTRL * pDrvCtrl
  808.     )
  809.     {
  810.     RFD * pRFD = pDrvCtrl->pRFD;
  811.     RFD * pRFDNew;
  812.     int unit = pDrvCtrl->idr.ac_if.if_unit;
  813.     while (pRFD->rfdStatus & RFD_S_COMPLETE)   /* while packets to process */
  814.         {
  815.         pDrvCtrl->rxHandle = TRUE;             /* interlock with eiInt() */
  816. if (!(pRFD->rfdStatus & RFD_S_OK))
  817.     pDrvCtrl->idr.ac_if.if_ierrors++;
  818. else
  819.     {
  820.     if (feiReceive (pDrvCtrl, pRFD) == ERROR)
  821. {
  822. /* buffer loaning was done */
  823.                 pRFDNew = pDrvCtrl->pRFDL;
  824.                 pDrvCtrl->pRFDL = pRFDNew->pPrev;
  825. LINK_WR (&pRFD->pPrev->link, 
  826.     LOCAL_TO_SYS_ADDR(unit,(UINT32)pRFDNew));
  827. LINK_WR (&pRFDNew->link, LINK_RD (&pRFD->link));
  828. pRFDNew->pPrev = pRFD->pPrev;
  829. pRFD = (RFD *) SYS_TO_LOCAL_ADDR(unit,
  830.     (UINT32)LINK_RD (&pRFD->link));
  831. pRFD->pPrev = pRFDNew;
  832. pRFD = pRFDNew;
  833. }
  834.     }
  835.         pRFD->rfdStatus = 0;
  836.         pRFD->rfdCommand = RFD_C_EL;            /* chip can have it.... */
  837. pRFD->pPrev->rfdCommand &= ~RFD_C_EL;   /* hook frame into CBL */
  838.         pRFD = (RFD *) SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD (&pRFD->link) )
  839.             ;   /* bump to next RFD in ring */
  840.         pDrvCtrl->pCSR->scbStatus &= (SCB_S_FR | SCB_S_RNR);
  841.         }
  842.     pDrvCtrl->pRFD = pRFD;                      /* keep track of current RFD */
  843.     /* kick receiver (if needed) */
  844.     if ((pDrvCtrl->pCSR->scbStatus & SCB_S_RUMASK) != SCB_S_RURDY)
  845.         {
  846.         if (feiSCBCommand (pDrvCtrl, SCB_C_RUSTART, TRUE, 
  847.                     (UINT32 *)LOCAL_TO_SYS_ADDR(unit, (UINT32)pRFD)) == ERROR)
  848.             {
  849.     pDrvCtrl->rxHandle = FALSE;
  850.             return;
  851.     }
  852.         while ((pDrvCtrl->pCSR->scbCommand)&SCB_C_RUMASK)
  853.             ;      /* wait for RUSTART accept */
  854.         }
  855.     pDrvCtrl->rxHandle = FALSE;
  856.     /* re-enable receiver interrupts */
  857.     I82557_INT_ENABLE;
  858.     }
  859. /*******************************************************************************
  860. *
  861. * feiReceive - pass a received frame to the next layer up
  862. *
  863. * Strips the Ethernet header and passes the packet to the appropriate
  864. * protocol.  The return value indicates if buffer loaning was used to hold
  865. * the data.  A return value of OK means that loaning was not done.
  866. *
  867. * RETURNS: OK, or ERROR if buffer-loaning the RFD.
  868. */
  869. LOCAL STATUS feiReceive
  870.     (
  871.     DRV_CTRL * pDrvCtrl,
  872.     RFD * pRFD
  873.     )
  874.     {
  875.     struct ether_header * pEh;
  876.     u_char * pData;
  877.     int len;
  878.     UINT16 etherType;
  879.     MBUF * pMbuf = NULL;
  880.     STATUS retVal = OK;
  881.     len = pRFD->actualCnt & 0x3fff; /* get frame length */
  882.     pEh = (struct ether_header *)pRFD->enetHdr; /* get ptr to ethernet header */
  883.     pDrvCtrl->idr.ac_if.if_ipackets++;          /* bump statistic */
  884.     /* call hook routine if one is connected */
  885.     if ((etherInputHookRtn != NULL) && ((*etherInputHookRtn)
  886. (& pDrvCtrl->idr.ac_if, (char *) pEh, len)))
  887.         return (OK);
  888.     len -= EH_SIZE;
  889.     if (len <= 0)
  890. {
  891. pDrvCtrl->idr.ac_if.if_ierrors++;           /* bump error stat */
  892.         pDrvCtrl->idr.ac_if.if_ipackets--;          /* fix statistic */
  893. return (OK);
  894. }
  895.     pData = (u_char *) pRFD->enetData;
  896.     etherType = ntohs (pEh->ether_type);
  897.     if ((pDrvCtrl->pRFDL != NULL) && (USE_CLUSTER (len)) &&
  898.         ((pMbuf = build_cluster (pData, len, (struct ifnet *) &pDrvCtrl->idr, 
  899.  MC_FEI, &pRFD->refCnt, (FUNCPTR) feiLoanFree, 
  900.  (int) pDrvCtrl, (int) pRFD, NULL)) 
  901.  != NULL))
  902.         retVal = ERROR; /* we loaned a frame */
  903.     else
  904.         pMbuf = copy_to_mbufs (pData, len, 0, 
  905.        (struct ifnet *) &pDrvCtrl->idr);
  906.     if (pMbuf != NULL)
  907. {
  908. #ifdef BSD43_DRIVER
  909.         do_protocol_with_type (etherType, pMbuf, &pDrvCtrl->idr, len);
  910. #else
  911.         do_protocol (pEh, pMbuf, &pDrvCtrl->idr, len);
  912. #endif
  913. }
  914.     else
  915. {
  916. pDrvCtrl->idr.ac_if.if_ierrors++;           /* bump error stat */
  917.         pDrvCtrl->idr.ac_if.if_ipackets--;          /* fix statistic */
  918. }
  919.     return (retVal);
  920.     }
  921. /*******************************************************************************
  922. *
  923. * feiLoanFree - return a loaned receive frame descriptor
  924. *
  925. * This routine is called by the protocol code when it has completed use of
  926. * an RFD that we loaned to it.
  927. *
  928. * RETURNS: N/A
  929. */
  930. LOCAL void feiLoanFree
  931.     (
  932.     DRV_CTRL * pDrvCtrl,
  933.     RFD * pRFD
  934.     )
  935.     {
  936.     pRFD->refCnt = 0; /* should already be zero... */
  937.     pRFD->pPrev = pDrvCtrl->pRFDL;
  938.     pDrvCtrl->pRFDL = pRFD;
  939.     }
  940. /*******************************************************************************
  941. *
  942. * feiNOP - format and issue a NOP command
  943. *
  944. * RETURNS: OK, or ERROR if the NOP command failed.
  945. */
  946. LOCAL STATUS feiNOP
  947.     (
  948.     int unit
  949.     )
  950.     {
  951.     if (!(feiAction (unit, CFD_C_NOP) & CFD_S_OK))
  952. return (ERROR);
  953.     return (OK);
  954.     }
  955. /*******************************************************************************
  956. *
  957. * feiDiag - format and issue a diagnostic command
  958. *
  959. * RETURNS: OK, or ERROR if the diagnostic command failed.
  960. */
  961. LOCAL STATUS feiDiag
  962.     (
  963.     int unit
  964.     )
  965.     {
  966.     UINT16 stat;
  967.     if (((stat = feiAction (unit, CFD_C_DIAG)) &
  968.         (CFD_S_OK | CFD_S_DIAG_F)) != CFD_S_OK)
  969.         {
  970. #ifdef  FEI_DEBUG
  971.         if (feiDebug)
  972.             printf ("if_fei.c: 82557 diagnostics failed, cfdStatus 0x%xn",
  973.                 stat);
  974. #endif  /* FEI_DEBUG */
  975.         return (ERROR);
  976.         }
  977.     return (OK);
  978.     }
  979. /*******************************************************************************
  980. *
  981. * feiConfig - format and issue a config command
  982. *
  983. * RETURNS: OK, or ERROR if the config command failed.
  984. */
  985. LOCAL STATUS feiConfig
  986.     (
  987.     int unit
  988.     )
  989.     {
  990.     DRV_CTRL * pDrvCtrl = & drvCtrl [unit];
  991.     CFD * pCFD = pDrvCtrl->pCFD;
  992.     /* set to config values recommeded by the i82557 User's Manual */
  993.     pCFD->cfdConfig.ccByte0  = 0x16;
  994.     pCFD->cfdConfig.ccByte1  = 0x88;  /* 0x08;  */
  995.     pCFD->cfdConfig.ccByte2  = 0x00;
  996.     pCFD->cfdConfig.ccByte3  = 0x00;
  997.     pCFD->cfdConfig.ccByte4  = 0x00;   /* 0x00; */
  998.     pCFD->cfdConfig.ccByte5  = 0x00;   /* 0x80; */
  999.     pCFD->cfdConfig.ccByte6  = 0x38;   /* save bad frame,no TNO 0x3a; */
  1000.     pCFD->cfdConfig.ccByte7  = 0x03;   
  1001.     pCFD->cfdConfig.ccByte8  = 0x01; /* MII operation */
  1002.     pCFD->cfdConfig.ccByte9  = 0x00;
  1003.     pCFD->cfdConfig.ccByte10 = 0x2e;
  1004.     pCFD->cfdConfig.ccByte11 = 0x00;    
  1005.     pCFD->cfdConfig.ccByte12 = 0x60;
  1006.     pCFD->cfdConfig.ccByte13 = 0x00;
  1007.     pCFD->cfdConfig.ccByte14 = 0xf2;
  1008.     if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC)
  1009.         pCFD->cfdConfig.ccByte15 = 0x49;     /* 0x49;  */
  1010.     else
  1011.         pCFD->cfdConfig.ccByte15 = 0x48;     /* 0x49 PROMISC;  */
  1012.     pCFD->cfdConfig.ccByte16 = 0x00;
  1013.     pCFD->cfdConfig.ccByte17 = 0x40;
  1014.     pCFD->cfdConfig.ccByte18 = 0xf2;
  1015. if (pDrvCtrl->board.phyDpx != PHY_HALF_DPX)
  1016.     pCFD->cfdConfig.ccByte19 = 0x80;
  1017. else
  1018.     pCFD->cfdConfig.ccByte19 = 0x00; /*c0 force full deplex    0x80;   */
  1019.     pCFD->cfdConfig.ccByte20 = 0x3f;
  1020.     pCFD->cfdConfig.ccByte21 = 0x05;
  1021.     if (!(feiAction (unit, CFD_C_CONFIG) & CFD_S_OK))
  1022. return (ERROR);
  1023.     return (OK);
  1024.     }
  1025. /*******************************************************************************
  1026. *
  1027. * feiIASetup - format and issue an interface address command
  1028. *
  1029. * RETURNS: OK, or ERROR if the address command failed.
  1030. */
  1031. LOCAL STATUS feiIASetup
  1032.     (
  1033.     int unit
  1034.     )
  1035.     {
  1036.     DRV_CTRL * pDrvCtrl = & drvCtrl [unit];
  1037.     bcopy ((char *) pDrvCtrl->idr.ac_enaddr,
  1038. (char *) pDrvCtrl->pCFD->cfdIASetup.ciAddress, 6);
  1039.     if (!(feiAction (unit, CFD_C_IASETUP) & CFD_S_OK))
  1040. return (ERROR);
  1041.     return (OK);
  1042.     }
  1043. /*******************************************************************************
  1044. *
  1045. * feiAction - execute the specified action command
  1046. *
  1047. * This routine executes the specified action
  1048. *
  1049. * We do the command contained in the CFD synchronously, so that we know
  1050. * it's complete upon return.
  1051. *
  1052. * RETURNS: The status return of the action command, or 0 on failure.
  1053. */
  1054. LOCAL UINT16 feiAction
  1055.     (
  1056.     int unit,
  1057.     UINT16 action
  1058.     )
  1059.     {
  1060.     DRV_CTRL * pDrvCtrl = & drvCtrl [unit];
  1061.     CFD * pCFD = pDrvCtrl->pCFD;
  1062.     UINT16 retVal = 0;
  1063.     int ix;
  1064.     UINT8       state;
  1065.     if (!(pCFD->cfdStatus & CFD_S_COMPLETE)) /* next CFD free ? */
  1066. return (0);
  1067.     /* fill in CFD */
  1068.     pCFD->cfdStatus = 0; /* clear status */
  1069.     pCFD->cfdCommand = action | CFD_C_SUSP; /* fill in action */
  1070.     pCFD->pPrev->cfdCommand &= ~CFD_C_SUSP; /* hook into CBL */
  1071.     pDrvCtrl->pCFD = (CFD *) SYS_TO_LOCAL_ADDR(unit,
  1072. (UINT32)LINK_RD(&pCFD->link) ); /* bump current CFD */
  1073.     /* check CU operation -- kick if needed */
  1074.     if ((((state = pDrvCtrl->pCSR->scbStatus) & SCB_S_CUMASK) != SCB_S_CUACTIVE)
  1075.         && (pCFD->cfdStatus == 0))
  1076.         {
  1077.         if (state == SCB_S_CUIDLE)
  1078.             {
  1079.             if (feiSCBCommand (pDrvCtrl, SCB_C_CUSTART, TRUE,
  1080.                 (UINT32 *) LOCAL_TO_SYS_ADDR(unit,(UINT32)pCFD) ) == ERROR)
  1081.                 {
  1082. #ifdef  FEI_DEBUG
  1083.                 if (feiDebug)
  1084.                     printf ("feiAction: feiSCBCommand failedn");
  1085. #endif  /* FEI_DEBUG */
  1086.                 goto errorAction;
  1087.                 }
  1088.             }
  1089.         else
  1090.             {
  1091.             if (feiSCBCommand (pDrvCtrl, SCB_C_CURESUME, FALSE, 0x0) == ERROR)
  1092.                 {
  1093. #ifdef  FEI_DEBUG
  1094.                 if (feiDebug)
  1095.                     printf ("feiAction: feiSCBCommand failedn");
  1096. #endif  /* FEI_DEBUG */
  1097.                 goto errorAction;
  1098.                 }
  1099.             }
  1100.         }
  1101.     /* wait for command to complete */
  1102.     for (ix = (FEI_ACTION_TMO * feiClkRate); --ix;)
  1103. {
  1104.         if ((retVal = pCFD->cfdStatus) & CFD_S_COMPLETE)
  1105.             break;
  1106. taskDelay (1);
  1107.         }
  1108.     if (!ix)
  1109. {
  1110. #ifdef FEI_DEBUG
  1111.          printf ("feiAction: command 0x%x, CFD status 0x%xn", action,
  1112.      pCFD->cfdStatus);
  1113. #endif /* FEI_DEBUG */
  1114.         retVal = 0;
  1115.         goto errorAction;
  1116. }
  1117.     /* put CFD back to a TxCB - mirrors feiattach() */
  1118. errorAction:
  1119.     pCFD->cfdStatus = CFD_S_COMPLETE | CFD_S_OK;
  1120.     LINK_WR (&pCFD->cfdTcb.pTBD, 0xffffffff); /* no TBDs used */
  1121.     pCFD->cfdTcb.txThresh = pDrvCtrl->board.tcbTxThresh;
  1122.     pCFD->cfdTcb.tbdNum = 0;
  1123.     return (retVal);
  1124.     }
  1125. /*******************************************************************************
  1126. *
  1127. * feiSCBCommand - deliver a command to the 82557 via the SCB
  1128. *
  1129. * This function causes the device to execute a command. An error status is
  1130. * returned if the command field does not return to zero, from a previous
  1131. * command, in a reasonable amount of time.
  1132. *
  1133. * RETURNS: OK, or ERROR if the command field appears to be frozen.
  1134. */
  1135. LOCAL STATUS feiSCBCommand
  1136.     (
  1137.     DRV_CTRL * pDrvCtrl,
  1138.     UINT8 cmd,
  1139.     BOOL addrValid,
  1140.     UINT32 * addr
  1141.     )
  1142.     {
  1143.     int ix;
  1144.     for (ix = 0x8000; --ix;)
  1145. {
  1146. if ((pDrvCtrl->pCSR->scbCommand & SCB_CR_MASK) == 0)
  1147.     break;
  1148.         }
  1149.     if (!ix)
  1150. {
  1151. #ifdef  FEI_DEBUG
  1152.         if (feiDebug)
  1153.             printf ("feiSCBCommand: command 0x%x failed, scb 0x%xn", cmd,
  1154.                 pDrvCtrl->pCSR->scbCommand);
  1155. #endif  /* FEI_DEBUG */
  1156.         return (ERROR);
  1157.         }
  1158.     if (addrValid) /* optionally fill the GP */
  1159. LINK_WR (&pDrvCtrl->pCSR->scbGP, addr);
  1160.     pDrvCtrl->pCSR->scbCommand |= cmd; /* write SCB command byte */
  1161.     return (OK);
  1162.     }
  1163. #ifdef  FEI_DEBUG
  1164. /*******************************************************************************
  1165. *
  1166. * feiDumpPrint - Display statistical counters
  1167. *
  1168. * This routine displays i82557 statistical counters
  1169. *
  1170. * RETURNS: OK, or ERROR if the DUMP command failed.
  1171. */
  1172. LOCAL STATUS feiDumpPrint
  1173.     (
  1174.     int         unit
  1175.     )
  1176.     {
  1177.     UINT32      dumpArray [18];
  1178.     UINT32 *    pDump;
  1179.     STATUS status = OK;
  1180.     /* dump area must be long-word allign */
  1181.     pDump = (UINT32 *) (((UINT32) dumpArray + 4) & 0xfffffffc);
  1182.     status = feiErrCounterDump(unit,pDump); 
  1183.     printf ("n");
  1184.     printf ("Tx good frames:             %dn", *pDump++);
  1185.     printf ("Tx MAXCOL errors:           %dn", *pDump++);
  1186.     printf ("Tx LATECOL errors:          %dn", *pDump++);
  1187.     printf ("Tx underrun errors:         %dn", *pDump++);
  1188.     printf ("Tx lost CRS errors:         %dn", *pDump++);
  1189.     printf ("Tx deferred:                %dn", *pDump++);
  1190.     printf ("Tx single collisions:       %dn", *pDump++);
  1191.     printf ("Tx multiple collisions:     %dn", *pDump++);
  1192.     printf ("Tx total collisions:        %dn", *pDump++);
  1193.     printf ("Rx good frames:             %dn", *pDump++);
  1194.     printf ("Rx CRC errors:              %dn", *pDump++);
  1195.     printf ("Rx allignment errors:       %dn", *pDump++);
  1196.     printf ("Rx resource errors:         %dn", *pDump++);
  1197.     printf ("Rx overrun errors:          %dn", *pDump++);
  1198.     printf ("Rx collision detect errors: %dn", *pDump++);
  1199.     printf ("Rx short frame errors:      %dn", *pDump++);
  1200.     return (status);
  1201.     }
  1202. /*****************************************************************************
  1203. *
  1204. * feiErrCounterDump - dump statistical counters 
  1205. *
  1206. * This routine dumps statistical counters for the purpose of debugging and
  1207. * tuning the 82557.
  1208. *
  1209. * The <memAddr> parameter is the pointer to an array of 68 bytes in the
  1210. * local memory.  This memory region must be allocated before this routine is
  1211. * called.  The memory space must also be DWORD (4 bytes) aligned.  When the
  1212. * last DWORD (4 bytes) is written to a value, 0xa007, it indicates the dump
  1213. * command has completed.  To determine the meaning of each statistical
  1214. * counter, see the Intel 82557 manual.
  1215. *
  1216. * RETURNS: OK or ERROR.
  1217. */
  1218. LOCAL STATUS feiErrCounterDump 
  1219.     (
  1220.     int unit,
  1221.     UINT32 *memAddr
  1222.     )
  1223.     {
  1224.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  1225.     STATUS status = OK;
  1226.     int i; 
  1227.     int         s = splimp ();   /* block network access to 82557 resource */
  1228.     memAddr[16]=0;    /* make sure the last DWORD is 0 */
  1229.     /* tells the 82557 where to write dump data */
  1230.     if (feiSCBCommand (pDrvCtrl, SCB_C_CULDDUMP, TRUE,
  1231.     (UINT32 *) LOCAL_TO_SYS_ADDR(unit,(UINT32)memAddr) ) == ERROR)
  1232.         status = ERROR;
  1233.     /* issue the dump and reset counter command */
  1234.     if (feiSCBCommand (pDrvCtrl, SCB_C_CUDUMPRST,FALSE,(UINT32)0) == ERROR)
  1235. status = ERROR;
  1236.     
  1237.     splx (s);   /* release 82557 resource to network */
  1238.     /* waits for it done */ 
  1239.     for (i=0;i<60;i++)
  1240. {
  1241. if (memAddr[16] == (UINT32)0xa007)
  1242.     break;
  1243.         taskDelay(2);
  1244. }
  1245.     if (i==60)
  1246. status = ERROR;
  1247.     return (status);
  1248.     }
  1249. #endif  /* FEI_DEBUG */
  1250. /****************************************************************************
  1251. *
  1252. * feiMDIRead - read the MDI register
  1253. *
  1254. * This routine reads the specific register in the PHY device
  1255. * Valid PHY address is 0-31
  1256. *
  1257. * RETURNS: OK or ERROR.
  1258. *
  1259. */
  1260. static int feiMDIRead 
  1261.     (
  1262.     int unit,
  1263.     int regAddr,
  1264.     int phyAddr,
  1265.     UINT16 *retVal
  1266.     )
  1267.     {
  1268.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  1269.     int i;
  1270.     UINT32 mdrValue;
  1271.     volatile UINT32 *mdiReg = (volatile UINT32 *)&pDrvCtrl->pCSR->mdiCR;
  1272.    
  1273.     mdrValue = ((regAddr<<16) | (phyAddr << 21) | (MDI_READ<<26) );
  1274.    
  1275.     /* write to MDI */
  1276.     *mdiReg = mdrValue;
  1277.     taskDelay(2);    /* wait for a while */
  1278.     /* check if it's done */
  1279.     for (i=0;i<40;i++)
  1280.         {
  1281.         if ( (*mdiReg) & (1<<28) )
  1282.             break;
  1283.         taskDelay(1);
  1284.         }
  1285.      if (i==40)
  1286.          return (ERROR);
  1287.      *retVal = (UINT16)((*mdiReg)&0xffff);
  1288.      return(OK);
  1289.      } 
  1290. /**************************************************************************
  1291. *
  1292. * feiMDIWrite - write to the MDI register
  1293. *
  1294. * This routine writes the specific register in the PHY device
  1295. * Valid PHY address is 0-31
  1296. *
  1297. * RETURNS: OK or ERROR.
  1298. */
  1299. static int feiMDIWrite
  1300.     (
  1301.     int unit,
  1302.     int regAddr,
  1303.     int phyAddr,
  1304.     UINT16 writeData 
  1305.     )
  1306.     {
  1307.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  1308.     int i;
  1309.     UINT32 mdrValue;
  1310.     volatile UINT32 *mdrReg = (volatile UINT32 *)&pDrvCtrl->pCSR->mdiCR;
  1311.   
  1312.     mdrValue = ((regAddr<<16) | (phyAddr << 21) | (MDI_WRITE<<26) | writeData );
  1313.    
  1314.     /* write to M */
  1315.     *mdrReg = mdrValue;
  1316.     taskDelay(2);    /* wait for a while */
  1317.     /* check if it's done */
  1318.     for (i=0;i<40;i++)
  1319.         {
  1320.         if ( (*mdrReg) & (1<<28) )
  1321.             break;
  1322.         taskDelay(1);
  1323.         }
  1324.      if (i==40)
  1325.          return (ERROR);
  1326.      return(OK);
  1327.      }
  1328. /****************************************************************************
  1329. *
  1330. * feiMDIPhyLinkSet - detect and set the link for the PHY device
  1331. *
  1332. * This routine first checks if the link has been established.  If not, it
  1333. * isolates the other one, and tries to establish the link.  PHY device 0 is
  1334. * always at PHY address 0.  PHY 1 can be at 1-31 PHY addresses.
  1335. *
  1336. * RETURNS: OK or ERROR.
  1337. *
  1338. */
  1339. static int feiMDIPhyLinkSet
  1340.     (
  1341.     int unit,
  1342.     int phyAddr
  1343.     )
  1344.     {
  1345.     UINT16 ctlReg;
  1346.     UINT16 statusReg;
  1347.     int isoDev,i;
  1348.     /* read control register */
  1349.     feiMDIRead (unit, MDI_CTRL_REG, phyAddr, &ctlReg);
  1350.     /* read again */
  1351.     feiMDIRead (unit, MDI_CTRL_REG, phyAddr, &ctlReg);
  1352.     /* check if the PHY is there */
  1353.     if (ctlReg == (UINT16)0xffff)
  1354.         return (ERROR);   /* no PHY present */
  1355. #if 0
  1356.     /* CR RESET will cause link down */
  1357.     feiMDIWrite (unit,MDI_CTRL_REG,phyAddr,MDI_CR_RESET); 
  1358.     taskDelay(4);
  1359. #endif
  1360.     /* The PHY is there, read status register  */
  1361.     feiMDIRead (unit, MDI_STATUS_REG, phyAddr,&statusReg);
  1362.     /* in case the status bit is the latched bit */
  1363.     if ( !(statusReg & MDI_SR_LINK_STATUS))
  1364.         feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1365.     if (statusReg & MDI_SR_LINK_STATUS)
  1366.         return (OK);  /* Device found and link OK */
  1367.     /* no link is established, let's configure it */
  1368.     
  1369.     /* isolates the other PHY */
  1370.     isoDev = (phyAddr)?0:1;
  1371.     feiMDIWrite (unit,MDI_CTRL_REG,isoDev,MDI_CR_ISOLATE);
  1372.     /* wait for a while */
  1373.     taskDelay (2);
  1374.     /* enable the PHY device we try to configure */
  1375.     feiMDIWrite (unit,MDI_CTRL_REG,phyAddr,MDI_CR_SELECT);
  1376.     taskDelay (2); /* wait for a while for command take effect */
  1377.     /* restart the auto negotiation process, execute anyways even if
  1378.      * it has no such capability.
  1379.      */
  1380.     feiMDIWrite (unit,MDI_CTRL_REG,phyAddr,MDI_CR_RESTART | MDI_CR_SELECT);
  1381.     /* wait for auto-negotiation to complete */
  1382.     for (i=0;i<80;i++)
  1383.         {
  1384.         /* read the status register */
  1385.         feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1386.         feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1387.    
  1388.         if (statusReg & (MDI_SR_AUTO_NEG | MDI_SR_REMOTE_FAULT) )
  1389.             break;
  1390.         taskDelay (2);
  1391. if (!(statusReg & MDI_SR_AUTO_SELECT) )
  1392.     break;  /* no such capability */
  1393.         }
  1394.     /* Read the status register */
  1395.     feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1396.     /* some of the status bits require to clear a latch */
  1397.     if ( !(statusReg & MDI_SR_LINK_STATUS))
  1398.         feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1399.     if (statusReg & MDI_SR_LINK_STATUS)
  1400.         return (OK);  /* Link configure done and successful */
  1401.         
  1402.     return (PHY_LINK_ERROR);   /* device is there, cann't establish link */
  1403.     }
  1404. /***************************************************************************
  1405. *
  1406. * feiMDIPhyConfig - configure the PHY device
  1407. *
  1408. * This routine configures the PHY device according to the parameters
  1409. * specified by users or the default value.
  1410. *
  1411. * RETURNS: OK or ERROR.
  1412. *
  1413. */
  1414. static int feiMDIPhyConfig 
  1415.     (
  1416.     int unit,
  1417.     int phyAddr
  1418.     )
  1419.     {
  1420.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  1421.     UINT16 ctlReg = 0;
  1422.     int fullDpx=FALSE;
  1423.     int autoSelect =FALSE;
  1424.     UINT16 statusReg;
  1425.     int status,i;
  1426.     /* find out what capabilities the device have */
  1427.     /*  read status register  */
  1428.     feiMDIRead (unit, MDI_STATUS_REG, phyAddr,&statusReg);
  1429.     /* some of the status bits require to read twice */
  1430.     feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1431.     /* The device at least has to have the half duplex and 10mb speed */
  1432.     if (statusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_TX_FULL_DPX) )
  1433.         fullDpx = TRUE;
  1434.     if (statusReg & MDI_SR_AUTO_SELECT)
  1435.         autoSelect = TRUE;
  1436. #ifdef FEI_DEBUG 
  1437.     logMsg ("status REG = %x !!!! n",statusReg,0,0,0,0,0);
  1438. #endif /* FEI_DEBUG */
  1439.     if (pDrvCtrl->board.phyDpx == PHY_FULL_DPX && fullDpx == TRUE)
  1440.         ctlReg |= MDI_CR_FDX;
  1441.     if (pDrvCtrl->board.phySpeed == PHY_100MBS)
  1442.         ctlReg |= MDI_CR_100;
  1443.     if (pDrvCtrl->board.phySpeed == PHY_AUTO_SPEED || 
  1444.        pDrvCtrl->board.phyDpx == PHY_AUTO_DPX )
  1445.         {
  1446. if (autoSelect != TRUE)
  1447.     {
  1448.     /* set back to default */
  1449.     pDrvCtrl->board.phySpeed = PHY_10MBS;
  1450.     pDrvCtrl->board.phyDpx = PHY_HALF_DPX;
  1451.     ctlReg |= (PHY_10MBS | PHY_HALF_DPX);
  1452.     }
  1453.     else
  1454.                 ctlReg |= (MDI_CR_SELECT|MDI_CR_RESTART);
  1455.          }
  1456.     /* or other possible board level selection */
  1457.     ctlReg |= pDrvCtrl->board.others;
  1458.     /* configure the PHY */
  1459.     feiMDIWrite (unit,MDI_CTRL_REG,phyAddr,ctlReg);
  1460.    
  1461.     taskDelay (2);   /* wait for a while */
  1462.     if (! (ctlReg & MDI_CR_RESTART) )
  1463.         return (OK);
  1464.     /* we are here if the restart auto negotiation is selected */
  1465. #ifdef FEI_DEBUG
  1466.     logMsg ("auto NEGOTIATION STARTS !!!! n",0,0,0,0,0,0);
  1467. #endif /* FEI_DEBUG */
  1468.     /* wait for it done */
  1469.     for (status = PHY_AUTO_FAIL,i=0;i<80;i++)
  1470.        {
  1471.        /*  read status register, some bits have the latch,first read clears */
  1472.        feiMDIRead (unit, MDI_STATUS_REG, phyAddr,&statusReg);
  1473.        feiMDIRead (unit, MDI_STATUS_REG, phyAddr, &statusReg);
  1474.        if (statusReg & MDI_SR_AUTO_NEG)
  1475.            {
  1476.            status = OK;  /* auto negotiation completed */
  1477.            break;
  1478.            }
  1479.        if (statusReg & MDI_SR_REMOTE_FAULT)
  1480.            {
  1481.            status = PHY_AUTO_FAIL;  /* auto negotiation fails */
  1482.            break;
  1483.            }
  1484.         }
  1485.               
  1486.       return (status);
  1487.       } 
  1488. /**************************************************************************
  1489. *
  1490. * feiPhyInit - initialize and configure the PHY device if there is one
  1491. *
  1492. * This routine initialize and configure the PHY device if there is one.
  1493. *
  1494. * RETURNS: OK or ERROR.
  1495. *
  1496. */
  1497. static int feiPhyInit
  1498.     (
  1499.     int unit
  1500.     )
  1501.     {
  1502.     int status;
  1503.     int phyDevice;
  1504.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  1505.     if (pDrvCtrl->board.phyAddr > 31)
  1506.         return (OK);  /* not a MII interface,no need to initialize PHY */
  1507.      /* configure the Physical layer medium if it's MII interface */
  1508.      /* starts with logical PHY 1 */
  1509.      phyDevice = pDrvCtrl->board.phyAddr?pDrvCtrl->board.phyAddr:1;
  1510.      status = feiMDIPhyLinkSet(unit,phyDevice);
  1511.      if (status != OK)
  1512.          {
  1513.          phyDevice = 0;
  1514.          status = feiMDIPhyLinkSet(unit,phyDevice);
  1515.          }
  1516.      if (status != OK)
  1517.  {
  1518.          printf ("LINK_FAIL error, check the line connection !!!n");
  1519.          return (status);
  1520.          }
  1521.      /* we are here if a valid link is established */
  1522.      status = feiMDIPhyConfig (unit,phyDevice); 
  1523.      if (status == PHY_AUTO_FAIL)
  1524.          {
  1525.          /* force default speed and duplex */
  1526.          pDrvCtrl->board.phySpeed = PHY_10MBS;
  1527.          pDrvCtrl->board.phyDpx = PHY_HALF_DPX; 
  1528.          pDrvCtrl->board.others = 0;
  1529.          /* and configure it again */
  1530.          status = feiMDIPhyConfig (unit,phyDevice);  
  1531.          }
  1532.      return (status);
  1533.      }