📄 if_eihk.c
字号:
#define DRV_CTRL_SIZ sizeof(DRV_CTRL)#define EI_RX_TIMEOUT 3 /* # watchdog runs for receive timeout */#define EI_TX_TIMEOUT 2 /* # watchdog runs for transmit timeout *//***** GLOBALS *****//* Function declarations not in any header files */IMPORT void sysSpareInt1 (int arg); /* hkv3500 specific */IMPORT STATUS sysEnetAddrGet (int unit, char addr[]);IMPORT STATUS sys596Init (int unit, SCB *pScb);IMPORT STATUS sys596IntAck (int unit);IMPORT STATUS sys596IntEnable (int unit);IMPORT void sys596IntDisable (int unit);IMPORT void sys596Port (int unit, int cmd, UINT32 addr);IMPORT void sys596ChanAtn (int unit);/***** LOCALS *****//* The array of driver control structs */LOCAL DRV_CTRL drvCtrl [MAX_UNITS];/* forward function declarations */static STATUS eiInit (int unit);static void eiReset (int unit);static int eiIoctl (IDR *pIDR, int cmd, caddr_t data);#ifdef BSD43_DRIVERstatic int eiOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDestAddr);static void eiTxStartup (int unit);#elsestatic void eiTxStartup (DRV_CTRL *pDrvCtrl);#endifvoid eiInt (DRV_CTRL *pDrvCtrl);static void eiTxCleanQ (DRV_CTRL *pDrvCtrl);static void eiHandleRecvInt (DRV_CTRL *pDrvCtrl);static STATUS eiReceive (DRV_CTRL *pDrvCtrl, RFD *pRfd);static void eiLoanFree (DRV_CTRL *pDrvCtrl, RFD *pRfd);static void eiDiag (int unit);static void eiConfig (int unit);static void eiIASetup (int unit);static void eiRxStartup (DRV_CTRL *pDrvCtrl);static void eiAction (int unit, UINT16 action);static STATUS eiCommand (DRV_CTRL *pDrvCtrl, UINT16 cmd);static void eiTxQPut (DRV_CTRL *pDrvCtrl, TFD *pTfd);static void eiTxQFlush (DRV_CTRL *pDrvCtrl);static void eiRxQPut (DRV_CTRL *pDrvCtrl, RFD *pRfd);static RFD *eiRxQGet (DRV_CTRL *pDrvCtrl);static BOOL eiRxQFull (DRV_CTRL *pDrvCtrl);static void eiQInit (EI_LIST *pHead);static EI_NODE *eiQGet (EI_LIST *pQueue);static void eiQPut (int unit, EI_LIST *pQueue, EI_NODE *pNode);static STATUS eiDeviceStart (int unit);static void eiWatchDog(int unit);/********************************************************************************* eihkattach - publish the `ei' network interface and initialize the driver and device** This routine publishes the `ei' interface by filling in a network interface* record and adding this record to the system list. This routine also* initializes the driver and the device to the operational state.** The 82596 shares a region of memory with the driver. The caller of this* routine can specify the address of this memory region, or can specify that* the driver must obtain this memory region from the system resources.** The <sysbus> parameter accepts values as described in the Intel manual* for the 82596. A default number of transmit/receive frames of 32 can be* selected by passing zero in the parameters <nTfds> and <nRfds>.* In other cases, the number of frames selected should be greater than two.** The <memBase> parameter is used to inform the driver about the shared* memory region. If this parameter is set to the constant "NONE," then this* routine will attempt to allocate the shared memory from the system. Any* other value for this parameter is interpreted by this routine as the address* of the shared memory region to be used.** If the caller provides the shared memory region, then the driver assumes* that this region does not require cache coherency operations, nor does it* require conversions between virtual and physical addresses.** If the caller indicates that this routine must allocate the shared memory* region, then this routine will use cacheDmaMalloc() to obtain* some non-cacheable memory. The attributes of this memory will be checked,* and if the memory is not both read and write coherent, this routine will* abort and return ERROR.** RETURNS: OK or ERROR.** SEE ALSO: ifLib,* .I "Intel 82596 User's Manual"*/STATUS eihkattach ( int unit, /* unit number */ int ivec, /* interrupt vector number */ UINT8 sysbus, /* sysbus field of SCP */ char * memBase, /* address of memory pool or NONE */ int nTfds, /* no. of transmit frames (0 = default) */ int nRfds /* no. of receive frames (0 = default) */ ) { DRV_CTRL *pDrvCtrl; UINT size; /* temporary size holder */ UINT sizeScp; UINT sizeIscp; UINT sizeScb; UINT sizeCfd; RFD * pRfd; /* pointer to RFD's */ int ix; static char *errMsg1 = "\neihkattach: could not obtain memory\n"; static char *errMsg2 = "\neihkattach: shared memory not cache coherent\n"; sizeScp = MEM_ROUND_UP (sizeof (SCP)); sizeIscp = MEM_ROUND_UP (sizeof (ISCP)); sizeScb = MEM_ROUND_UP (sizeof (SCB)); sizeCfd = MEM_ROUND_UP (sizeof (CFD)); /* Sanity check the unit number */ if (unit < 0 || unit >= MAX_UNITS) return (ERROR); /* Ensure single invocation per system life */ pDrvCtrl = & drvCtrl [unit]; if (pDrvCtrl->attached) return (OK); /* Determine number of Tx and Rx descriptors to use */ pDrvCtrl->nTFDs = nTfds ? nTfds : DEF_NUM_TFDS; pDrvCtrl->nRFDs = nRfds ? nRfds : DEF_NUM_RFDS; /* Publish the interface record */#ifdef BSD43_DRIVER ether_attach ( (IFNET *)&pDrvCtrl->idr, unit, "ei", (FUNCPTR)NULL, (FUNCPTR) eiIoctl, (FUNCPTR) eiOutput, (FUNCPTR) eiReset);#else ether_attach ( &pDrvCtrl->idr.ac_if, unit, "ei", (FUNCPTR) NULL, (FUNCPTR) eiIoctl, (FUNCPTR) ether_output, (FUNCPTR) eiReset ); pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)eiTxStartup;#endif /* calculate the total size of 82596 memory pool */ size = 16 + /* allow for alignment */ sizeScp + sizeIscp + sizeScb + sizeCfd + /* synch'ed command frame */ (sizeof (RFD) * pDrvCtrl->nRFDs) + /* pool of receive frames */ (sizeof (TFD) * pDrvCtrl->nTFDs); /* pool of transmit frames */ /* Establish the memory area that we will share with the device. If * the caller has provided an area, then we assume it is non-cacheable * and will not require the use of the special cache routines. * If the caller did not provide an area, then we must obtain it from * the system, using the cache savvy allocation routine. */ switch ((int) memBase) { case NONE : /* we must obtain it */ /* this driver can't handle incoherent caches */ if (!CACHE_DMA_IS_WRITE_COHERENT () || !CACHE_DMA_IS_READ_COHERENT ()) { printf (errMsg2); goto error; } pDrvCtrl->memBase = cacheDmaMalloc (size); if (pDrvCtrl->memBase == NULL) /* no memory available */ { printf (errMsg1); goto error; } pDrvCtrl->cacheFuncs = cacheDmaFuncs; break; default : /* the user provided an area */ pDrvCtrl->memBase = memBase; /* use the provided address */ pDrvCtrl->cacheFuncs = cacheNullFuncs; break; } /* Save other passed-in parameters */ pDrvCtrl->sysbus = sysbus; /* remember sysbus value */ pDrvCtrl->ivec = ivec; /* interrupt vector */ /* Carve up the shared memory region into the specific sections */ bzero ((char *) pDrvCtrl->memBase, size); pDrvCtrl->pScp = (SCP *) /* align to first 16 byte page */ ( ((u_long) pDrvCtrl->memBase + 0xf) & ~0xf ); pDrvCtrl->pIscp = (ISCP *)((int)pDrvCtrl->pScp + sizeScp); pDrvCtrl->pScb = (SCB *) ((int)pDrvCtrl->pIscp + sizeIscp); pDrvCtrl->pCfd = (CFD *) ((int)pDrvCtrl->pScb + sizeScb); pDrvCtrl->rfdPool = (RFD *) ((int)pDrvCtrl->pCfd + sizeCfd); pDrvCtrl->tfdPool = (TFD *) ((int)pDrvCtrl->rfdPool+ (sizeof (RFD) * pDrvCtrl->nRFDs)); for (ix = 0, pRfd = pDrvCtrl->rfdPool; ix < DEF_NUM_RFDS; ix++, pRfd++) { pRfd->refCnt = 0; /* initialize ref cnt */ } /* Init the watchdog that will patrol for device lockups */ pDrvCtrl->transLocks = 0; pDrvCtrl->recvLocks = 0; pDrvCtrl->wid = wdCreate (); /* create watchdog */ if (pDrvCtrl->wid == NULL) /* no resource */ goto error; pDrvCtrl->wdInterval = sysClkRateGet() >> 1; /* get our enet addr */ if (sysEnetAddrGet (unit, (char *)pDrvCtrl->idr.ac_enaddr) == ERROR) { errnoSet (S_iosLib_INVALID_ETHERNET_ADDRESS); goto error; } /* initialize the unit */ if (eiInit (unit) == ERROR) goto error; /* Set our flag */ pDrvCtrl->attached = TRUE; /* Set status flags in IDR */ pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS); /* Successful return */ return (OK); /***** Handle error cases *****/ error: { /* Release system memory */ if (((int) memBase == NONE) && ((int) pDrvCtrl->memBase != NULL)) cacheDmaFree (pDrvCtrl->memBase); /* Release watchdog */ if (pDrvCtrl->wid != NULL) wdDelete (pDrvCtrl->wid); return (ERROR); } }/********************************************************************************* eiInit - Initialize the interface.** Initialization of interface; clear recorded pending operations.* Called at boot time and by eiWatchDog() if a reset is required.** RETURNS: OK or ERROR*/static STATUS eiInit ( int unit /* unit number */ ) { DRV_CTRL *pDrvCtrl = & drvCtrl [unit]; pDrvCtrl->rcvHandling = FALSE; /* netTask not running our receive job */ pDrvCtrl->txCleaning = FALSE; /* netTask not running our clean job */ pDrvCtrl->txIdle = TRUE; /* transmitter idle */ eiQInit ((EI_LIST *)&pDrvCtrl->rxQueue); /* to be received queue */ eiQInit ((EI_LIST *)&pDrvCtrl->txQueue); /* to be sent queue */ eiQInit ((EI_LIST *)&pDrvCtrl->tfdQueue); /* free tfds to add to send q */ eiQInit ((EI_LIST *)&pDrvCtrl->cblQueue); /* actively sending queue */ eiQInit ((EI_LIST *)&pDrvCtrl->cleanQueue); /* queue of TFDs to clean */ pDrvCtrl->wdTxTimeout = 0; pDrvCtrl->wdRxTimeout = 0; { /***** Perform device initialization *****/ /* Block local variables */ int ix; sys596IntDisable (unit); /* disable device interrupts */ (void) sys596Init (unit, pDrvCtrl->pScb); /* do board specific init */ /* Connect the interrupt handler */ /* Note: hkv3500 BSP demultiplexes interrupt in sysSpareInt1() */ if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), sysSpareInt1, (int)pDrvCtrl) == ERROR) return (ERROR); /* Start the device */ if ( eiDeviceStart (unit) == ERROR ) return (ERROR); eiDiag (unit); /* run diagnostics */ eiConfig (unit); /* configure chip */ eiIASetup (unit); /* setup address */ for (ix = 0; ix < pDrvCtrl->nTFDs; ix ++) /* tank up the free tfd queue */ { eiQPut ( unit, (EI_LIST *) & pDrvCtrl->tfdQueue, (EI_NODE *) & pDrvCtrl->tfdPool [ix] ); } pDrvCtrl->pFreeRfd = NULL; /* first free RFD */ pDrvCtrl->nLoanRfds = MAX_RFDS_LOANED; /* number of loanable RFD's */ for (ix = 0; ix < pDrvCtrl->nRFDs; ix ++) /* tank up the receive queue */ { if (pDrvCtrl->rfdPool[ix].refCnt == 0) eiRxQPut (pDrvCtrl, & pDrvCtrl->rfdPool [ix]); } sys596IntAck (unit); /* clear any pended dev ints */ sys596IntEnable (unit); /* enable interrupts at system */ } /* End block */ wdCancel(pDrvCtrl->wid); /* in case re-initializing */ wdStart(pDrvCtrl->wid, (int) pDrvCtrl->wdInterval, (FUNCPTR) eiWatchDog, pDrvCtrl->idr.ac_if.if_unit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -