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

📄 if_eex.c

📁 Tornado 2.0.2 source code!vxworks的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    pDrvCtrl->pCfd      = &Cfd;    /* 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;    pDrvCtrl->rcvHandling   = FALSE;  /* netTask not running our receive job */    pDrvCtrl->txCleaning    = FALSE;  /* netTask not running our clean job */    pDrvCtrl->txIdle        = TRUE;         /* transmitter idle */    /* Perform device initialization */    if (eex586Init (unit) != OK)        goto error;    sysIntEnablePIC (ilevel);    /* 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 watchdog */        if (pDrvCtrl->wid != NULL)            wdDelete (pDrvCtrl->wid);        return (ERROR);        }    }/********************************************************************************* eexReset - reset the eex interface** Mark interface as inactive and reset the chip.*/static void eexReset    (    int unit    )    {    DRV_CTRL *pDrvCtrl;    pDrvCtrl = & drvCtrl [unit];    pDrvCtrl->idr.ac_if.if_flags = 0;    eex586IntDisable (unit);                    /* disable ints from the dev */    eex586SetReset (unit);                      /* put the 586 chip in reset */    }/********************************************************************************* eexIoctl - interface ioctl procedure** Process an interface ioctl request.*/static int eexIoctl    (    IDR     *pIDR,    int     cmd,    caddr_t data    )    {    int error;#ifdef EEX_DEBUG    printf ("eex: ioctl: pIDR=%x cmd=%x data=%x\n", pIDR, cmd, data);#endif /* EEX_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/********************************************************************************* eexOutput - 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 eexOutput    (    IDR *    pIDR,    MBUF *     pMbuf,    SOCK * pDestAddr    )    {#ifdef EEX_DEBUG    printf ("eex: output: pIDR=%x pMbuf=%x pDestAddr=%x\n",            pIDR, pMbuf, pDestAddr);#endif /* EEX_DEBUG */    return (ether_output ( (IFNET *)pIDR, pMbuf, pDestAddr,            (FUNCPTR) eexTxStartup, pIDR));    }#endif/********************************************************************************* eexTxStartup - 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 eexOutput() 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 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 eexTxStartup    (    int unit    )    {    DRV_CTRL * pDrvCtrl;    pDrvCtrl = & drvCtrl [unit];#elsestatic void eexTxStartup    (    DRV_CTRL * 	pDrvCtrl    )    {#endif    MBUF * pMbuf;    int length;    EEX_SHORTLINK tfdOffset;    /*     * 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)        {        IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */        copy_from_mbufs (buffer, pMbuf, length);        length = max (ETHERSMALL, length);        if ( (etherOutputHookRtn != NULL) &&            (* etherOutputHookRtn)            (&pDrvCtrl->idr, buffer, length))            continue;        /* get free tfd */        tfdOffset = eexQGet (pDrvCtrl, (EEX_LIST *)&pDrvCtrl->tfdQueue);        if (tfdOffset == NULL)            break;                              /* out of TFD's */        /* copy header and data to contiguous board memory areas */        sysOutWord (pDrvCtrl->port + WRPTR, tfdOffset + TF_BUFFER);        sysOutWordString (pDrvCtrl->port + DXREG, (short *)buffer,                          (length + 1) / 2);#ifndef EEX_AL_LOC        length -= EH_SIZE;              /* compensate for header not in data */#endif  /* EEX_AL_LOC */        sysOutWord (pDrvCtrl->port + WRPTR, tfdOffset + TF_ACT_COUNT);        sysOutWord (pDrvCtrl->port + DXREG,                    (length & ACT_COUNT_MASK) | TBD_S_EOF);#ifndef EEX_AL_LOC        /* Move length/ethertype up to where 82586 expects it following dest. */        sysOutWord (pDrvCtrl->port + RDPTR, tfdOffset + TF_OLDLENGTH);        length = sysInWord (pDrvCtrl->port + DXREG);        /* separate read and write because both pointers increment */        /* on any access to DXREG */        sysOutWord (pDrvCtrl->port + WRPTR, tfdOffset + TF_NEWLENGTH);        sysOutWord (pDrvCtrl->port + DXREG, length);#endif  /* EEX_AL_LOC */#ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic. */        pDrvCtrl->idr.ac_if.if_opackets++;#endif        eexTxQPut (pDrvCtrl, tfdOffset);        }    }/********************************************************************************* eexInt - entry point for handling interrupts from the 82586** 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 eexInt    (    DRV_CTRL *pDrvCtrl    )    {    UINT16  event;    int unit;    unit = pDrvCtrl->idr.ac_if.if_unit;    sysBusIntAck (pDrvCtrl->intLevel);    event = sysInWord (pDrvCtrl->port + SCB_STATUS) & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);#ifdef EEX_DEBUG    logMsg ("eex: interrupt: event=%x\n", event, 0, 0, 0, 0, 0);#endif /* EEX_DEBUG */    eexCommand (pDrvCtrl, event);                        /* ack the events */    eex586IntAck (unit);                                /* ack 586 interrupt */    /* Handle transmitter interrupt */    if (event & SCB_S_CNA)                              /* reclaim tx tfds */        {        wdCancel(pDrvCtrl->wid);                /* canus delenda est */        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 = pDrvCtrl->cblQueue.tail;            }        if (!pDrvCtrl->txCleaning)                          /* not cleaning? */            {            pDrvCtrl->txCleaning = TRUE;                    /* set flag */            netJobAdd ( (FUNCPTR) eexTxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);                            /* defer cleanup */            }        if (pDrvCtrl->txQueue.head != NULL)             /* anything to flush? */            eexTxQFlush (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) eexHandleRecvInt, (int) pDrvCtrl,0, 0, 0, 0);         /* netTask processes */        }             /* dhe 10/20/94 could lose some packets here */    if ( (event & SCB_S_RNR) && !(pDrvCtrl->rcvHandling))        eexRxStartup(pDrvCtrl);    } /********************************************************************************* eexTxCleanQ - 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 eexTxCleanQ    (    DRV_CTRL *pDrvCtrl    )    {    EEX_SHORTLINK tfdOffset;    UINT16 status;    BOOL needTxStart;    int unit;    unit = pDrvCtrl->idr.ac_if.if_unit;    do        {        pDrvCtrl->txCleaning = TRUE;        if (pDrvCtrl->tfdQueue.head == NULL)              /* tfd queue empty */            needTxStart = TRUE;                           /* set flag */        else            needTxStart = FALSE;        /* process transmitted frames */        while (1)            {            /* Get TFD. No ints allowed while manipulating this queue. */            eex586IntDisable (unit);            tfdOffset = eexQGet (pDrvCtrl, (EEX_LIST *)&pDrvCtrl->cleanQueue);            eex586IntEnable (unit);            if (tfdOffset == NULL)                break;            sysOutWord (pDrvCtrl->port + RDPTR, tfdOffset);            status = sysInWord (pDrvCtrl->port + DXREG);            pDrvCtrl->idr.ac_if.if_collisions +=         /* add any colls */                (status & CFD_S_RETRY) ? 16 :  /* excessive colls */                (status & CFD_S_COLL_MASK);    /* some colls */            if (!(status & CFD_S_OK))          /* packet not sent */                {                pDrvCtrl->idr.ac_if.if_oerrors++;        /* incr err count */                pDrvCtrl->idr.ac_if.if_opackets--;       /* decr sent count */                }            /* return to tfdQ */            eexQPut (pDrvCtrl, (EEX_LIST *)&pDrvCtrl->tfdQueue, tfdOffset);            }        if (needTxStart)                                  /* check flag */#ifdef BSD43_DRIVER            eexTxStartup (unit);#else            eexTxStartup (pDrvCtrl);#endif        pDrvCtrl->txCleaning = FALSE;        }    while (pDrvCtrl->cleanQueue.head != NULL);            /* check again */    }/********************************************************************************* eexHandleRecvInt - task level interrupt service for input packets

⌨️ 快捷键说明

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