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

📄 if_eidve.c

📁 IXP425的BSP代码
💻 C
📖 第 1 页 / 共 4 页
字号:
* 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 eidveattach    (    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 = "\neidveattach: could not obtain memory\n";    static char *errMsg2 = "\neidveattach: 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;    /* calculate the total size of 82596 memory pool */    size =            24 +                                /* 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;                }#ifndef	DMA_MEMORY_IS_DUALPORTED            pDrvCtrl->cacheFuncs = cacheDmaFuncs;#endif	/* DMA_MEMORY_IS_DUALPORTED */            break;        default :                               /* the user provided an area */            pDrvCtrl->memBase = memBase;        /* use the provided address */#ifndef	DMA_MEMORY_IS_DUALPORTED            pDrvCtrl->cacheFuncs = cacheNullFuncs;#else	    printf ("\neidveattach: allocate 0x%x bytes from address 0x%x... ",				size, (UINT)(pDrvCtrl->memBase));#endif	/* DMA_MEMORY_IS_DUALPORTED */            break;        }#ifdef	DMA_MEMORY_IS_DUALPORTED	pDrvCtrl->cacheFuncs.flushRtn      = NULL;	pDrvCtrl->cacheFuncs.invalidateRtn = NULL;	pDrvCtrl->cacheFuncs.virtToPhysRtn = (FUNCPTR)sysDmaVirtToPhys;	pDrvCtrl->cacheFuncs.physToVirtRtn = (FUNCPTR)sysDmaPhysToVirt;#endif	/* DMA_MEMORY_IS_DUALPORTED */    /* 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);    /*     * Align the RFD pool on a 2-byte boundary.  This causes the IP     * header to be aligned on a 4-byte boundary and enables the protocol     * layer (ip_input) to access long fields without getting a bus error.     */    pDrvCtrl->rfdPool = (RFD *)         (MEM_ROUND_UP (((int)pDrvCtrl->pCfd + sizeCfd)) + 2);    pDrvCtrl->tfdPool = (TFD *)		/* TFD is OK on a 4-byte boundary */      MEM_ROUND_UP ((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;	}    /* Publish the interface record */    ether_attach    (                    (IFNET *) & pDrvCtrl->idr,                    unit,                    "ei",                    (FUNCPTR) NULL,                    (FUNCPTR) eiIoctl,                    (FUNCPTR) ether_output,                    (FUNCPTR) eiReset                    );    pDrvCtrl->idr.ac_if.if_start = (FUNCPTR) eiTxStartup;    /* 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);           /* do board specific init */    /* Connect the interrupt handler */    if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec),		    eiInt, (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	   );    return (OK);    }/********************************************************************************* eiReset - reset the ei interface** Mark interface as inactive and reset the chip.*/static void eiReset    (    int unit    )    {    DRV_CTRL *pDrvCtrl;    pDrvCtrl = & drvCtrl [unit];    pDrvCtrl->idr.ac_if.if_flags = 0;    sys596IntDisable (unit);                    /* disable ints from the dev */    sys596Port (unit, PORT_RESET, NULL);        /* reset the 596 chip */    }/********************************************************************************* eiIoctl - interface ioctl procedure** Process an interface ioctl request.*/static int eiIoctl    (    IFNET  *pIfNet,    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 *)pIfNet)->ac_ipaddr = IA_SIN (data)->sin_addr;            arpwhohas (pIfNet, &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);    }/********************************************************************************* 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.  This will cause eiOutput() 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.** 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.*/void eiTxStartup    (    DRV_CTRL * pDrvCtrl    )    {    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)        {        IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */        /* get free tfd */        pTfd = (TFD *) eiQGet ((EI_LIST *)&pDrvCtrl->tfdQueue);        if (pTfd == NULL)            {            m_freem (pMbuf);            break;                              /* out of TFD's */            }        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);        }

⌨️ 快捷键说明

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