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

📄 if_eitp.c

📁 IXP425的BSP代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    /* 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));    /* Init the watchdog that will patrol for device lockups */    pDrvCtrl->transLocks = 0;    pDrvCtrl->wid = wdCreate ();                      /* create watchdog */    if (pDrvCtrl->wid == NULL)                        /* no resource */        goto error;    /* get our enet addr */    if (sysEnetAddrGet (unit, (char *)pDrvCtrl->idr.ac_enaddr) == ERROR)        goto error;    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 */    { /***** Perform device initialization *****/    /* Block local variables */    int ix;    /* Connect the interrupt handler */    if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (ivec), eiInt, (int)pDrvCtrl)        == ERROR)        goto error;	/* Disable system interrupts (NOTE #1) */	intLevel = intLock ();    /* Start the device */    if ( eiDeviceStart (unit) == ERROR )        goto error;    if ( eiDiag (unit) == ERROR )              /* run diagnostics */		goto error;    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 */        eiRxQPut (pDrvCtrl, & pDrvCtrl->rfdPool [ix]);	/* Re-enable system interrupts */   	intUnlock (intLevel);    } /* End block */    /* 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:        {		/* Re-enable system interrupts */    	intUnlock (intLevel);        /* 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);        }    }/********************************************************************************* eiReset - reset the ei interface** Mark interface as inactive and reset the chip.*/static void eiReset    (    int unit    )    {    int intLevel;    DRV_CTRL *pDrvCtrl;    pDrvCtrl = & drvCtrl [unit];    if (pDrvCtrl->idr.ac_if.if_flags & IFF_RUNNING)        {        /* issue command to disable CU and RU */        intLevel = intLock ();        eiCommand (pDrvCtrl, SCB_C_CUABORT | SCB_C_RUABORT);        intUnlock (intLevel);        }    pDrvCtrl->idr.ac_if.if_flags = 0;    }/********************************************************************************* eiIoctl - interface ioctl procedure** Process an interface ioctl request.*/static int eiIoctl    (    IDR     *pIDR,    int     cmd,    caddr_t data    )    {    int error;#ifdef EI_DEBUG    printf ("ei: ioctl: pIDR=%x cmd=%x data=%x\n", pIDR, cmd, data);#endif /* EI_DEBUG */    error = 0;    switch (cmd)        {        case SIOCSIFADDR:            ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;            arpwhohas (pIDR, &IA_SIN (data)->sin_addr);            break;        case SIOCSIFFLAGS:            /* Flags are set outside this module. No additional work to do. */            break;        default:            error = EINVAL;        }    return (error);    }#ifdef BSD43_DRIVER/********************************************************************************* eiOutput - interface output routine.** This is the entry point for packets arriving from protocols above.  This* routine merely calls our specific output routines that eventually lead* to a transmit to the network.** RETURNS: 0 or appropriate errno*/static int eiOutput    (    IDR *    pIDR,    MBUF *     pMbuf,    SOCK * pDestAddr    )    {#ifdef EI_DEBUG    printf ("ei: output: pIDR=%x pMbuf=%x pDestAddr=%x\n",            pIDR, pMbuf, pDestAddr);#endif /* EI_DEBUG */    return (ether_output ((IFNET *)pIDR, pMbuf, pDestAddr,            (FUNCPTR) eiTxStartup, pIDR));    }#endif/********************************************************************************* eiTxStartup - start output on the chip** Looks for any action on the queue, and begins output 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 eiOutput() to be * called, which calls ether_output(), which will usually call this routine.* 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 slightly different model in which the generic ether_output()* routine 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* thread explained in the second example, with the important distinction that* the context is that of netTask().** The third thread occurs when this routine runs out of TFDs 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, the* transmit clean-up handler detects the out-of-TFDs state and calls this* function. The clean-up handler also runs from netTask.** 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.*/#ifdef BSD43_DRIVERstatic void eiTxStartup    (    int unit    )    {    DRV_CTRL * pDrvCtrl = & drvCtrl [unit];#elsestatic void eiTxStartup    (    DRV_CTRL * 	pDrvCtrl 	/* driver control structure */    )    {#endif    MBUF * pMbuf;    int length;    TFD * pTfd;    /*     * Loop until there are no more packets ready to send or we     * have insufficient resources left to send another one.     */    while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)        {        /* get free tfd */        pTfd = (TFD *) eiQGet ((EI_LIST *)&pDrvCtrl->tfdQueue);        if (pTfd == NULL)            break;                              /* out of TFD's */        IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */        copy_from_mbufs ((ETH_HDR *)pTfd->enetHdr, pMbuf, length);        length = max (ETHERSMALL, length);        if ((etherOutputHookRtn != NULL) &&            (* etherOutputHookRtn)            (&pDrvCtrl->idr, (ETH_HDR *)pTfd->enetHdr, length))            continue;        pTfd->count = length & ~0xc000;     /* fill in length */        eiTxQPut (pDrvCtrl, pTfd);#ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic. */        pDrvCtrl->idr.ac_if.if_opackets++;#endif        }    }/********************************************************************************* eiInt - entry point for handling interrupts from the 82596** The interrupting events are acknowledged to the device, so that the device* will deassert its interrupt signal. The amount of work done here is kept* to a minimum; the bulk of the work is defered to the netTask. Several flags* are used here to synchronize with task level code and eliminate races.*/static void eiInt    (    DRV_CTRL *pDrvCtrl    )    {    UINT16  event;    SCB *pScb;    int unit;    pScb = pDrvCtrl->pScb;    unit = pDrvCtrl->idr.ac_if.if_unit;    event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);#ifdef EI_DEBUG    logMsg ("ei: interrupt: event=%x\n", event, 0, 0, 0, 0, 0);#endif /* EI_DEBUG */    eiCommand (pDrvCtrl, event);                        /* ack the events */    /* Handle transmitter interrupt */    if (event & SCB_S_CNA)                              /* reclaim tx tfds */        {        wdCancel(pDrvCtrl->wid);        if (pDrvCtrl->cleanQueue.head == NULL)      /* clean queue empty */            {            pDrvCtrl->cleanQueue.head = pDrvCtrl->cblQueue.head; /* new head */            pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail; /* new tail */            }        else                                            /* concatenate queues */            {            pDrvCtrl->cleanQueue.tail->pNext =                        (EI_NODE*) pDrvCtrl->cblQueue.head;            pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail;            }        if (!pDrvCtrl->txCleaning)                          /* not cleaning? */            {            pDrvCtrl->txCleaning = TRUE;                    /* set flag */            netJobAdd ((FUNCPTR) eiTxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);                            /* defer cleanup */            }        if (pDrvCtrl->txQueue.head != NULL)             /* anything to flush? */            eiTxQFlush (pDrvCtrl);                      /* flush the tx q */        else            pDrvCtrl->txIdle = TRUE;                    /* transmitter idle */        }    /* Handle receiver interrupt */    if ((event & SCB_S_FR) && !(pDrvCtrl->rcvHandling))        {        pDrvCtrl->rcvHandling = TRUE;        (void) netJobAdd ((FUNCPTR) eiHandleRecvInt, (int) pDrvCtrl,0, 0, 0, 0);         /* netTask processes */        }    }/********************************************************************************* eiTxCleanQ - checks errors in completed TFDs and moves TFDs to free queue** This routine is executed by netTask. It "cleans" the TFDs on the clean-up* queue by checking each one for errors and then returning the TFD to the* "free TFD" queue. The startup routine is sometimes called here to eliminate* the lock-out case where the driver input queue is full but there are no* TFDs available.*/static void eiTxCleanQ    (    DRV_CTRL *pDrvCtrl    )    {    TFD *pTfd;    BOOL needTxStart;    int unit;	int intLevel;

⌨️ 快捷键说明

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