📄 if_ln.c
字号:
#ifdef __STDC__LOCAL void lnReset (int unit);LOCAL void lnInt (DRV_CTRL *pDrvCtrl);LOCAL void lnHandleRecvInt (DRV_CTRL *pDrvCtrl);LOCAL STATUS lnRecv (DRV_CTRL *pDrvCtrl);#ifdef BSD43_DRIVERLOCAL int lnOutput (IDR *ifp, MBUF *m0, SOCK *dst);#elseLOCAL void lnStartOutput (DRV_CTRL * pDrvCtrl);#endif /* BSD43_DRIVER */LOCAL int lnIoctl (IDR *ifp, int cmd, caddr_t data);LOCAL void lnChipReset (DRV_CTRL *pDrvCtrl);LOCAL BOOL lnGetFullRMD (DRV_CTRL *pDrvCtrl);LOCAL u_short lnCsr0Read (DRV_CTRL * pDrvCtrl);LOCAL void lnCsr0Write (DRV_CTRL * pDrvCtrl, u_short value);LOCAL void lnCsrWrite (DRV_CTRL * pDrvCtrl, int reg, u_short value);LOCAL void lnRestart (int unit);LOCAL void lnRestartSetup (DRV_CTRL * pDrvCtrl);#ifdef BSD43_DRIVERLOCAL BOOL convertDestAddr (IDR *pIDR, SOCK *pDestSktAddr, char *pDestEnetAddr, u_short *pPacketType, MBUF *pMbuf);#endif /* BSD43_DRIVER */LOCAL void lnLoanFree (DRV_CTRL *pDrvCtrl, char *pRxBuf, UINT8 *pRef);#else /* __STDC__ */LOCAL void lnReset ();LOCAL void lnInt ();LOCAL void lnHandleRecvInt ();LOCAL STATUS lnRecv ();#ifdef BSD43_DRIVERLOCAL int lnOutput ();#elseLOCAL void lnStartOutput ();#endif /* BSD43_DRIVER */LOCAL int lnIoctl ();LOCAL void lnChipReset ();LOCAL BOOL lnGetFullRMD ();LOCAL u_short lnCsr0Read ();LOCAL void lnCsr0Write ();LOCAL void lnCsrWrite ();LOCAL void lnRestart ();LOCAL BOOL convertDestAddr ();LOCAL void lnLoanFree ();#endif /* __STDC__ *//********************************************************************************* lnattach - publish the `ln' network interface and initialize driver structures** This routine publishes the `ln' 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 <memAdrs> parameter can be used to specify the location of the* memory that will be shared between the driver and the device. The value* NONE is used to indicate that the driver should obtain the memory.** The <memSize> parameter is valid only if the <memAdrs> parameter is not* set to NONE, in which case <memSize> indicates the size of the* provided memory region.** The <memWidth> parameter sets the memory pool's data port width (in bytes);* if it is NONE, any data width is used.** BUGS* To zero out LANCE data structures, this routine uses bzero(), which* ignores the <memWidth> specification and uses any size data access to* write to memory.** RETURNS: OK or ERROR.*/STATUS lnattach ( int unit, /* unit number */ char *devAdrs, /* LANCE I/O address */ int ivec, /* interrupt vector */ int ilevel, /* interrupt level */ char *memAdrs, /* address of memory pool (-1 = malloc it) */ ULONG memSize, /* only used if memory pool is NOT malloc()'d */ int memWidth, /* byte-width of data (-1 = any width) */ int spare, /* not used */ int spare2 /* not used */ ) { DRV_CTRL *pDrvCtrl; char *pShMem; /* start of the LANCE memory pool */ char *buf; ln_rmd *rmd; unsigned int sz; int ix; /* 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); /* publish the interface data record */#ifdef BSD43_DRIVER ether_attach (& pDrvCtrl->idr.ac_if, unit, "ln", (FUNCPTR) NULL, (FUNCPTR) lnIoctl, (FUNCPTR) lnOutput, (FUNCPTR) lnReset);#else /* Publish the interface record */ ether_attach ( (IFNET *) & pDrvCtrl->idr, unit, "ln", (FUNCPTR) NULL, (FUNCPTR) lnIoctl, (FUNCPTR) ether_output, /* generic ether_output */ (FUNCPTR) lnReset ); pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)lnStartOutput;#endif /* create the transmit semaphore. */ if ((pDrvCtrl->TxSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE)) == NULL) { printf ("ln: error creating transmitter semaphore\n"); return (ERROR); } /* establish size of shared memory region we require */ if ((int) memAdrs != NONE) /* specified memory pool */ { /* we want to maximize lnRsize and lnTsize */ sz = (memSize - (RMD_SIZ + TMD_SIZ + (lnLPool * LN_BUFSIZ) + IB_SIZ)) / ((2 * LN_BUFSIZ) + RMD_SIZ + TMD_SIZ); sz >>= 1; /* adjust for roundoff */ for (lnRsize = 0; sz != 0; lnRsize++, sz >>= 1) ; lnTsize = lnRsize; /* lnTsize = lnRsize for convenience */ } /* limit ring sizes to reasonable values */ lnRsize = max (lnRsize, 2); /* 4 Rx buffers is reasonable min */ lnRsize = min (lnRsize, 7); /* 128 Rx buffers is max for chip */ lnTsize = max (lnTsize, 2); /* 4 Tx buffers is reasonable min */ lnTsize = min (lnTsize, 7); /* 128 Tx buffers is max for chip */ lnLPool = min (lnLPool, LN_L_POOL); /* L_POOL is max for Rx loaner pool */ /* add it all up - allow extra bytes for alignment adjustments */ sz = (((1 << lnRsize) + 1) * RMD_SIZ ) + (LN_BUFSIZ << lnRsize) + (((1 << lnTsize) + 1) * TMD_SIZ ) + (LN_BUFSIZ << lnTsize) + (LN_BUFSIZ * lnLPool) + IB_SIZ + 24; /* establish a region of shared memory */ /* * OK. We now know how much shared memory we need. If the caller * provides a specific memory region, we check to see if the provided * region is large enough for our needs. If the caller did not * provide a specific region, then we attempt to allocate the memory * from the system, using the cache aware allocation system call. */ switch ( (int) memAdrs ) { default : /* caller provided memory */ if ( memSize < sz ) /* not enough space */ { printf ( "ln: not enough memory provided\n" ); return ( ERROR ); } pShMem = memAdrs; /* set the beginning of pool */ /* assume pool is cache coherent, copy null structure */ pDrvCtrl->cacheFuncs = cacheNullFuncs; break; case NONE : /* get our own memory */ /* * Because the structures that are shared between the device * and the driver may share cache lines, the possibility exists * that the driver could flush a cache line for a structure and * wipe out an asynchronous change by the device to a neighboring * structure. Therefore, this driver cannot operate with memory * that is not write coherent. We check for the availability of * such memory here, and abort if the system did not give us what * we need. */ if (!CACHE_DMA_IS_WRITE_COHERENT ()) { printf ( "ln: device requires cache coherent memory\n" ); return (ERROR); } pShMem = (char *) cacheDmaMalloc (sz); if ((int) pShMem == NULL) { printf ( "ln: system memory unavailable\n" ); return (ERROR); } /* copy the DMA structure */ pDrvCtrl->cacheFuncs = cacheDmaFuncs; break; } /* Align pool on 4 byte boundary - uses up to 8 bytes of excess memory. */ pShMem = (char *) ( ( (int)pShMem + 3) & ~3); /* save some things */ pDrvCtrl->flags = 0; /* initialize the LANCE flags */ pDrvCtrl->memWidth = memWidth; pDrvCtrl->ivec = ivec; /* interrupt vector */ pDrvCtrl->ilevel = ilevel; /* interrupt level */ pDrvCtrl->devAdrs = (LN_DEVICE *) devAdrs; /* LANCE I/O address */ pDrvCtrl->pMemPool = pShMem; /* start of memory pool */ /* obtain our Ethernet address and save it */ bcopy ((char *) lnEnetAddr, (char *) pDrvCtrl->idr.ac_enaddr, 6); /* * MEMORY MAPPING * * low memory * * |-------------------------------------| * | The initialization block | * | (IB_SIZ) | * |-------------------------------------| * | The Rx descriptors | * | ((1 << lnRsize) + 1) * RMD_SIZ | * |-------------------------------------| * | The receive buffers | * | (LN_BUFSIZ << lnRsize) | * |-------------------------------------| * | The Rx loaner pool | * | (LN_BUFSIZ * lnLPool) | * |-------------------------------------| * | The Tx descriptors | * | ((1 << lnTsize) + 1)* TMD_SIZ | * |-------------------------------------| * | The transmit buffers | * | (LN_BUFSIZ << lnTsize) | * |-------------------------------------| */ /* first let's clear memory */ bzero ((char *) pShMem, (int) sz); /* XXX deal with memWidth */ /* carve Rx memory structure */ pDrvCtrl->rring = (ln_rmd *) ((int)pShMem + IB_SIZ); pDrvCtrl->rringLen = lnRsize; pDrvCtrl->rringSize = 1 << lnRsize; pDrvCtrl->rmdIndex = 0; /* setup Rx buffer descriptors */ rmd = pDrvCtrl->rring; /* * Set the Rx buffer misaligned so that the ether header will align the * IP header on a 4 byte boundary. */ buf = ( (char *) (rmd + (pDrvCtrl->rringSize +1))) + 2; /* Skip over the receive buffer pool to the Rx loaner pool. */ buf += LN_BUFSIZ << lnRsize; /* setup Rx loaner pool */ pDrvCtrl->nLoanRx = lnLPool; for (ix = 0; ix < lnLPool; ix++) { pDrvCtrl->lPool[ix] = buf + (ix * LN_BUFSIZ); pDrvCtrl->refCnt[ix] = 0; pDrvCtrl->pRefCnt[ix] = & pDrvCtrl->refCnt[ix]; } /* carve Tx memory structure */ /* Note: +2 offset aligns IP header on 4 byte boundary. */ pDrvCtrl->tring = (ln_tmd *)(buf + (ix * LN_BUFSIZ) + 2); pDrvCtrl->tringLen = lnTsize; pDrvCtrl->tringSize = 1 << lnTsize; pDrvCtrl->tmdIndex = 0; pDrvCtrl->tmdIndexC = 0; lnChipReset (pDrvCtrl); /* reset LANCE */ if (intConnect ((VOIDFUNCPTR *) INUM_TO_IVEC (ivec), lnInt, (int) pDrvCtrl) == ERROR) return (ERROR); lnRestartSetup (pDrvCtrl); pDrvCtrl->attached = TRUE; /* Set our flag */ return (OK); }/********************************************************************************* lnReset - reset the interface** Mark interface as inactive & reset the chip*/LOCAL void lnReset ( int unit ) { DRV_CTRL *pDrvCtrl = & drvCtrl [unit]; pDrvCtrl->idr.ac_if.if_flags = 0; lnChipReset (pDrvCtrl); /* reset LANCE */ }/********************************************************************************* lnInt - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller.*/LOCAL void lnInt ( DRV_CTRL *pDrvCtrl ) { ln_tmd *tmd; u_short stat; int i; stat = lnCsr0Read (pDrvCtrl); /* Read the device status register */ if (!(stat & lncsr_INTR)) /* If false interrupt, return. */ return; /* * Enable interrupts, clear receive and/or transmit interrupts, and clear * any errors that may be set. */ lnCsr0Write (pDrvCtrl, ((stat & (lncsr_BABL | lncsr_CERR | lncsr_MISS | lncsr_MERR | lncsr_RINT | lncsr_TINT | lncsr_IDON)) | lncsr_INEA)); /* Check for errors */ if (stat & (lncsr_BABL | lncsr_MISS | lncsr_MERR)) { ++pDrvCtrl->idr.ac_if.if_ierrors; if (stat & lncsr_MERR) /* restart chip on memory error */ { logMsg ("lnInt: memory error detected\n",0, 0, 0, 0, 0, 0); pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); (void) netJobAdd ((FUNCPTR) lnRestart, pDrvCtrl->idr.ac_if.if_unit, 0,0,0,0); } } /* schedule netTask to handle any Rx packets */ if ((stat & lncsr_RINT) && (stat & lncsr_RXON) && !(pDrvCtrl->flags & LN_RX_HANDLING_FLAG)) { pDrvCtrl->flags |= LN_RX_HANDLING_FLAG; (void) netJobAdd ((FUNCPTR)lnHandleRecvInt, (int)pDrvCtrl, 0,0,0,0); } /* * Did LANCE update any of the TMD's? * If not then don't bother continuing with transmitter stuff */ if (!(stat & lncsr_TINT)) { /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* allow interrupt line to go inactive */ i = 3; while (i-- && (lnCsr0Read (pDrvCtrl) & lncsr_INTR)) ; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -