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

VxWorks

开发平台:

C/C++

  1. /* if_nicEvb.c - National Semiconductor ST-NIC Chip network interface driver */
  2. /* Copyright 1984-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03i,05may97,tam  re-work driver to improve reliability and performances:
  8.                  modified receive interrupt processing and error handling,
  9.                  fixed bug in nicTxStartup(), added function nicPagePtrUpdate()
  10.  and nicResetDelay().
  11. 03h,21apr97,mkw  reset count to 0 before timeout check in nicTransmit and
  12.  set TRANS_TIMOUT value to 400.
  13. 03g,18apr97,mkw  Fixed nicTransmit to use count value.
  14. 03g,15jul97,spm  added ARP request to SIOCSIFADDR ioctl handler
  15. 03f,05mar97,map  added sysEnetAddrGet() call to fetch MAC address (SPR# 7745)
  16. 03f,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  17. 03e,10dec96,tpr  removed intEnable() prototype. Defined in intLib.h now.
  18. 03d,18sep96,p_m  added SYNC definition for CPUs other than PPC
  19. 03c,08aug96,tam  added code to synchronize i/o acess in nicWritePort().
  20. 03b,03mar96,tam  replaced sysIntEnablePIC by intEnable().
  21. 03a,02feb96,dzb  re-worked many parts of driver. implemented Rx buffer-loaning.
  22.                  fixed nicRestart to recover gracefully from DMA overflow.
  23.  re-worked Tx code to send directly from mbuf chain.
  24.  changed to turn off Rx interrupts, instead of an active flag.
  25.  fixed nicRead() to flush extra DMA-byte on Rx error.
  26. 02d,11jul95,amp  used intLock(), implemented nicEnetAddrGet(), cleanup.
  27. 02c,29jun95,caf  changed name to "nicEvb".
  28. 02b,27jun95,amp  improved reliability.
  29. 02a,16jun95,amp  modified if_nic.c for EVB403.
  30. 01z,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  31. 01y,19feb93,jdi  documentation cleanup.
  32. 01x,15oct92,rfs  Added documentation.
  33. 01w,02oct92,rfs  Made multiple attach calls per unit return OK.
  34. 01v,09sep92,gae  documentation tweaks.
  35. 01u,02sep92,ajm  added conditional compilation for __STDC__ (DEC)
  36. 01t,18aug92,rfs  Revised to follow style of other drivers.
  37.                  Added cache support.  Reworked OVW error recovery.
  38. 01s,23jun92,ajm  fixed ansi warnings for pktBufRead calls
  39.                  went back and fixed all 68k ansi warnings
  40. 01r,26may92,rrr  the tree shuffle
  41.                  -changed includes to have absolute path from h/
  42. 01q,26may92,ajm  got rid of HOST_DEC def's (new compiler)
  43.                  updated copyright
  44. 01p,10oct91,rfs  modified pktBufRead() & pktBufWrite() to return if len is zero
  45. 01o,04oct91,rrr  passed through the ansification filter
  46.                  -changed functions to ansi style
  47.                  -changed includes to have absolute path from h/
  48.                  -changed VOID to void
  49.                  -changed copyright notice
  50. 01n,28sep91,ajm  ifdef'd HOST_DEC for compiler problem
  51. 01m,02Aug91,rfs  cleanup of transmit design, int handler, NIC command register
  52.                  was being handled incorrectly, DMA operations required
  53.                  semaphoring and error checking, changed names, deleted
  54.                  nicdelay(), deleted excessive include files. Provided correct
  55.                  OVW recovery.  Your basic rewrite.
  56. 01l,01may91,elh  fixed transmit buffering problems, added changes from
  57.                  heurikon, removed DMAState, XmtByteCount.
  58. 01k,20sep90,dab  made nicInit() return int.
  59. 01j,10aug90,dnw  added forward declarations of void routines.
  60.                  added include of if_subr.h.
  61. 01i,11jul90,hjb  removed code that uses gotIp.  made nicRead() a void function.
  62.                  changed references to do_protocol() to use
  63.                  do_protocol_with_type().
  64. 01h,19apr90,hjb  deleted param.h, de-linted.
  65. 01g,18mar90,hjb  reduction of redundant code and addition of cluster support.
  66.                  added error recording (TXE, RXE), removed unnecessary
  67.                  error handler which didn't do anything.  delinted.
  68. 01f,18sep89,cwp  added multiple transmit buffer support
  69. 01e,14sep89,dab  changed iv68k.h to iv.h.
  70. 01d,15jun89,cwp  fixed ring buffer overflow and transmit errors.
  71. 01c,04apr89,cwp  first working version.
  72. 01b,25feb89,cwp  added changes from unix driver.
  73. 01a,12jan89,cwp  written.
  74. */
  75. /*
  76. This module implements the National Semiconductor 83902A ST-NIC Ethernet
  77. network interface driver.
  78. This driver is non-generic and is for use on the IBM EVB403 board.  
  79. Only unit number zero is supported.  The driver must be given several 
  80. target-specific parameters.  These parameters, and the mechanisms 
  81. used to communicate them to the driver, are detailed below.
  82. BOARD LAYOUT
  83. This device is on-board.  No jumpering diagram is necessary.
  84. EXTERNAL INTERFACE
  85. This driver provides the standard external interface with the following
  86. exceptions.  All initialization is performed within the attach routine; there
  87. is no separate initialization routine.  Therefore, in the global interface
  88. structure, the function pointer to the initialization routine is NULL.
  89. The only user-callable routine is nicEvbattach(), which publishes the `nicEvb'
  90. interface and initializes the driver and device.
  91. TARGET-SPECIFIC PARAMETERS
  92. .iP "device I/O address"
  93. This parameter is passed to the driver by nicEvbattach().
  94. It specifies the base address of the device's I/O register
  95. set.
  96. .iP "interrupt vector"
  97. This parameter is passed to the driver by nicEvbattach().
  98. It specifies the interrupt vector to be used by the driver
  99. to service an interrupt from the ST-NIC device.  The driver will connect
  100. the interrupt handler to this vector by calling intConnect().
  101. .iP "device restart/reset delay"
  102. The global variable nicRestartDelay (UINT32), defined in this file, 
  103. should be initialized in the BSP sysHwInit() routine. nicRestartDelay is 
  104. used only with PowerPC platform and is equal to the number of time base 
  105. increments which makes for 1.6 msec. This corresponds to the delay necessary 
  106. to respect when restarting or resetting the device.
  107. .LP
  108. EXTERNAL SUPPORT REQUIREMENTS
  109. The driver requires the following support functions:
  110. .iP "STATUS sysEnetAddrGet (int unit, UINT8 * addr)" "" 9 -1
  111. The driver expects this routine to provide the six-byte Ethernet hardware
  112. address that will be used by <unit>.  This routine must copy the six-byte
  113. address to the space provided by <addr>.  This routine is expected to return
  114. OK on success, or ERROR.  The driver calls this routine, during device
  115. initialization, from the nicEnetAddrGet() routine.
  116. .LP
  117. SYSTEM RESOURCE USAGE
  118. When implemented, this driver requires the following system resources:
  119.     - one mutual exclusion semaphore
  120.     - one interrupt vector
  121. SEE ALSO: ifLib
  122. */
  123. /* includes */
  124. #include "vxWorks.h"
  125. #include "iv.h"
  126. #include "stdlib.h"
  127. #include "intLib.h"
  128. #include "netLib.h"
  129. #ifdef NIC_DEBUG
  130. #include "logLib.h"
  131. #endif
  132. #include "taskLib.h"
  133. #include "logLib.h"
  134. #include "net/mbuf.h"
  135. #include "sys/ioctl.h"
  136. #include "errno.h"
  137. #include "net/if.h"
  138. #include "net/unixLib.h"
  139. #include "net/if_subr.h"
  140. #include "netinet/in_var.h"
  141. #include "netinet/if_ether.h"
  142. #include "etherLib.h"
  143. #include "semLib.h"
  144. #include "drv/netif/netifDev.h"
  145. #include "drv/netif/if_nicEvb.h"
  146. #include "vxLib.h"
  147. #include "private/funcBindP.h"
  148. /* defines */
  149. #if (CPU_FAMILY == PPC)
  150. #define NIC_USE_PPCTIMEBASE
  151. #else   /* CPU_FAMILY == PPC */
  152. #undef NIC_USE_PPCTIMEBASE
  153. #endif /* CPU_FAMILY == PPC */
  154. #define MAX_UNITS 1 /* max number of units supported */
  155. #define TRANS_TIMEOUT 400 /* times to poll for end of Tx */
  156. #define L_POOL           0x4 /* Rx loan buffers in pool */
  157. /* debug macros */
  158. #undef NIC_INSTRUMENT /* instrument the driver */
  159. #undef NIC_DEBUG /* log debug messages */
  160. /* 
  161.  * NIC_FASTER, if defined, improved the driver throuput, however the driver
  162.  * seems to be less reliable. Left undefined for now.
  163.  */
  164. #undef NIC_FASTER /* improve throuput but less stable */
  165. /* typedefs */
  166. typedef struct mbuf MBUF;
  167. typedef struct arpcom IDR; /* Interface Data Record wrapper */
  168. typedef struct ifnet IFNET; /* real Interface Data Record */
  169. typedef struct sockaddr SOCK;
  170. typedef struct ether_header ETH_HDR;
  171. typedef struct rx_hdr
  172.     {
  173.     UINT8 status; /* status of packet */
  174.     UINT8 nextRxPage; /* page next pkt starts at */
  175.     UINT8 cntL; /* low byte of frame length */
  176.     UINT8 cntH; /* high byte of frame length */
  177.     } RX_HDR;
  178. #define RX_HDR_SIZ sizeof(RX_HDR)
  179. typedef struct rx_frame
  180.     {
  181.     UINT16 pad1;
  182.     RX_HDR rxHdr; /* receive status header */
  183.     ETH_HDR enetHdr; /* ethernet header */
  184.     UINT8 data [ETHERMTU];/* frame data */
  185.     UINT32 fcs; /* frame check sequence */
  186.     UINT8 refCnt; /* loaner reference count */
  187.     UINT8 pad2;
  188.     } RX_FRAME;
  189. #define RX_FRAME_SIZ sizeof(RX_FRAME)
  190. typedef struct drv_ctrl /* driver control structure */
  191.     {
  192.     IDR                 idr; /* interface data record */
  193.     BOOL                attached; /* indicates unit is attached */
  194.     int                 nicIntVec; /* interrupt vector */
  195.     SEM_ID              dmaSem; /* exclusive use of remote DMA */
  196.     UINT8 nextPkt; /* NIC buf page for next pkt */
  197.     NIC_DEVICE * nicAddr; /* address of NIC chip */
  198.     RX_FRAME * pRxFrame; /* Rx frame memory */
  199.     RX_FRAME * lPool [L_POOL]; /* Rx loaner pool */
  200.     int lIndex; /* Rx loaner pool index */
  201.     } DRV_CTRL;
  202. /* globals */
  203. UINT32  nicRestartDelay = 30000;/* number of time base ticks to wait for */
  204. /* when resetting the chip */
  205. #ifdef NIC_INSTRUMENT
  206. UINT32 nicRestartNb = 0; /* number of restart due to ring overflow */
  207. UINT32 nicIntNb = 0; /* number of receive interrupt */
  208. UINT32 nicLen = 0; /* lenght of the current received packet */
  209. UINT32 nicHdrStat = 0; /* status byte of the current received packet */
  210. UINT32 nicNextPage = 0; /* page pointer to the next received packet */
  211. UINT32 nicCurrentPage = 0; /* start page of the current packet */
  212. UINT32 nicTxNb = 0; /* number of transmitted packets */
  213. UINT32 nicTxTimeout = 0; /* number of transmit time-out */
  214. UINT32 nicInitNb = 0; /* number of time device is re-initialized */
  215. #endif
  216. IMPORT STATUS sysEnetAddrGet (int unit, UINT8 * addr);
  217. /* locals */
  218. LOCAL DRV_CTRL drvCtrl [MAX_UNITS];
  219. /* forward declarations */
  220. #ifdef __STDC__
  221. LOCAL void nicReset (int unit);
  222. LOCAL void nicIntr (int unit);
  223. LOCAL void nicRestart (DRV_CTRL *pDrvCtrl, UINT8 cr);
  224. LOCAL void nicHandleInt (DRV_CTRL *pDrvCtrl);
  225. LOCAL BOOL nicRead (DRV_CTRL *pDrvCtrl);
  226. #ifdef BSD43_DRIVER
  227. LOCAL int nicOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDest);
  228. #endif
  229. LOCAL int nicIoctl (IDR *pIDR, int cmd, caddr_t data);
  230. LOCAL void nicEnetAddrGet (int unit);
  231. LOCAL void nicConfig (int unit);
  232. LOCAL STATUS nicPktBufRead (DRV_CTRL *pDrvCtrl, UINT32 nicBufAddr,
  233.     UINT32 len, char *pData);
  234. LOCAL void nicWriteCr (NIC_DEVICE *pNic, UINT8 value);
  235. LOCAL void nicWriteReg (NIC_DEVICE *pNic, volatile UINT8 *pReg,
  236.     UINT8 value, UINT8 page);
  237. LOCAL UINT8 nicReadReg (NIC_DEVICE *pNic, volatile UINT8 *pReg, char page);
  238. LOCAL STATUS nicTransmit (DRV_CTRL *pDrvCtrl, MBUF *pMbuf, int len,
  239.     BOOL waitFlag);
  240. LOCAL void nicWritePort (UINT8 value);
  241. LOCAL STATUS nicReceive (DRV_CTRL *pDrvCtrl, UINT32 nicBufAddr, char *pData,
  242.     int len);
  243. #ifdef BSD43_DRIVER
  244. LOCAL STATUS nicTxStartup(int unit);
  245. #else
  246. LOCAL STATUS nicTxStartup(DRV_CTRL *pDrvCtrl);
  247. #endif
  248. LOCAL UINT8 nicReadPort (void);
  249. LOCAL void nicLoanFree (DRV_CTRL *pDrvCtrl, RX_FRAME *pRx);
  250. LOCAL BOOL nicPagePtrUpdate (DRV_CTRL * pDrvCtrl);
  251. LOCAL void nicResetDelay (void);
  252. #else  /* __STDC__ */
  253. LOCAL void nicReset ();
  254. LOCAL void nicIntr ();
  255. LOCAL void nicRestart ();
  256. LOCAL void nicHandleInt ();
  257. LOCAL BOOL nicRead ();
  258. LOCAL int nicOutput ();
  259. LOCAL int nicIoctl ();
  260. LOCAL void nicEnetAddrGet ();
  261. LOCAL void nicConfig ();
  262. LOCAL STATUS nicPktBufRead ();
  263. LOCAL void nicWriteCr ();
  264. LOCAL void nicWriteReg ();
  265. LOCAL UINT8 nicReadReg ();
  266. LOCAL STATUS nicTransmit ();
  267. LOCAL void nicWritePort ();
  268. LOCAL STATUS nicReceive ();
  269. LOCAL STATUS nicTxStartup();
  270. LOCAL UINT8 nicReadPort ();
  271. LOCAL void nicNicFree ();
  272. LOCAL BOOL nicPagePtrUpdate ();
  273. LOCAL void nicResetDelay () ;
  274. #endif  /* __STDC__ */
  275. /*******************************************************************************
  276. *
  277. * nicEvbattach - publish and initialize the `nicEvb' network interface driver
  278. *
  279. * This routine publishes the `nicEvb' interface by filling in a network
  280. * interface record and adding this record to the system list.  It also
  281. * initializes the driver and the device to the operational state.
  282. *
  283. * RETURNS: OK, or ERROR if the receive buffer memory could not be allocated.
  284. */
  285. STATUS nicEvbattach
  286.     (
  287.     int unit, /* unit number */
  288.     NIC_DEVICE * pNic, /* address of NIC chip */
  289.     int ivec /* interrupt vector to use */
  290.     )
  291.     {
  292.     DRV_CTRL * pDrvCtrl; /* driver control struct */
  293.     RX_FRAME * pPool; /* receive memory pool */
  294.     int ix; /* counter */
  295.     if (unit < 0 || unit >= MAX_UNITS) /* sanity check the unit number */
  296.         return (ERROR);
  297.     pDrvCtrl = &drvCtrl [unit];
  298.     if (pDrvCtrl->attached) /* ensure single invocation */
  299.         return (OK);
  300.     if ((pPool = (RX_FRAME *) malloc ((L_POOL + 1) * RX_FRAME_SIZ)) == NULL)
  301.         return (ERROR);
  302.     for (ix = 0; ix < L_POOL; ix++) /* assign addresses of Rx pool */
  303. pDrvCtrl->lPool [ix] = pPool++;
  304.     pDrvCtrl->lIndex = L_POOL; /* initialize loaner pool index */
  305.     pDrvCtrl->pRxFrame = pPool; /* link in primary buffer */
  306.     pDrvCtrl->nicAddr = pNic; /* save NIC address */
  307.     pDrvCtrl->nicIntVec = ivec; /* save int vector number */
  308.     pDrvCtrl->nextPkt = CURR; /* reset to initial value */
  309.     pDrvCtrl->dmaSem = semMCreate (SEM_Q_PRIORITY);
  310.     /* publish the interface data record */
  311. #ifdef BSD43_DRIVER
  312.     ether_attach (&pDrvCtrl->idr.ac_if, unit, "nicEvb", (FUNCPTR) NULL,
  313.         (FUNCPTR) nicIoctl, (FUNCPTR) nicOutput, (FUNCPTR) nicReset);
  314. #else
  315.     ether_attach (
  316.                  &pDrvCtrl->idr.ac_if, 
  317.                  unit, 
  318.                  "nicEvb", 
  319.                  (FUNCPTR) NULL,
  320.                  (FUNCPTR) nicIoctl, 
  321.                  (FUNCPTR) ether_output, 
  322.                  (FUNCPTR) nicReset
  323.                  );
  324.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)nicTxStartup;
  325. #endif
  326.  
  327.     /* connect the interrupt handler */
  328.     (void) intConnect (INUM_TO_IVEC (ivec), nicIntr, 0); 
  329.     intEnable (ivec); 
  330.     nicConfig (unit); /* configure the device */
  331.     /* raise the interface flags */
  332.     pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS;
  333.     pDrvCtrl->attached = TRUE;
  334.     return (OK);
  335.     }
  336. /*******************************************************************************
  337. *
  338. * nicReset - reset of interface
  339. *
  340. * This routine performs a software reset of the ST-NIC device.
  341. *
  342. * RETURNS: N/A.
  343. *
  344. * NOMANUAL
  345. */
  346. void nicReset
  347.     (
  348.     int unit /* device unit to reset */
  349.     )
  350.     {
  351.     DRV_CTRL * pDrvCtrl = &drvCtrl [unit];
  352.     NIC_DEVICE * pNic = pDrvCtrl->nicAddr;
  353.     pDrvCtrl->idr.ac_if.if_flags = 0;
  354.     nicWriteCr (pNic, STP | ABORT | RPAGE0);
  355.     taskDelay (2); /* wait at least 1.6 mSec */
  356.     }
  357. /*******************************************************************************
  358. *
  359. * nicIntr - The driver's interrupt handler
  360. *
  361. * This function clears the cause of the device interrupt(s) and then acts
  362. * on the individual possible causes.  The primary goal of this routine is to
  363. * minimize the time spent in it.  This is accomplished by deferring processing
  364. * to the netTask via the netJobAdd() function.
  365. *
  366. * Note that in case the receiver overruns, we promptly mark the interface as
  367. * "down" and leave error handling to task-level.   This is in case netTask
  368. * is in the midst of DMA activity, we must allow it to complete.  The receive
  369. * handler will give up when it discovers the interface is down, which will
  370. * then allow netTask to run our OVW handler.  This provides a nice orderly
  371. * error recovery.
  372. *
  373. * RETURNS: N/A.
  374. */
  375. LOCAL void nicIntr
  376.     (
  377.     int unit
  378.     )
  379.     {
  380.     DRV_CTRL * pDrvCtrl = &drvCtrl [unit];
  381.     NIC_DEVICE * pNic = pDrvCtrl->nicAddr; /* NIC registers */
  382.     UINT8 isr; /* copy of ISR */
  383.     UINT8 cr; /* copy of CR */
  384. #ifdef NIC_INSTRUMENT
  385.     nicIntNb++;
  386. #endif
  387.     isr = nicReadReg(pNic, &pNic->Isr, RPAGE0);
  388.     nicWriteReg(pNic, &pNic->Isr, isr, RPAGE0);
  389.     /* handle receiver overrun */
  390.     if  ((isr & OVW) && (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)))
  391. {
  392. cr = nicReadReg (pNic, &pNic->Cr, RPAGE0);
  393. nicWriteReg(pNic, &pNic->Imr, 0, RPAGE0); /* disable all interrupts */
  394.         pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
  395. netJobAdd ((FUNCPTR) nicRestart, (int) pDrvCtrl, cr, 0, 0, 0);
  396.         return;
  397. }
  398.     /* handle packet received */
  399.     if  ((isr & PRX) && (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)))
  400. netJobAdd ((FUNCPTR) nicHandleInt, (int) pDrvCtrl, 0, 0, 0, 0);
  401.     }
  402. /*******************************************************************************
  403. *
  404. * nicRestart - restart chip after receive ring buffer overflow
  405. *
  406. * This routine is the task-level handler that deals with a receive DMA
  407. * overflow condition.  It gets access to the remote DMA, cleans up NIC
  408. * registers, empties the receive ring buffers, and then resends any
  409. * packet that was in the midst of transmission when the overflow hit.
  410. *
  411. * RETURNS: N/A.
  412. */
  413. LOCAL void nicRestart
  414.     (
  415.     DRV_CTRL * pDrvCtrl,
  416.     UINT8 cr
  417.     )
  418.     {
  419.     NIC_DEVICE * pNic = pDrvCtrl->nicAddr; /* NIC registers */
  420.     BOOL resend = FALSE;
  421. #ifdef NIC_INSTRUMENT
  422.     nicRestartNb++;
  423. #endif
  424.     nicWriteCr (pNic, STP);
  425.     nicResetDelay (); /* wait at least 1.6 mSec */
  426.     if (semTake(pDrvCtrl->dmaSem, 100) == ERROR)
  427. {
  428. #ifdef NIC_DEBUG
  429. if (_func_logMsg != NULL)
  430.     _func_logMsg ("nicRestart: can't obtain dmaSemn", 0, 0, 0, 0, 0,0);
  431. #endif
  432.         semTake (pDrvCtrl->dmaSem, WAIT_FOREVER);
  433.         }
  434.     nicWriteReg (pNic, &pNic->Rbcr0, 0, RPAGE0);
  435.     nicWriteReg (pNic, &pNic->Rbcr1, 0, RPAGE0);
  436.     if ((cr & TXP) && (!(nicReadReg (pNic, &pNic->Isr, RPAGE0) & (TXE | PTX))))
  437. resend = TRUE;
  438.     nicWriteReg (pNic, &pNic->Tcr, MODE1, RPAGE0);
  439.     nicWriteCr (pNic, RPAGE0 | ABORT | STA); /* back to page 0 */
  440.     pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS;
  441.     while (nicRead (pDrvCtrl))
  442. ;
  443.     nicWriteReg(pNic, &pNic->Isr, OVW, RPAGE0);
  444.     nicWriteReg (pNic, &pNic->Tcr, MODE0, RPAGE0);
  445.     if (resend)
  446.         nicWriteCr (pNic, RPAGE0 | STA | TXP | ABORT);
  447.     semGive(pDrvCtrl->dmaSem);
  448.     nicWriteReg (pNic, &pNic->Imr, PRXE | OVWE, RPAGE0);
  449.     }
  450. /*******************************************************************************
  451. *
  452. * nicHandleInt - deferred receive interrupt handler
  453. *
  454. * This function handles the received frames from the device.  It runs in the
  455. * context of the netTask, which was triggered by a received packet interrupt.
  456. * Actual processing of the packet is done by calling nicRead().
  457. *
  458. * RETURNS: N/A.
  459. */
  460. LOCAL void nicHandleInt
  461.     (
  462.     DRV_CTRL * pDrvCtrl
  463.     )
  464.     {
  465.     /* empties the receive ring buffer of its packets */
  466.     while (nicRead (pDrvCtrl));
  467.     }
  468. /*******************************************************************************
  469. *
  470. * nicRead - read a packet off the interface ring buffer
  471. *
  472. * nicRead copies packets from local memory into an mbuf and hands it to
  473. * the next higher layer (IP or etherInputHook).
  474. *
  475. * RETURNS: TRUE, or FALSE if the packet reception encountered errors.
  476. */
  477. LOCAL BOOL nicRead
  478.     (
  479.     DRV_CTRL * pDrvCtrl
  480.     )
  481.     {
  482.     NIC_DEVICE * pNic = pDrvCtrl->nicAddr;/* NIC registers */
  483.     RX_FRAME * pRx = pDrvCtrl->pRxFrame;/* free Rx buffer */
  484.     MBUF * pMbuf = NULL;
  485.     UINT32 len; /* len of Rx pkt */
  486. #ifdef BSD43_DRIVER
  487.     UINT16 type; /* packet type - saved */
  488. #endif
  489.     int cur;
  490.     if (!(pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) ||
  491.         (pDrvCtrl->nextPkt == (cur = nicReadReg (pNic, &pNic->Curr, RPAGE1))))
  492. return (FALSE);
  493.     /*
  494.      * OK, there is work to be done.
  495.      * First we copy the NIC receive status header from the NIC buffer
  496.      * into our local area. This is done so that we can obtain the length
  497.      * of the packet before copying out the rest of it. Note that the length
  498.      * field in the NIC header includes the Ethernet header, the data, and
  499.      * the 4 byte FCS field.
  500.      */
  501.     if (nicPktBufRead (pDrvCtrl, pDrvCtrl->nextPkt << 8, (RX_HDR_SIZ),
  502. (char *) &pRx->rxHdr) == ERROR)
  503.         {
  504. #ifdef NIC_DEBUG
  505. if (_func_logMsg != NULL)
  506.     _func_logMsg("nicRead could not read packet headern",0,0,0,0,0,0);
  507. #endif
  508. return (FALSE);
  509. }
  510.     len = pRx->rxHdr.cntL + (pRx->rxHdr.cntH << 8) - 4 /* FCS */;
  511.     /* valid frame checks */
  512.     /*
  513.      * NOTE: if the packet's receive status byte indicates an error
  514.      * the packet is discarded and the receive page pointers are updated to
  515.      * point to the next packet.
  516.      */
  517. #ifdef NIC_INSTRUMENT
  518.     nicLen = len;
  519.     nicHdrStat = pRx->rxHdr.status;
  520.     nicNextPage = pRx->rxHdr.nextRxPage;
  521.     nicCurrentPage = cur;
  522. #endif
  523.     if ((len < 60) || (len > 1514) || ((pRx->rxHdr.status & ~PHY) != PRX))
  524. {
  525. pDrvCtrl->idr.ac_if.if_ierrors++;
  526. #ifdef NIC_DEBUG
  527. if (_func_logMsg != NULL)
  528.     _func_logMsg ("nicRead receive error: statusHeader=0x%x nextRxPage=%d currentPage=%d len=%d IntNb=%dn",pRx->rxHdr.status, pRx->rxHdr.nextRxPage, cur,len,nicIntNb);
  529. #endif  
  530. if (nicPagePtrUpdate (pDrvCtrl))
  531.     return (TRUE);
  532. else
  533.     return (FALSE);
  534. }
  535.     /* copy Ethernet packet section of the frame */
  536.     if (nicPktBufRead(pDrvCtrl, (pDrvCtrl->nextPkt << 8) + RX_HDR_SIZ, len,
  537. (char *) &pRx->enetHdr) == ERROR)
  538. {
  539. #ifdef NIC_DEBUG
  540. if (_func_logMsg != NULL)
  541.     _func_logMsg ("nicRead: Could not read packet datan",0,0,0,0,0,0);
  542. #endif
  543. if (nicPagePtrUpdate(pDrvCtrl))
  544.     return (TRUE);
  545. else
  546.     return (FALSE);
  547. }
  548.     /* update ring buffer/page pointers */
  549.     if (!nicPagePtrUpdate (pDrvCtrl))
  550. {
  551. return (FALSE);
  552. }
  553.     pDrvCtrl->idr.ac_if.if_ipackets++;
  554.     if ((etherInputHookRtn != NULL) && /* call hook if installed */
  555.         ((* etherInputHookRtn) (&pDrvCtrl->idr.ac_if, (char *) &pRx->enetHdr,
  556.         len)))
  557.         return (TRUE);
  558.     len -= sizeof (ETH_HDR);            /* now equals length of data only */
  559. #ifdef BSD43_DRIVER
  560.     type = pRx->enetHdr.ether_type; /* build_cluster trashes type field */
  561. #endif
  562.     if ((pDrvCtrl->lIndex) && (USE_CLUSTER (len))) /* use loaning ? */
  563. {
  564. pRx->refCnt = 0;
  565.         pMbuf = build_cluster (pRx->data, len, &pDrvCtrl->idr, MC_NIC_EVB,
  566.             &pRx->refCnt, nicLoanFree, (int) pDrvCtrl, (int) pRx, 0);
  567. }
  568.     if (pMbuf != NULL) /* loaning worked ? */
  569.         pDrvCtrl->pRxFrame = pDrvCtrl->lPool [--pDrvCtrl->lIndex];
  570.     else
  571.         {
  572.         pMbuf = copy_to_mbufs (pRx->data, len, 0, &pDrvCtrl->idr.ac_if);
  573.         if (pMbuf == NULL)
  574.             {
  575.             pDrvCtrl->idr.ac_if.if_ierrors++;
  576.             return (TRUE);
  577.             }
  578.         }
  579. #ifdef BSD43_DRIVER
  580.     do_protocol_with_type (type, pMbuf, &pDrvCtrl->idr, len); /* up to IP */
  581. #else
  582.     do_protocol (&pRx->enetHdr, pMbuf, &pDrvCtrl->idr, len);
  583. #endif
  584.     return (TRUE);
  585.     }
  586. #ifdef BSD43_DRIVER
  587. /*******************************************************************************
  588. *
  589. * nicOutput - the driver's output routine
  590. *
  591. * RETURNS: N/A.
  592. */
  593. LOCAL int nicOutput
  594.     (
  595.     IDR  * pIDR,
  596.     MBUF * pMbuf,
  597.     SOCK * pDest
  598.     )
  599.     {
  600.     return ether_output ((IFNET *) pIDR, pMbuf, pDest, (FUNCPTR) nicTxStartup,
  601. pIDR);
  602.     }
  603. #endif
  604. /*******************************************************************************
  605. *
  606. * nicTxStartup - the driver's actual output routine
  607. *
  608. * This routine accepts outgoing packets from the if_snd queue, and then 
  609. * gains exclusive access to the DMA (through a mutex semaphore),
  610. * then calls nicTransmit() to send the packet out onto the interface.
  611. *
  612. * RETURNS: OK, or ERROR if the packet could not be transmitted.
  613. */
  614. #ifdef BSD43_DRIVER
  615. LOCAL STATUS nicTxStartup
  616.     (
  617.     int unit
  618.     )
  619.     {
  620.     DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];
  621. #else
  622. LOCAL STATUS nicTxStartup
  623.     (
  624.     DRV_CTRL *  pDrvCtrl
  625.     )
  626.     {
  627. #endif
  628.     MBUF * pMbuf;
  629.     MBUF * mbuf;
  630.     int status = OK;
  631.     int length = 0;
  632.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  633. {
  634.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);/* dequeue a packet */
  635.         if ((pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  636.             (IFF_UP | IFF_RUNNING))
  637.             return (ERROR);
  638.         if (semTake (pDrvCtrl->dmaSem, 100) == ERROR) /* get DMA access */
  639.             {
  640.     if (_func_logMsg != NULL)
  641. _func_logMsg("nicTxStartup: can't obtain dmaSemn",0,0,0,0,0,0);
  642.             semTake (pDrvCtrl->dmaSem, WAIT_FOREVER);
  643.             }
  644. for (mbuf = pMbuf; mbuf != NULL; mbuf = mbuf->m_next)
  645.     length += mbuf->m_len; /* find length of chain */
  646.         if (length == 0)
  647.     {
  648.     m_freem (pMbuf); /* empty mbuf chain */
  649.     semGive (pDrvCtrl->dmaSem);
  650.     continue;
  651.     }
  652. #ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic */
  653.         pDrvCtrl->idr.ac_if.if_opackets++;
  654. #endif
  655. #ifdef NIC_INSTRUMENT
  656. nicTxNb++;
  657. #endif
  658. /* send packet out over interface */
  659.         if ( (status = nicTransmit (pDrvCtrl, pMbuf, length, TRUE)) == ERROR)
  660.             {
  661.             pDrvCtrl->idr.ac_if.if_opackets--;
  662.             pDrvCtrl->idr.ac_if.if_oerrors++;
  663.             }
  664.         semGive (pDrvCtrl->dmaSem);
  665. }
  666.     return status;
  667.     }
  668. /*******************************************************************************
  669. *
  670. * nicIoctl - the driver's I/O control routine
  671. *
  672. * Perform device-specific commands.
  673. *
  674. * RETURNS: 0, or EINVAL if the command 'cmd' is not supported.
  675. */
  676. LOCAL int nicIoctl
  677.     (
  678.     IDR * pIDR,
  679.     int cmd, /* command to execute */
  680.     caddr_t data /* command-specific data */
  681.     )
  682.     {
  683.     int error = 0;
  684.     int s = splimp ();
  685.     switch (cmd)
  686. {
  687.         case SIOCSIFADDR:
  688.             ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;
  689.             arpwhohas (pIDR, &IA_SIN (data)->sin_addr);
  690.             break;
  691.         case SIOCSIFFLAGS: /* no driver-dependent flags */
  692.             break;
  693.         default:
  694.             error = EINVAL;
  695. }
  696.     splx (s);
  697.     return (error);
  698.     }
  699. /*******************************************************************************
  700. *
  701. * nicEnetAddrGet - get the Ethernet address.
  702. *
  703. * Get ethernet address from the BSP.
  704. *
  705. * RETURNS: N/A.
  706. */
  707. LOCAL void nicEnetAddrGet
  708.     (
  709.     int unit
  710.     )
  711.     {
  712.     DRV_CTRL * pDrvCtrl = & drvCtrl [unit];
  713.     UINT8 enetAdrs[6];
  714.     UINT8 count;
  715.     sysEnetAddrGet (unit, enetAdrs);
  716.     for (count=0; count<6; count++)
  717.         pDrvCtrl->idr.ac_enaddr[count] = enetAdrs[5-count];
  718.         
  719.     }
  720. /*******************************************************************************
  721. *
  722. * nicConfig - configure the NIC chip and program address
  723. *
  724. * This routine follows the algorythm in the ST-NIC manual for enabling
  725. * a NIC device on an active network.  Essentially, this routine initializes
  726. * the NIC device.
  727. *
  728. * RETURNS: N/A.
  729. */
  730. LOCAL void nicConfig
  731.     (
  732.     int unit
  733.     )
  734.     {
  735.     DRV_CTRL * pDrvCtrl = &drvCtrl [unit];
  736.     NIC_DEVICE * pNic= pDrvCtrl->nicAddr;
  737.     
  738.     nicWriteCr (pNic, RPAGE0 | STP | ABORT);
  739.     nicResetDelay ();
  740.     nicWriteReg (pNic, &pNic->Dcr, NOTLS | FIFO8, RPAGE0);
  741.     /* clear remote DMA byte count registers */
  742.     nicWriteReg (pNic, &pNic->Rbcr0, 0, RPAGE0);             
  743.     nicWriteReg (pNic, &pNic->Rbcr1, 0, RPAGE0);
  744.     /* accept broadcast, but not runt or multicast */
  745.     nicWriteReg (pNic, &pNic->Rcr, AB, RPAGE0);         
  746.     nicWriteReg (pNic, &pNic->Tcr, MODE1, RPAGE0); /* int loopback mode */
  747.     nicWriteReg (pNic, &pNic->Pstart, PSTART, RPAGE0);
  748.     nicWriteReg (pNic, &pNic->Pstop, PSTOP, RPAGE0);
  749.     nicWriteReg (pNic, &pNic->Bnry, BNRY, RPAGE0);
  750.     nicWriteReg (pNic, &pNic->Isr, 0xff, RPAGE0); /* clr pending ints */
  751.     nicWriteReg (pNic, &pNic->Imr, PRXE | OVWE, RPAGE0); /* enable int */
  752.     nicEnetAddrGet (unit); /* get enet address */
  753.     /* set up page 1 registers */
  754.     nicWriteReg (pNic, &pNic->Par0, pDrvCtrl->idr.ac_enaddr [0], RPAGE1);
  755.     nicWriteReg (pNic, &pNic->Par1, pDrvCtrl->idr.ac_enaddr [1], RPAGE1);
  756.     nicWriteReg (pNic, &pNic->Par2, pDrvCtrl->idr.ac_enaddr [2], RPAGE1);
  757.     nicWriteReg (pNic, &pNic->Par3, pDrvCtrl->idr.ac_enaddr [3], RPAGE1);
  758.     nicWriteReg (pNic, &pNic->Par4, pDrvCtrl->idr.ac_enaddr [4], RPAGE1);
  759.     nicWriteReg (pNic, &pNic->Par5, pDrvCtrl->idr.ac_enaddr [5], RPAGE1);
  760.     nicWriteReg (pNic, &pNic->nic_pg1.mar0, 0xff, RPAGE1);
  761.     nicWriteReg (pNic, &pNic->nic_pg1.mar1, 0xff, RPAGE1);
  762.     nicWriteReg (pNic, &pNic->nic_pg1.mar2, 0xff, RPAGE1);
  763.     nicWriteReg (pNic, &pNic->nic_pg1.mar3, 0xff, RPAGE1);
  764.     nicWriteReg (pNic, &pNic->nic_pg1.mar4, 0xff, RPAGE1);
  765.     nicWriteReg (pNic, &pNic->nic_pg1.mar5, 0xff, RPAGE1);
  766.     nicWriteReg (pNic, &pNic->nic_pg1.mar6, 0xff, RPAGE1);
  767.     nicWriteReg (pNic, &pNic->nic_pg1.mar7, 0xff, RPAGE1);
  768.     nicWriteReg (pNic, &pNic->Curr, CURR, RPAGE1);
  769.     nicWriteCr (pNic, RPAGE0 | ABORT | STA); /* back to page 0 */
  770.     nicWriteReg (pNic, &pNic->Tcr, MODE0, RPAGE0); /* Tx normal mode */
  771.     }
  772. /*******************************************************************************
  773. *
  774. * nicPktBufRead - read data from the NIC receive ring buffer
  775. *
  776. * This routine gets exclusive access to the remote DMA, and calls
  777. * nicReceive() to get data from the NIC's receive ring buffer.
  778. *
  779. * RETURNS: OK, or ERROR if obtaining the requested bytes encountered an error.
  780. */
  781. LOCAL STATUS nicPktBufRead
  782.     (
  783.     DRV_CTRL * pDrvCtrl,
  784.     UINT32 nicBufAddr,
  785.     UINT32 len,
  786.     char * pData
  787.     )
  788.     {
  789.     STATUS status = OK;
  790.     /* avoid starting DMA if device is down to to fatal error */
  791.     if ((pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  792.         (IFF_UP | IFF_RUNNING))
  793.         return (ERROR);
  794.     if (semTake (pDrvCtrl->dmaSem, 100) == ERROR) /* get DMA */
  795. {
  796. if (_func_logMsg != NULL)
  797.     _func_logMsg ("nicPktBufRead: can't obtain dmaSemn",0,0,0,0,0,0);
  798.         semTake (pDrvCtrl->dmaSem, WAIT_FOREVER);
  799. }
  800.     status = nicReceive (pDrvCtrl, nicBufAddr, pData, len); /* goto ring */
  801.     semGive(pDrvCtrl->dmaSem);
  802.     return (status);
  803.     }
  804. /*******************************************************************************
  805. *
  806. * nicWriteCr - write to the NIC command register
  807. *
  808. * RETURNS: N/A.
  809. */
  810. LOCAL void nicWriteCr
  811.     (
  812.     NIC_DEVICE *pNic,
  813.     UINT8 value
  814.     )
  815.     {
  816.     int level = intLock ();
  817.     do {
  818.         pNic->Cr = value;
  819.         } while (!((*(volatile UINT8 *)NIC_DMA) & ACC_MASK));
  820.     intUnlock (level);
  821.     }
  822. /*******************************************************************************
  823. *
  824. * nicWriteReg - write to a NIC register
  825. *
  826. * RETURNS: N/A.
  827. */
  828. LOCAL void nicWriteReg 
  829.     (
  830.     NIC_DEVICE * pNic,
  831.     volatile UINT8 * pReg,
  832.     UINT8 value,
  833.     UINT8 page
  834.     )
  835.     {
  836.     volatile UINT8 * nicDma = (volatile UINT8 *) NIC_DMA;
  837.     UINT8 cr;
  838.     int level = intLock ();
  839.     do {
  840. cr = pNic->Cr;
  841. } while (!((*nicDma) & ACC_MASK));
  842.     if ((cr & PBMASK) != page)
  843. do {
  844.     pNic->Cr = (cr & 0x3f) | page;
  845.     } while (!((*nicDma) & ACC_MASK));
  846.     do {
  847. *pReg = value;
  848. } while (!((*nicDma) & ACC_MASK));
  849.     intUnlock (level);
  850.     }
  851. /*******************************************************************************
  852. *
  853. * nicReadReg - read from a NIC register
  854. *
  855. * RETURNS: the register value.
  856. */
  857. LOCAL UINT8 nicReadReg 
  858.     (
  859.     NIC_DEVICE * pNic,
  860.     volatile UINT8 * pReg,
  861.     char page
  862.     )
  863.     {
  864.     volatile UINT8 * nicDma = (volatile UINT8 *) NIC_DMA;
  865.     UINT8 cr;
  866.     int level = intLock ();
  867.     do {
  868. cr = pNic->Cr;
  869. } while (!((*nicDma) & ACC_MASK));
  870.     if ((cr & PBMASK) != page)
  871. do {
  872.     pNic->Cr = (cr & 0x3f) | page;
  873.     } while (!((*nicDma) & ACC_MASK));
  874.     do {
  875. cr = *pReg;
  876. } while (!((*nicDma) & ACC_MASK));
  877.     intUnlock (level);
  878.     return (cr);
  879.     }
  880. /*******************************************************************************
  881. *
  882. * nicWritePort - write to the DMA port
  883. *
  884. * RETURNS: N/A.
  885. */
  886. LOCAL void nicWritePort
  887.     (
  888.     UINT8 value
  889.     )
  890.     {
  891. #ifndef NIC_FASTER
  892.     int level = intLock ();
  893. #endif
  894.     do 
  895. {
  896. *(volatile char *) NIC_PORT = value;
  897.         }
  898.     while (!((*(volatile UINT8 *) NIC_DMA) & ACC_MASK));
  899. #ifndef NIC_FASTER
  900.     intUnlock (level);
  901. #endif
  902.     }
  903. /*******************************************************************************
  904. *
  905. * nicReadPort - read from the DMA port
  906. *
  907. * RETURNS: the DMA port value.
  908. */
  909. LOCAL UINT8 nicReadPort (void)
  910.     {
  911.     UINT8 value;
  912. #ifndef NIC_FASTER
  913.     int level = intLock ();
  914. #endif
  915.     do
  916. {
  917. value = *(volatile UINT8 *) NIC_PORT;
  918.         }
  919.     while (!((*(volatile UINT8 *) NIC_DMA) & ACC_MASK));
  920. #ifndef NIC_FASTER
  921.     intUnlock (level);
  922. #endif
  923.     return (value);
  924.     }
  925. /*******************************************************************************
  926. *
  927. * nicTransmit - send data over the NIC network interface
  928. *
  929. * This routine transfers data to the NIC device via the remote DMA, and
  930. * then signal for a transmission.
  931. *
  932. * RETURNS: OK, or ERROR if the transmitter signalled an error.
  933. */
  934. LOCAL STATUS nicTransmit
  935.     (
  936.     DRV_CTRL * pDrvCtrl,
  937.     MBUF * pMbuf,
  938.     int len,
  939.     BOOL waitFlag
  940.     )
  941.     {
  942.     NIC_DEVICE * pNic = pDrvCtrl->nicAddr;
  943.     UINT8 cr;
  944.     UINT8 isr;
  945.     UINT8 * buf;
  946.     int status = OK;
  947.     int count;
  948.     int ix;
  949.     int tranxLen = max (len, MINPKTSIZE);
  950. #ifdef NIC_FASTER
  951.     nicWriteReg(pNic, &pNic->Imr, 0, RPAGE0);   /* disable all interrupts */
  952. #endif
  953.     nicWriteReg (pNic, &pNic->Rbcr0, 0x10, RPAGE0);
  954.     nicWriteCr (pNic, RREAD);
  955.     nicWriteReg (pNic, &pNic->Rbcr0, (tranxLen & 0x00ff), RPAGE0);
  956.     nicWriteReg (pNic, &pNic->Rbcr1, (tranxLen & 0xff00) >> 8, RPAGE0);
  957.     nicWriteReg (pNic, &pNic->Rsar0, 0x00, RPAGE0);
  958.     nicWriteReg (pNic, &pNic->Rsar1, 0x00, RPAGE0);
  959.     nicWriteCr (pNic, RWRITE);
  960.     count = 0;
  961.     for (; pMbuf != NULL; pMbuf = m_free (pMbuf))
  962. for (ix = 0, buf = mtod (pMbuf, UINT8 *); ix < pMbuf->m_len; ix++)
  963.     { 
  964.     count++;
  965.     nicWritePort (*buf++);
  966.     }
  967.     for (; count < tranxLen; count ++) /* pad out if too short */
  968. nicWritePort (0);
  969.     nicWriteReg (pNic, &pNic->Tpsr, 0x00, RPAGE0);
  970.     nicWriteReg (pNic, &pNic->Tbcr0, (tranxLen & 0x000000ff), RPAGE0);
  971.     nicWriteReg (pNic, &pNic->Tbcr1, ((tranxLen & 0x0000ff00) >> 8), RPAGE0);
  972.     cr = nicReadReg (pNic, &pNic->Cr, RPAGE0);
  973.     nicWriteReg(pNic, &pNic->Isr, (PTX | TXE), RPAGE0);
  974.     nicWriteCr (pNic, TXP | (cr & (RWRITE | RREAD))); /* start Tx */
  975.     count = 0;
  976.     if (waitFlag) /* wait for Tx to end ? */
  977. {
  978.         while (count++ < TRANS_TIMEOUT) /* only poll a few times */
  979.     {
  980.             isr = nicReadReg (pNic, &pNic->Isr, RPAGE0);
  981.     if (isr & TXE) /* error encountered */
  982.         {
  983.                 status = ERROR;
  984.         break;
  985.         }
  986.     if (isr & PTX) /* Tx done */
  987.         break;
  988.             }
  989.         if (count >= TRANS_TIMEOUT) /* error ? */
  990.     {
  991.             status = ERROR;
  992. #ifdef NIC_INSTRUMENT
  993.     nicTxTimeout++;
  994. #endif
  995. #ifdef NIC_DEBUG
  996.     if (_func_logMsg != NULL)
  997. _func_logMsg("nicTransmit TRANS_TIMEOUT %dn",
  998.      nicTxTimeout,0,0,0,0,0);
  999. #endif
  1000.     }
  1001.         }
  1002. #ifdef NIC_FASTER
  1003.     nicWriteReg(pNic, &pNic->Imr, PRXE | OVWE, RPAGE0); /* re-enable intr. */
  1004. #endif
  1005.     return (status);
  1006.     }
  1007. /*******************************************************************************
  1008. *
  1009. * nicReceive - receive data from the NIC network interface
  1010. *
  1011. * This routine transfers data from the NIC device ring buffers via the
  1012. * remote DMA.
  1013. *
  1014. * RETURNS: OK, always.
  1015. */
  1016. LOCAL STATUS nicReceive 
  1017.     (
  1018.     DRV_CTRL * pDrvCtrl,
  1019.     UINT32 nicBufAddr, 
  1020.     char * pData, 
  1021.     int len
  1022.     )
  1023.     {
  1024.     NIC_DEVICE * pNic = pDrvCtrl->nicAddr;
  1025.     int residual;
  1026.     int dmaCnt;
  1027.     int ix;
  1028. #ifdef NIC_FASTER
  1029.     nicWriteReg(pNic, &pNic->Imr, 0, RPAGE0); /* disable all interrupts */
  1030. #endif
  1031.     if ((nicBufAddr + len) < (PSTOP * PACKET_SIZE))
  1032. {
  1033. nicWriteReg (pNic, &pNic->Rbcr0, (len & 0xff), RPAGE0);
  1034. nicWriteReg (pNic, &pNic->Rbcr1, ((len & 0xff00) >> 8), RPAGE0);
  1035. nicWriteReg (pNic, &pNic->Rsar0, (nicBufAddr & 0xff), RPAGE0);
  1036. nicWriteReg (pNic, &pNic->Rsar1, (((nicBufAddr & 0xff00)>> 8)), RPAGE0);
  1037. nicWriteCr (pNic, RREAD);
  1038. for (ix = 0; ix < len; ix ++)
  1039.     *pData++ = nicReadPort ();
  1040. }
  1041.     else
  1042. {
  1043. residual = (nicBufAddr + len) - (PSTOP * PACKET_SIZE);
  1044. dmaCnt = len - residual;
  1045. nicWriteReg (pNic, &pNic->Rbcr0, (dmaCnt & 0xff), RPAGE0);
  1046. nicWriteReg (pNic, &pNic->Rbcr1, ((dmaCnt & 0xff00) >> 8), RPAGE0);
  1047. nicWriteReg (pNic, &pNic->Rsar0, (nicBufAddr & 0xff), RPAGE0);
  1048. nicWriteReg (pNic, &pNic->Rsar1, (((nicBufAddr & 0xff00)>> 8)), RPAGE0);
  1049. nicWriteCr (pNic, RREAD);
  1050. for (ix = 0; ix < dmaCnt; ix++)
  1051.     *pData++ = nicReadPort ();
  1052. nicWriteReg (pNic, &pNic->Rbcr0, (residual & 0xff), RPAGE0);
  1053. nicWriteReg (pNic, &pNic->Rbcr1, ((residual & 0xff00) >> 8), RPAGE0);
  1054. nicWriteReg (pNic, &pNic->Rsar0, 0x00, RPAGE0);
  1055. nicWriteReg (pNic, &pNic->Rsar1, PSTART, RPAGE0);
  1056. nicWriteCr (pNic, RREAD);
  1057. for (ix = 0; ix < residual; ix++)
  1058.     *pData++ = nicReadPort ();
  1059. }
  1060. #ifdef NIC_FASTER
  1061.     nicWriteReg(pNic, &pNic->Imr, PRXE | OVWE, RPAGE0); /* re-enable intr. */
  1062. #endif
  1063.     return (OK);
  1064.     } 
  1065. /*******************************************************************************
  1066. *
  1067. * nicLoanFree - return a buffer to the Rx loaner pool
  1068. *
  1069. * RETURNS: N/A.
  1070. */
  1071. LOCAL void nicLoanFree
  1072.     (
  1073.     DRV_CTRL * pDrvCtrl,
  1074.     RX_FRAME * pRx
  1075.     )
  1076.     {
  1077.     pDrvCtrl->lPool [pDrvCtrl->lIndex++] = pRx;
  1078.     }
  1079. /*******************************************************************************
  1080. *
  1081. * nicPagePtrUpdate - updates receive buffer/page pointers
  1082. *
  1083. * This routine updates the receive buffer/page pointer and the receive
  1084. * boundary register (BNRY). The chip is re-initialized if the receive next 
  1085. * packet pointer recorded in the current packet header is out of range.
  1086. *
  1087. * RETURNS: TRUE, or FALSE if next packet pointer is out of range.
  1088. */
  1089.  
  1090. LOCAL BOOL nicPagePtrUpdate
  1091.     (
  1092.     DRV_CTRL *          pDrvCtrl
  1093.     )
  1094.     {
  1095.     RX_FRAME *          pRx = pDrvCtrl->pRxFrame;/* free Rx buffer */
  1096.     NIC_DEVICE *        pNic= pDrvCtrl->nicAddr;
  1097.     /* update ring buffer/page pointers */
  1098.     if ((pRx->rxHdr.nextRxPage < PSTART)||(pRx->rxHdr.nextRxPage >= PSTOP))
  1099.         {
  1100. #ifdef NIC_DEBUG
  1101.         if (_func_logMsg != NULL)
  1102.     _func_logMsg ("nicPagePtrUpdate: statusHeader=0x%x nextRxPage=%d IntNb=%dn",pRx->rxHdr.status, pRx->rxHdr.nextRxPage, nicIntNb, 0,0);
  1103. #endif
  1104. #ifdef NIC_INSTRUMENT
  1105.      nicInitNb++;
  1106. #endif
  1107.         pDrvCtrl->idr.ac_if.if_ierrors++;
  1108. /* restart the chip - we should never end up here - */
  1109.      nicConfig (0);
  1110.      pDrvCtrl->nextPkt = CURR;
  1111.      pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS;
  1112.         return (FALSE);
  1113.         }
  1114.     /* updates the Boundary pointer register (BNRY) */
  1115.     if ((pDrvCtrl->nextPkt = pRx->rxHdr.nextRxPage) == PSTART)
  1116.         nicWriteReg (pNic, &pNic->Bnry, PSTOP - 1, RPAGE0);
  1117.     else
  1118.         nicWriteReg (pNic, &pNic->Bnry, pDrvCtrl->nextPkt - 1, RPAGE0);
  1119.     return (TRUE);
  1120.     }
  1121. /*******************************************************************************
  1122. *
  1123. * nicResetDelay - performs the delay required before resetting the chip 
  1124. *
  1125. * This routine performs a 1.6 ms delay for PowerPC architecture if 
  1126. * using the internal PPC time base (the number of time base increment to
  1127. * count for 1.6 msec is defined by the value nicRestartDelay which must 
  1128. * be set in the BSP), or waits for one system clock tick otherwise.
  1129. *
  1130. * RETURNS: N/A.
  1131. */
  1132.  
  1133. LOCAL void nicResetDelay (void)
  1134.     {
  1135. #ifdef  NIC_USE_PPCTIMEBASE
  1136.     UINT32 tbu1, tbu2;
  1137.     UINT32 tbl1, tbl2;
  1138. #endif
  1139. #ifdef  NIC_USE_PPCTIMEBASE
  1140.     vxTimeBaseGet (&tbu1, &tbl1);
  1141.     while (1)  {
  1142.         vxTimeBaseGet (&tbu2, &tbl2);
  1143.         if ((tbu2-tbu1) != 0)
  1144.             vxTimeBaseGet (&tbu1, &tbl1);
  1145.         else
  1146.     if ((tbl2 - tbl1) > nicRestartDelay)
  1147.              break;
  1148.         }
  1149. #else
  1150.     taskDelay (1);                      /* wait at least 1.6 mSec */
  1151. #endif
  1152.     }