⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_fei.c

📁 Tornado 2.0.2 source code!vxworks的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    pDrvCtrl->pCFD->pPrev = pCFD;    /*     * N.B.     * Use RFD_C_EL to tie the end of the RBD ring, and not RFD_C_SUSP     * This is because we want the option of inserting a new RFD into     * the ring on the fly (i.e., via an SCB_RUSTART command).  Why would     * we do this?  Buffer loaning....  A suspend/resume reception model     * will not allow us to do this, so we must use an idle/start model.     */    /* first ready RFD pointer */    pDrvCtrl->pRFD = pRFD = (RFD *) ((UINT32) pCFD + sizeCFD);    /*initialize the RFD ring,some of the fields will be done later in feiInit*/    for (ix = 0; ix < nRFD; ix++, pRFD++)	{	/* system bus address to link field */	LINK_WR (&pRFD->link,            LOCAL_TO_SYS_ADDR(unit, ((UINT32) pRFD + sizeRFD)) );        /* previous RFD pointer */        pRFD->pPrev = (RFD *) ((UINT32) pRFD - sizeRFD);	LINK_WR (&pRFD->pRBD, 0xffffffff);	/* no RBDs used */	pRFD->bufSize = ETHERMTU + EH_SIZE;	pRFD->refCnt = 0;        pRFD->actualCnt = 0;        }    pRFD--;    LINK_WR (&pRFD->link,LOCAL_TO_SYS_ADDR(unit,(UINT32)pDrvCtrl->pRFD) )        ; /* tie end of RFD ring, use system bus address */    pDrvCtrl->pRFD->pPrev = pRFD;    /* initialize the RFD loanable buffers  */    pDrvCtrl->pRFDL = NULL;    pRFD++;    for (ix = 0; ix < nRFDLoan; ix++, pRFD++)	{	pRFD->rfdStatus = 0;	pRFD->rfdCommand = 0;	LINK_WR (&pRFD->pRBD, 0xffffffff);	/* no RBDs used */	pRFD->bufSize = ETHERMTU + EH_SIZE;	pRFD->refCnt = 0;	pRFD->actualCnt = 0;        pRFD->pPrev = pDrvCtrl->pRFDL;          /* link into head of list */        pDrvCtrl->pRFDL = pRFD;        }    if ((pDrvCtrl->txRestart = txWd = wdCreate ()) == NULL)        goto error;    feiReset (unit);			/* reset the chip */    /* CU and RU should be idle following feiReset() */    if (feiSCBCommand (pDrvCtrl, SCB_C_CULDBASE, TRUE, 0x0) == ERROR)        goto error;    if (feiSCBCommand (pDrvCtrl, SCB_C_RULDBASE, TRUE, 0x0) == ERROR)        goto error;     /* connect the interrupt handler */    if (pDrvCtrl->board.vector)        {        if (SYS_INT_CONNECT(INUM_TO_IVEC (pDrvCtrl->board.vector),                                 feiInt, pDrvCtrl) == ERROR)            goto error;        }    /* get our ethernet hardware address */    bcopy ((char *)pDrvCtrl->board.enetAddr, (char *) pDrvCtrl->idr.ac_enaddr, 	   sizeof (pDrvCtrl->board.enetAddr));    if (feiDiag (unit) == ERROR)	/* run diagnostics */	goto error;    if (feiIASetup (unit) == ERROR)	/* setup address */	goto error;    if (feiConfig (unit) == ERROR)	/* configure chip */	goto error;    pDrvCtrl->rxHandle = FALSE;    pDrvCtrl->txStall = FALSE;    pDrvCtrl->attached = TRUE;    if (feiInit (unit) == ERROR)        goto error;     return (OK);error:					/* error cleanup */        {        if (memAlloc)            cacheDmaFree (memBase);        if (txWd)            wdDelete (txWd);        return (ERROR);        }    }/********************************************************************************* feiInit - initialize the 82557 device** This routine initializes the 82557 device and brings it up to an operational* state.  The driver must have already been attached with the feiattach()* routine.** This routine is called at boot time and by feiWatchDog() if a reset is* required.** RETURNS: OK, or ERROR if the device could not be initialized.*/LOCAL STATUS feiInit     (    int		unit		/* unit number */    )    {    DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];    RFD *       pRFD;    UINT16      event;    int         ix;    if (!pDrvCtrl->attached)            /* must have been attached */        return (ERROR);    /* wait for the receive handler to catch up to the [reset] 557 */    for (ix = (FEI_INIT_TMO * feiClkRate); --ix;)        {        if (!pDrvCtrl->rxHandle)            break;        taskDelay (1);        }    if (!ix)        return (ERROR);    /* initiailize RFD ring */    pRFD = pDrvCtrl->pRFD;    do {        pRFD->rfdStatus = 0;        pRFD->rfdCommand = 0;        pRFD = (RFD *) SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD (&pRFD->link));        } while (pRFD != pDrvCtrl->pRFD);    pRFD->pPrev->rfdCommand = RFD_C_EL;    if (feiNOP (unit) == ERROR)         /* put CU into suspended state */        return (ERROR);    event = pDrvCtrl->pCSR->scbStatus;  /* save int events */    pDrvCtrl->pCSR->scbStatus = event;    BOARD_INT_ACK(unit);   /* acknowledge interrupts */    I82557_INT_ENABLE;    BOARD_INT_ENABLE(unit);         /* enable interrupts at system */    /* mark the interface as up */#ifdef BSD43_DRIVER    pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);#else    pDrvCtrl->idr.ac_if.if_flags |= (IFF_MULTICAST| IFF_UP | IFF_RUNNING				    | IFF_NOTRAILERS);#endif    /* startup the receiver */    if (feiSCBCommand (pDrvCtrl, SCB_C_RUSTART, TRUE,        (UINT32 *)LOCAL_TO_SYS_ADDR(unit, (UINT32) pRFD) ) == ERROR)        return (ERROR);    return (OK);    }/********************************************************************************* feiReset - reset the `fei' interface** This routine marks the interface as inactive and resets the chip.  It brings* down the interface to a non-operational state.  To bring the interface back* up, feiInit() must be called.** RETURNS: N/A*/LOCAL void feiReset    (    int		unit		/* unit number of interface */    )    {    DRV_CTRL *	pDrvCtrl = &drvCtrl [unit];    BOARD_INT_DISABLE(unit);     /* disable system interrupt */    I82557_INT_DISABLE;          /* disable chip interrupt   */    /* mark the interface as down */    pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);    /* issue a selective reset to the 82557 chip */    PORT_WR (&pDrvCtrl->pCSR->port, FEI_PORT_SELRESET);    taskDelay (2);			/* wait for the reset... */    }/********************************************************************************* feiIoctl - interface control request routine** This routine processes the interface's ioctl() request.** RETURNS: OK, or EINVAL if <cmd> is not recognized.*/LOCAL int feiIoctl    (    IFNET *	pIfNet,		/* interface to act upon */    int		cmd,		/* command to process */    caddr_t	data		/* command-specific data */    )    {    DRV_CTRL *  pDrvCtrl = & drvCtrl [pIfNet->if_unit];    int		retVal = OK;    int		s = splimp ();		/* not taken in some calling funcs */    switch (cmd)        {        case SIOCSIFADDR:		/* set interface address */#ifdef BSD43_DRIVER            retVal = set_if_addr (pIfNet, data, pDrvCtrl->idr.ac_enaddr);#else            ((struct arpcom *)pIfNet)->ac_ipaddr = IA_SIN (data)->sin_addr;            arpwhohas ((struct arpcom *) pIfNet, &IA_SIN (data)->sin_addr);#endif            break;        case SIOCSIFFLAGS:		/* set interface flags */            break;#ifdef BSD44_DRIVER        case SIOCADDMULTI:        case SIOCDELMULTI:            pDrvCtrl->idr.ac_if.if_flags |= IFF_PROMISC;            retVal = OK;            break;#endif                    default:            retVal = EINVAL;        }    splx (s);    return (retVal);    }#ifdef BSD43_DRIVER/********************************************************************************* feiOutput - interface output routine** This routine simply calls ether_output().  ether_output() resolves* the hardware addresses and calls feiTxStartup() with the unit number* passed as an argument.** RETURNS: OK if successful, otherwise `errno'.*/LOCAL int feiOutput    (    IDR *	pIDR,    MBUF *	pMbuf,    SOCK *	pDestAddr    )    {    return (ether_output ((IFNET *) pIDR, pMbuf, pDestAddr,	(FUNCPTR) feiTxStartup, pIDR));    }#endif/********************************************************************************* feiTxStartup - transmit frames on the device** Look for packets on the IP output queue; output frames if there is anything* there.** This routine is called from several possible threads.  Each will be described* below.** The first (and most common thread) is when a user task requests the* transmission of data.  Under BSD 4.3, this will cause feiOutput() to be  * called, which will cause ether_output() to be called, which will cause this * routine to be called (usually). This routine will not be called if  * ether_output() finds that our interface output queue is full.  In this case, * the outgoing data will be thrown out. BSD 4.4 uses a slight different model* in which the generic ether_output() is called directly, followed by a call * to this routine.** The second, and most obscure thread, is when the reception of certain* packets causes an immediate (attempted) response.  For example, ICMP echo* packets (ping), and ICMP "no listener on that port" notifications.  All* functions in this driver that handle the reception side are executed in the* context of netTask().  Always.  So, in the case being discussed, netTask()* will receive these certain packets, cause IP to be stimulated, and cause the* generation of a response to be sent.  We then find ourselves following the* first thread explained above, with the important distinction that the* context is that of netTask().** The third thread occurs when this routine runs out of CFDs and returns.  If* this occurs when our output queue is not empty, this routine would typically* not get called again until new output was requested.  Even worse, if the* output queue was also full, this routine would never get called again and* we would have a lock state.  It DOES happen.  To guard against this,* we turn on a watchdog timer to scedule us again after an appropriate timeout.** Note that this function is ALWAYS called between an splnet() and an splx().* This is true because netTask(), and ether_output() take care of* this when calling this function.  Therefore, no calls to these spl functions* are needed anywhere in this output thread.  Thus, mutual exclusion is* guaranteed.** RETURNS: N/A*/LOCAL void feiTxStartup    (#ifdef BSD43_DRIVER    int		unit#else    DRV_CTRL * 	pDrvCtrl #endif    )    {#ifdef BSD43_DRIVER    DRV_CTRL *	pDrvCtrl = &drvCtrl [unit];#else    int		unit = pDrvCtrl->idr.ac_if.if_unit;#endif    CFD *pCFD = pDrvCtrl->pCFD;    CFD *pCFDNext;    MBUF *	pMbuf;    int		length;    int status = OK;    /* loop until no more tx packets or we are out of tx resources */    while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)        {        pCFDNext = (CFD *) SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD(&pCFD->link));        if (!(pCFDNext->cfdStatus & CFD_S_COMPLETE)) /* next CFD free ? */            {            pDrvCtrl->txStall = TRUE;            wdStart (pDrvCtrl->txRestart, FEI_TX_RESTART_TMO * feiClkRate,                (FUNCPTR) feiTxRestart, unit);            break;            }        if (pDrvCtrl->txStall)            wdCancel (pDrvCtrl->txRestart);        IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf); /* dequeue a packet */        copy_from_mbufs (pCFD->cfdTcb.enetHdr, pMbuf, length);        length = max (ETHERSMALL, length); /* short frames are padded */        if ((etherOutputHookRtn != NULL) && (*etherOutputHookRtn)            (&pDrvCtrl->idr, pCFD->cfdTcb.enetHdr, length))            continue;			/* hook routine ate packet */	/* get frame ready for transmission */        pCFD->cfdTcb.count = (length & 0x3fff) | TCB_CNT_EOF;	pCFD->cfdStatus = 0;	pCFD->cfdCommand = CFD_C_XMIT | CFD_C_SUSP;	pCFD->pPrev->cfdCommand &= ~CFD_C_SUSP; /* hook frame into CBL */	/* undates the first ready RFD pointer */	pDrvCtrl->pCFD =	    (CFD *)SYS_TO_LOCAL_ADDR(unit,(UINT32)LINK_RD(&pCFD->link) );        /* Bump the statistic counter. */        pDrvCtrl->idr.ac_if.if_opackets++;	/* resume CU operation ? (check suspended, not sent yet, cmd return) */	if (((pDrvCtrl->pCSR->scbStatus & SCB_S_CUMASK) == SCB_S_CUSUSP) &&	    (pCFD->cfdStatus == 0) )	    {	    status =feiSCBCommand (pDrvCtrl, SCB_C_CURESUME, FALSE, 0);	    if (status == ERROR)	        break;            }        }        /* make sure the last CFD is  transmitted */                    if (pCFD->cfdStatus == 0)            feiSCBCommand (pDrvCtrl, SCB_C_CURESUME, FALSE, 0);    }/********************************************************************************* feiTxRestart - reschedule transmit processing** Reschedule transmit processing because we previously had no available* CFDs.** RETURNS: N/A*/LOCAL void feiTxRestart    (    int         unit    )    {    DRV_CTRL *  pDrvCtrl = &drvCtrl [unit];    pDrvCtrl->txStall = FALSE;#ifdef BSD43_DRIVER    (void) netJobAdd ((FUNCPTR) feiTxStartup, unit, 0, 0, 0, 0);#else    (void) netJobAdd ((FUNCPTR) feiTxStartup, (int)pDrvCtrl, 0, 0, 0, 0);#endif    }/********************************************************************************* feiInt - entry point for handling interrupts from the 82557** The interrupting events are acknowledged to the device, so that the device* will de-assert its interrupt signal.  The amount of work done here is kept* to a minimum; the bulk of the work is defered to the netTask.** RETURNS: N/A*/LOCAL void feiInt    (    DRV_CTRL *	pDrvCtrl    )    {    UINT16	event;    int		unit = pDrvCtrl->idr.ac_if.if_unit;    event = pDrvCtrl->pCSR->scbStatus;	/* save int events */    if ((event & SCB_S_STATMASK) == 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -