📄 if_dc.c
字号:
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); } else dcNumRds += (memSize - sz) / (DC_BUFSIZ + TMD_SIZ); 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; } SYS_INT_CONNECT(pDrvCtrl, dcInt, pDrvCtrl, &retVal); if (retVal == 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)); DC_CSR_WRITE (devAdrs, CSR3, ((ULONG)pTemp)); /* recv descriptor */ pTemp = DC_CACHE_VIRT_TO_PHYS (pDrvCtrl->txRing); pTemp = (void *)(MEM_TO_PCI_PHYS((ULONG)pTemp)); DC_CSR_WRITE (devAdrs, CSR4, ((ULONG)pTemp)); /* xmit descriptor */ /* get the ethernet address */ 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 { if (dc21140EnetAddrGet (devAdrs, (char *) pDrvCtrl->idr.ac_enaddr, 6) != OK) logMsg ("dc21140: error reading ethernet rom\n", 0,0,0,0,0,0); } if (!DEC21140(pDrvCtrl->dcOpMode)) { dc21040AuiTpInit (devAdrs); /* configure AUI or 10BASE-T */ DC_CSR_WRITE (devAdrs, CSR6, 0x0); pDrvCtrl->dcMediaBlocks.DontSwitch = 1; } else { DC_CSR_WRITE (devAdrs, CSR6, 0x0); dc21140AuiMiiInit (pDrvCtrl, devAdrs, uTemp); } if ((pDrvCtrl->dcOpMode & DC_FULLDUPLEX_FLAG) && (pDrvCtrl->dcOpMode != NONE)) DC_CSR_UPDATE (devAdrs, CSR6, CSR6_FD); /* clear the status register */ DC_CSR_WRITE (devAdrs, CSR5, 0xffffffff); /* set the operating mode to start Xmitter only */ DC_CSR_UPDATE (devAdrs, CSR6, (CSR6_ST | CSR6_BIT25)); if ((pDrvCtrl->dcOpMode & DC_ILOOPB_FLAG) && (pDrvCtrl->dcOpMode != NONE)) DC_CSR_UPDATE (devAdrs, CSR6, CSR6_OM_ILB); else if ((pDrvCtrl->dcOpMode & DC_ELOOPB_FLAG) && (pDrvCtrl->dcOpMode != NONE)) DC_CSR_UPDATE (devAdrs, CSR6, CSR6_OM_ELB); /* Xmit a Filter Setup Frame */ dcFltrFrmXmit (pDrvCtrl, (char *) pDrvCtrl->idr.ac_enaddr, 1); /* start the receiver with multicast and promiscuous mode, if needed */ DC_CSR_UPDATE (devAdrs, CSR6, (CSR6_SR | ((pDrvCtrl->dcOpMode & DC_MULTICAST_FLAG) ? CSR6_PM: 0) | ((pDrvCtrl->dcOpMode & DC_PROMISCUOUS_FLAG) ? CSR6_PR: 0))); /* set up the interrupts */ if (!DEC21140(pDrvCtrl->dcOpMode)) DC_CSR_WRITE (devAdrs, CSR7, ( CSR7_NIM | /* normal interrupt mask */ CSR7_AIM | /* abnormal interrupt mask */ CSR7_SEM | /* system error mask */ CSR7_RIM | /* rcv interrupt mask */ CSR7_RUM | /* rcv buff unavailable mask */ CSR7_TUM /* xmit buff unavailble mask */ )); else DC_CSR_WRITE (devAdrs, CSR7, ( CSR7_NIM | /* normal interrupt mask */ CSR7_AIM | /* abnormal interrupt mask */ CSR7_SEM | /* system error mask */ CSR7_RIM | /* rcv interrupt mask */ CSR7_RUM | /* rcv buff unavailable mask */ CSR7_TUM /* xmit buff unavailble mask */ )); SYS_INT_ENABLE (pDrvCtrl); pDrvCtrl->idr.ac_if.if_flags |= ((IFF_UP | IFF_RUNNING | IFF_NOTRAILERS) | ((dcOpMode & DC_PROMISCUOUS_FLAG) ? IFF_PROMISC : 0) | ((dcOpMode & DC_MULTICAST_FLAG) ? IFF_ALLMULTI : 0)); /* Set our flag */ pDrvCtrl->attached = TRUE; pDrvCtrl->txFlushScheduled = FALSE; return (OK); }/********************************************************************************* dcReset - reset the interface** Mark interface as inactive & reset the chip*/LOCAL void dcReset ( int unit ) { DRV_CTRL *pDrvCtrl = & drvCtrl [unit]; pDrvCtrl->idr.ac_if.if_flags = 0; dcChipReset (pDrvCtrl); /* reset device */ }/********************************************************************************* dcInt - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller.*/LOCAL void dcInt ( DRV_CTRL * pDrvCtrl /* pointer to device control struct */ ) { ULONG stat; /* status register */ ULONG devAdrs; /* device address */ devAdrs = pDrvCtrl->devAdrs; /* Read the device status register */ stat = DC_CSR_READ (devAdrs, CSR5); /* clear the interrupts */ DC_CSR_WRITE (devAdrs, CSR5, stat); stat &= DC_CSR_READ (devAdrs, CSR7); /* If false interrupt, return. */ if ( ! (stat & (CSR5_NIS | CSR5_AIS)) ) return; /* Check for system error */ if (stat & CSR5_SE) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* restart chip on fatal error */ pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); netJobAdd ((FUNCPTR)dcRestart, pDrvCtrl->idr.ac_if.if_unit, 0,0,0,0); } /* Have netTask handle any input packets */ if (stat & (CSR5_RI | CSR5_RU)) { DC_INT_DISABLE (devAdrs, CSR7_RIM); netJobAdd ((FUNCPTR)dcHandleRecvInt, (int)pDrvCtrl, 0, 0, 0, 0); } if ((stat & CSR5_TU) && pDrvCtrl->idr.ac_if.if_snd.ifq_len && (! pDrvCtrl->txFlushScheduled)) { pDrvCtrl->txFlushScheduled = TRUE; netJobAdd ((FUNCPTR) dcTxFlush, (int) pDrvCtrl, 0, 0, 0, 0); } return; }/********************************************************************************* dcHandleRecvInt - task level interrupt service for input packets** This routine is called at task level indirectly by the interrupt* service routine to do any message received processing.*/LOCAL void dcHandleRecvInt ( DRV_CTRL * pDrvCtrl /* pointer to device control struct */ ) { DC_RDE * rmd; /* pointer to Rx ring descriptor */ while ((rmd = dcGetFullRMD (pDrvCtrl)) != NULL) dcRecv (pDrvCtrl, rmd); DC_INT_ENABLE (pDrvCtrl->devAdrs, CSR7_RIM); while ((rmd = dcGetFullRMD (pDrvCtrl)) != NULL) dcRecv (pDrvCtrl, rmd);#ifdef DC_DEBUG pDrvCtrl->errStats.rxMissed += (DC_CSR_READ (pDrvCtrl->devAdrs, CSR8) & (CSR8_MFO | CSR8_MFC_MSK));#endif /* DC_DEBUG */ return; }/********************************************************************************* dcTxRingClean - cleans up the transmit ring** This routine is called at task level in the context of dcOutput() or* tNetTask by dcTxFlush() to collect statistics, and mark "free" all* descriptors consumed by the device.*/LOCAL void dcTxRingClean ( DRV_CTRL *pDrvCtrl ) { DC_TDE * tmd; /* pointer to Xmit ring descriptor */ while (pDrvCtrl->txDiIndex != pDrvCtrl->txIndex) { /* disposal has not caught up */ tmd = pDrvCtrl->txRing + pDrvCtrl->txDiIndex; /* if the buffer is still owned by device, don't touch it */ DC_CACHE_INVALIDATE (tmd, TMD_SIZ);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -