📄 if_lnpci.c
字号:
static STATUS lnRecv (DRV_CTRL *pDrvCtrl, ln_rmd *rmd);#ifdef BSD43_DRIVERstatic int lnOutput (IDR *ifp, MBUF *m0, SOCK *dst);#elseLOCAL void lnPciStartOutput (DRV_CTRL * pDrvCtrl);#endif /* BSD43_DRIVER */static int lnIoctl (IDR *ifp, int cmd, caddr_t data);static int lnChipReset (DRV_CTRL *pDrvCtrl);static ln_rmd * lnGetFullRMD (DRV_CTRL *pDrvCtrl);static void lnCsrWrite (DRV_CTRL * pDrvCtrl, int reg, ULONG value);static ULONG lnCsrRead (DRV_CTRL * pDrvCtrl, int reg);static void lnBcrWrite (DRV_CTRL * pDrvCtrl, int reg, ULONG value);static STATUS lnRestartSetup (DRV_CTRL *pDrvCtrl);static void lnRestart (DRV_CTRL *pDrvCtrl);#ifdef BSD43_DRIVERstatic BOOL convertDestAddr (IDR *pIDR, SOCK *pDestSktAddr, char *pDestEnetAddr, u_short *pPacketType, MBUF *pMbuf);#endif/********************************************************************************* lnPciattach - publish the `lnPci' network interface and initialize the driver and device** 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 lnPciattach ( 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, /* used if memory pool is NOT malloc()'d */ int memWidth, /* byte-width of data (-1 = any width) */ ULONG pciMemBase, /* memory base as seen from PCI*/ int spare2 /* not used */ ) { DRV_CTRL *pDrvCtrl; unsigned int sz; /* temporary size holder */ char *pTurkey; /* start of the LANCE memory pool */ /* 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, "lnPci", (FUNCPTR) NULL, (FUNCPTR) lnIoctl, (FUNCPTR) lnOutput, (FUNCPTR) lnReset);#else ether_attach ( &pDrvCtrl->idr.ac_if, unit, "lnPci", (FUNCPTR) NULL, (FUNCPTR) lnIoctl, (FUNCPTR) ether_output, /* generic output for Ethernet */ (FUNCPTR) lnReset ); pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)lnPciStartOutput;#endif /* Create the transmit semaphore. */ pDrvCtrl->TxSem = semMCreate ( SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE ); if (pDrvCtrl->TxSem == NULL) { printf ("lnPci: error creating transmitter semaphore\n"); return (ERROR); } { /***** Establish size of shared memory region we require *****/ if ((int) memAdrs != NONE) /* specified memory pool */ { /* * With a specified memory pool we want to maximize * lnRsize and lnTsize */ sz = (memSize - (RMD_SIZ + TMD_SIZ + sizeof (ln_ib))) / ((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 */ if (lnRsize < 2) lnRsize = 2; /* 4 buffers is reasonable min */ if (lnRsize > 7) lnRsize = 7; /* 128 buffers is max for chip */ /* limit ring sizes to reasonable values */ if (lnTsize < 2) lnTsize = 2; /* 4 buffers is reasonable min */ if (lnTsize > 7) lnTsize = 7; /* 128 buffers is max for chip */ /* Add it all up */ sz = (sizeof (ln_ib)) + ( ((1 << lnRsize) + 1) * RMD_SIZ ) + (LN_BUFSIZ << lnRsize) + ( ((1 << lnTsize) + 1) * TMD_SIZ ) + (LN_BUFSIZ << lnTsize) + 6; /* allow for alignment adjustment */ } { /***** 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 ( "lnPci: not enough memory provided\n" ); return ( ERROR ); } pTurkey = 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 ( "lnPci: device requires cache coherent memory\n" ); return (ERROR); } pTurkey = (char *) cacheDmaMalloc ( sz ); if ((int)pTurkey == NULL) { printf ( "lnPci: system memory unavailable\n" ); return (ERROR); } /* copy the DMA structure */ pDrvCtrl->cacheFuncs = cacheDmaFuncs; break; } } /* Turkey Carving * -------------- * * LOW MEMORY * * |-------------------------------------| * | The initialization block | * | (sizeof (ln_ib)) | * |-------------------------------------| * | The Rx descriptors | * | (1 << lnRsize) * sizeof (ln_rmd)| * |-------------------------------------| * | The receive buffers | * | (LN_BUFSIZ << lnRsize) | * |-------------------------------------| * | The Tx descriptors | * | (1 << lnTsize) * sizeof (ln_tmd)| * |-------------------------------------| * | The transmit buffers | * | (LN_BUFSIZ << lnTsize) | * |-------------------------------------| */ /* Save some things */ pDrvCtrl->memBase = (char *)((ULONG)pTurkey & 0xff000000); pDrvCtrl->memWidth = memWidth; pDrvCtrl->bufSize = LN_BUFSIZ; pDrvCtrl->pciMemBase = pciMemBase; /* pci memory base */ if ((int) memAdrs == NONE) pDrvCtrl->flags |= LS_MEM_ALLOC_FLAG; { /***** Carve up the turkey *****/ /* First let's clean the whole turkey */ bzero ( (char *) pTurkey, (int) sz ); /* carve out initialization block */ pDrvCtrl->ib = (ln_ib *)pTurkey; sz = sizeof (ln_ib); /* size of initialization block */ /* carve out receive message descriptor (RMD) ring structure */ pDrvCtrl->rpo2 = lnRsize; /* remember for lnConfig */ pDrvCtrl->rsize = (1 << lnRsize); /* receive ring size */ /* make it 16 byte aligned */ pDrvCtrl->rring = (ln_rmd *) (((int)pDrvCtrl->ib + sz + 0x0f) & ~0x0f); sz = (1 << lnRsize) * RMD_SIZ; pDrvCtrl->rmd_ring.r_bufs = (char *)((int)pDrvCtrl->rring + sz); sz = (LN_BUFSIZ << lnRsize); /* room for all the receive buffers */ /* carve out transmit message descriptor (TMD) ring structure */ pDrvCtrl->tpo2 = lnTsize; /* remember for lnConfig */ pDrvCtrl->tsize = (1 << lnTsize); /* transmit ring size */ pDrvCtrl->tring = (ln_tmd *) (((int)pDrvCtrl->rmd_ring.r_bufs + sz + 0x0f) & ~0x0f); sz = (1 << lnTsize) * TMD_SIZ; /* carve out transmit buffer space */ pDrvCtrl->tmd_ring.t_bufs = (char *)((int)pDrvCtrl->tring + sz); } /* Save some values */ pDrvCtrl->ivec = ivec; /* interrupt vector */ pDrvCtrl->ilevel = ilevel; /* interrupt level */ pDrvCtrl->devAdrs = (LN_DEVICE *)devAdrs; /* LANCE I/O address */ /* Obtain our Ethernet address and save it */ bcopy ((char *) lnEnetAddr, (char *)pDrvCtrl->idr.ac_enaddr, 6); /***** Device Initializations *****/ if (lnChipReset (pDrvCtrl) == ERROR) /* reset lance device */ { logMsg ("lnPci: Device failed to reset\n", 0,0,0,0,0,0); return (ERROR); } if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(ivec),lnInt,(int)pDrvCtrl) == ERROR) return (ERROR); if (lnRestartSetup (pDrvCtrl) == ERROR) return (ERROR); pDrvCtrl->attached = TRUE; return (OK); }/********************************************************************************* lnReset - reset the interface** Mark interface as inactive & reset the chip*/static 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.*/static void lnInt ( DRV_CTRL *pDrvCtrl ) { ln_tmd *tmd; int *pDindex; int *pTindex; int *pTsize; ln_tmd *pTring; ULONG stat; /* Read the device status register */ stat = lnCsrRead (pDrvCtrl, 0); /* If false interrupt, return. */ if ( ! (stat & CSR0_INTR) ) return; /* * enable interrupts, clear receive and/or transmit interrupts, and clear * any errors that may be set. */ lnCsrWrite (pDrvCtrl, 0, ((stat & (CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR| CSR0_RINT|CSR0_TINT|CSR0_IDON)) | CSR0_INEA)); /* Check for errors */ if (stat & (CSR0_BABL | CSR0_MISS | CSR0_MERR)) { ++pDrvCtrl->idr.ac_if.if_ierrors; /* restart chip on fatal error */ if (stat & CSR0_MERR) /* memory error */ { pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); (void) netJobAdd ( (FUNCPTR)lnRestart, pDrvCtrl->idr.ac_if.if_unit, 0,0,0,0 ); } } /* Have netTask handle any input packets */ if ((stat & CSR0_RINT) && (stat & CSR0_RXON)) { if ( ! (pDrvCtrl->flags & LS_RCV_HANDLING_FLAG) ) { pDrvCtrl->flags |= LS_RCV_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 & CSR0_TINT)) return; pDindex = &pDrvCtrl->dindex; pTindex = &pDrvCtrl->tindex; pTsize = &pDrvCtrl->tsize; pTring = pDrvCtrl->tring; while (*pDindex != *pTindex) { /* disposal has not caught up */ tmd = pTring + *pDindex;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -