📄 if_dcfast.c
字号:
ULONG dcCSR0Bmr = 0;/* locals */LOCAL DRV_CTRL drvCtrl [MAX_UNITS]; /* array of driver control structs */LOCAL int dcNumRds = NUM_RDS; /* number of ring descriptors */LOCAL int dcNumTds = NUM_TDS; /* number of xmit descriptors */LOCAL int dcLPool = DC_L_POOL;/* forward static functions */LOCAL void dcReset (int unit);LOCAL void dcInt (DRV_CTRL *pDrvCtrl);LOCAL void dcHandleRecvInt (DRV_CTRL *pDrvCtrl);LOCAL STATUS dcRecv (DRV_CTRL *pDrvCtrl, DC_RDE *rmd);LOCAL int dcOutput (IDR *ifp, MBUF *m0, SOCK *dst);LOCAL int dcIoctl (IDR *ifp, int cmd, caddr_t data);LOCAL int dcChipReset (DRV_CTRL *pDrvCtrl);LOCAL DC_RDE * dcGetFullRMD (DRV_CTRL *pDrvCtrl);LOCAL void dcAuiTpInit (ULONG devAdrs);LOCAL void dcCsrWrite (ULONG devAdrs, int reg, ULONG value);LOCAL ULONG dcCsrRead (ULONG devAdrs, int reg);LOCAL void dcRestart (int unit);LOCAL STATUS dcEnetAddrGet (ULONG devAdrs, char * enetAdrs, int len);LOCAL STATUS dc21140EnetAddrGet (ULONG devAdrs, char * enetAdrs, int len);LOCAL BOOL convertDestAddr (IDR * pIDR, SOCK * pDestSktAddr, char * pDestEnetAddr, u_short * pPacketType, MBUF * pMbuf);LOCAL void dcLoanFree (DRV_CTRL *pDrvCtrl, char *pRxBuf, UINT8 *pRef);LOCAL int dcFltrFrmSetup (DRV_CTRL * pDrvCtrl, char * pPhysAdrsTbl, int tblLen);LOCAL int dcFltrFrmXmit (DRV_CTRL * pDrvCtrl, char * pPhysAdrsTbl, int tblLen);#ifdef DC_DEBUGvoid dcCsrShow (ULONG devAdrs);#endif /* DC_DEBUG *//* RCP: Add utilities to read entries in Serial ROM for DEC21140 */USHORT dcReadRom (ULONG devAdrs, UCHAR lineCnt);int dcViewRom (ULONG devAdrs, UCHAR lineCnt, int cnt);/* RCP: Temporary reference of new global symbol */LOCAL STATUS sysLanIntEnable (int Level);/********************************************************************************* dcattach - publish the `dc' network interface.** This routine publishes the `dc' 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 <unit> parameter is used to specify the device unit to initialize.** The <devAdrs> is used to specify the I/O address base of the device.** The <ivec> parameter is used to specify the interrupt vector associated* with the device interrupt.** The <ilevel> parater is used to specify the level of the interrupt which* the device would use.** 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.** The <pciMemBase> parameter defines the main memory base as seen from PCI bus.* * The <dcOpMode> parameter defines the mode in which the device should be* operational.** RCP: Added for DEC21140 Serial ROM** 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 dcattach ( int unit, /* unit number */ ULONG 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) */ ULONG pciMemBase, /* main memory base as seen from PCI bus */ int dcOpMode /* mode of operation */ ) { DRV_CTRL * pDrvCtrl; /* pointer to drvctrl */ unsigned int sz; /* temporary size holder */ char * pShMem; /* start of the LANCE memory pool */ char * buf; /* temp buffer pointer */ void * pTemp; /* temp pointer */ DC_RDE * rmd; /* pointer to rcv descriptor */ DC_TDE * tmd; /* pointer to xmit descriptor */ int ix; /* counter *//* RCP: Added temporary value */ ULONG uTemp; /* temporary storage */ /* 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); pDrvCtrl->ivec = ivec; /* interrupt vector */ pDrvCtrl->ilevel = ilevel; /* interrupt level */ pDrvCtrl->devAdrs = devAdrs; /* LANCE I/O address */ pDrvCtrl->pciMemBase = pciMemBase; /* pci memory base */ pDrvCtrl->memWidth = memWidth; /* memory width */ pDrvCtrl->dcOpMode = dcOpMode; /* mode of operation */ /* Publish the interface data record */ ether_attach ( & pDrvCtrl->idr.ac_if, unit, "dc", (FUNCPTR) NULL, (FUNCPTR) dcIoctl, (FUNCPTR) dcOutput, (FUNCPTR) dcReset ); /* Create the transmit semaphore. */ if ((pDrvCtrl->TxSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE)) == NULL) { printf ("dc: error creating transmitter semaphore\n"); return (ERROR); } /* Establish size of shared memory region we require */ if ((int) memAdrs != NONE) /* specified memory pool */ { sz = (memSize - (RMD_SIZ + TMD_SIZ + (dcLPool * DC_BUFSIZ) + FLTR_FRM_SIZE)) / ((2 * DC_BUFSIZ) + RMD_SIZ + TMD_SIZ); dcNumRds = max (sz, MIN_RDS); dcNumTds = max (sz, MIN_TDS); } /* add it all up - allow for alignment adjustment */ sz = ((dcNumRds + 1) * RMD_SIZ) + (dcNumRds * DC_BUFSIZ) + ((dcNumTds + 1) * TMD_SIZ) + (dcNumTds * DC_BUFSIZ) + (DC_BUFSIZ * dcLPool) + FLTR_FRM_SIZE; /* 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 ( "dc: 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 ( "dc: device requires cache coherent memory\n" ); return (ERROR); } pShMem = (char *) cacheDmaMalloc ( sz ); if ((int)pShMem == NULL) { printf ( "dc: system memory unavailable\n" ); return (ERROR); } /* copy the DMA structure */ pDrvCtrl->cacheFuncs = cacheDmaFuncs; break; } if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(ivec),dcInt,(int)pDrvCtrl) == ERROR) return (ERROR); /* Turkey Carving * -------------- * * LOW MEMORY * |-------------------------------------| * | The Rx descriptors | * | (dcNumRds * sizeof (DC_RDE)) | * |-------------------------------------| * | The receive buffers | * | (DC_BUFSIZ * dcNumRds) | * |-------------------------------------| * | The Rx loaner pool | * | (DC_BUFSIZ * dcLPool) | * |-------------------------------------| * | The Tx descriptors | * | (dcNumTds * sizeof (DC_TDE)) | * |-------------------------------------| * | The transmit buffers | * | (DC_BUFSIZ * dcNumTds) | * |-------------------------------------| * | Setup Filter Frame | * | (FLTR_FRM_SIZE) | * |-------------------------------------| */ /* zero the shared memory */ bzero ( (char *) pShMem, (int) sz ); /* carve Rx memory structure */ pDrvCtrl->rxRing = (DC_RDE *) (((int)pShMem + 0x03) & ~0x03); /* wd align */ pDrvCtrl->dcNumRds = dcNumRds; /* receive ring size */ pDrvCtrl->rxIndex = 0; /* Set up the Rx descriptors */ rmd = pDrvCtrl->rxRing; /* receive ring */ buf = (char *)(rmd + pDrvCtrl->dcNumRds); for (ix = 0; ix < pDrvCtrl->dcNumRds; ix++, rmd++, buf += DC_BUFSIZ) { pTemp = DC_CACHE_VIRT_TO_PHYS (buf); /* convert to PCI phys addr */ pTemp = (void *)(MEM_TO_PCI_PHYS((ULONG)pTemp)); rmd->rDesc2 = PCISWAP((ULONG)pTemp); /* buffer address 1 */ rmd->rDesc3 = 0; /* no second buffer */ /* buffer size */ rmd->rDesc1 = PCISWAP(RDESC1_RBS1_VAL(DC_BUFSIZ) | RDESC1_RBS2_VAL(0)); if (ix == (pDrvCtrl->dcNumRds - 1)) /* if its is last one */ rmd->rDesc1 |= PCISWAP(RDESC1_RER); /* end of receive ring */ rmd->rDesc0 = PCISWAP(RDESC0_OWN); /* give ownership to lance */ } /* setup Rx loaner pool */ pDrvCtrl->nLoanRx = dcLPool; for (ix = 0; ix < dcLPool; ix++, buf += DC_BUFSIZ) { pDrvCtrl->lPool[ix] = buf; pDrvCtrl->refCnt[ix] = 0; pDrvCtrl->pRefCnt[ix] = & pDrvCtrl->refCnt[ix]; } /* carve Tx memory structure */ pDrvCtrl->txRing = (DC_TDE *) (((int)buf + 0x03) & ~0x03); /* word align */ pDrvCtrl->dcNumTds = dcNumTds; /* transmit ring size */ pDrvCtrl->txIndex = 0; pDrvCtrl->txDiIndex = 0; /* Setup the Tx descriptors */ tmd = pDrvCtrl->txRing; /* transmit ring */ buf = (char *)(tmd + pDrvCtrl->dcNumTds); for (ix = 0; ix < pDrvCtrl->dcNumTds; ix++, tmd++, buf += DC_BUFSIZ) { pTemp = DC_CACHE_VIRT_TO_PHYS (buf); /* convert to PCI phys addr */ pTemp = (void *)(MEM_TO_PCI_PHYS((ULONG)pTemp)); tmd->tDesc2 = PCISWAP((ULONG)pTemp); /* buffer address 1 */ tmd->tDesc3 = 0; /* no second buffer */ tmd->tDesc1 = PCISWAP((TDESC1_TBS1_PUT(0) | TDESC1_TBS2_PUT(0) | TDESC1_IC | /* intrpt on xmit */ TDESC1_LS | /* last segment */ TDESC1_FS)); /* first segment */ if (ix == (pDrvCtrl->dcNumTds - 1)) /* if its is last one */ tmd->tDesc1 |= PCISWAP(TDESC1_TER); /* end of Xmit ring */ tmd->tDesc0 = 0 ; /* clear status */ } /* carve Setup Filter Frame buffer */ pDrvCtrl->pFltrFrm = (ULONG *)(((int)buf + 0x03) & ~0x03); /* word align */ buf += FLTR_FRM_SIZE; /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* Device Initialization */ dcChipReset (pDrvCtrl); /* reset the chip */ pTemp = DC_CACHE_VIRT_TO_PHYS (pDrvCtrl->rxRing); pTemp = (void *)(MEM_TO_PCI_PHYS((ULONG)pTemp)); dcCsrWrite (devAdrs, CSR3, ((ULONG)pTemp)); /* recv descriptor */ pTemp = DC_CACHE_VIRT_TO_PHYS (pDrvCtrl->txRing); pTemp = (void *)(MEM_TO_PCI_PHYS((ULONG)pTemp)); dcCsrWrite (devAdrs, CSR4, ((ULONG)pTemp)); /* xmit descriptor */ /* get the ethernet address *//* RCP: If DEC21140 make an alternate call */ if (!DEC21140(pDrvCtrl->dcOpMode)) { if (dcEnetAddrGet (devAdrs, (char *) pDrvCtrl->idr.ac_enaddr, 6) != OK) logMsg ("dc: error reading ethernet rom\n", 0,0,0,0,0,0); } else/* Get the ethernet address for the DEC21140 */ { if (dc21140EnetAddrGet (devAdrs, (char *) pDrvCtrl->idr.ac_enaddr, 6) != OK) logMsg ("dc21140: error reading ethernet rom\n", 0,0,0,0,0,0); }/* RCP: Check to see if Full Duplex mode set */ if ((pDrvCtrl->dcOpMode & DC_FULLDUPLEX_FLAG) && (pDrvCtrl->dcOpMode != NONE)) dcCsrWrite (devAdrs, CSR6, (dcCsrRead(devAdrs, CSR6) | CSR6_FD));/* RCP: DEC21040 Specific Setup */ if (!DEC21140(pDrvCtrl->dcOpMode)) { dcAuiTpInit (devAdrs); /* configure AUI or 10BASE-T *//* RCP: Added initialization of CSR6 to turn off Promiscuous and Multicast */ dcCsrWrite (devAdrs, CSR6, 0x0); } else {/* RCP: DEC21140 Setup - these modes must be set before start Xmitter *//* Default to 10BT */ uTemp = dcCsrRead(devAdrs, CSR6); uTemp = uTemp | CSR6_TTM | CSR6_BIT25;/* Now verify the parameters passed to configure the interface further */ if ((pDrvCtrl->dcOpMode & DC_100_MB_FLAG) && (pDrvCtrl->dcOpMode != NONE)) {/* Hard Coded values from SROM offset to start 100MB testing. The actual code should be imbellished to handle the configuration for other possible interfaces other then 100BaseTx. This information will be stored in the DC21140 Info Leaf of the SROM. In the case of the DEC520-AA PMC, the starting offset for the DEC21140 Info Leaf is 0x41. This location contains some basic capabilities of the interface and the initial state of CSR12. Also there is a block count for the total number of interfaces supported by the interface card. For testing the default values for the SYM_SCR (100MBaseTx) port will be used. The information for this interface starts in offset 0x49. The configuration for Full Duplex starts in offset 0x4D. Potentially the driver could be altered to do some autosensing and configuration, but for now arguments will be passed to the driver to configure it.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -