📄 if_egl.c
字号:
else egl->egl_if.if_ierrors++; /* bump error stat */#else m = bcopy_to_mbufs (pData, len, 0, &egl->egl_if, eglMemWidth); if (m != NULL) do_protocol (eh, m, &egl->egl_ac, len); else egl->egl_if.if_ierrors++; /* bump error stat */#endif }/********************************************************************************* egl_reset - mark interface as inactive & reset the chip** RETURNS: 0 or -1.*/LOCAL STATUS egl_reset ( int unit ) { EGL_SOFTC *egl; volatile SHIO *shio; struct ifnet *ifp; int s; if (unit < 0 || unit >= NEGL) return (-1); egl = egl_softc [unit]; shio = egl->eglAddr; ifp = &egl->egl_if;#ifdef EGL_DEBUG printf ("egl%d: egl_reset\n", unit, 0, 0, 0, 0, 0);#endif /* EGL_DEBUG */ s = splimp (); ifp->if_flags &= ~IFF_RUNNING; if (egl_physreset (unit) != OK) { splx (s);#ifdef EGL_DEBUG logMsg ("egl%d: reset failed\n", unit, 0, 0, 0, 0, 0);#endif return (-1); } splx (s); return (0); }/********************************************************************************* egl_rint - Ethernet interface receive (& error) interrupt*/LOCAL void egl_rint ( int unit, EGL_SOFTC *egl, int index, int len ) { ETH_BUF *eth_buf; if (len != -1) { eth_buf = egl->egl_rbinfo[index]; egl->egl_rbinfo[index] = NULL; egl_ioflush (eth_buf); /* definitly need on receive */ egl_recv (unit, len, eth_buf); REL_ETH_BUF(eth_buf); } (void)egl_hangrcv (unit, index); /* hang another receive request */ egl->egl_qfull = 0; /* at least one slot open now */ }/********************************************************************************* egl_setiopbs - setup iopb's*/LOCAL void egl_setiopbs ( int unit ) { EGL_SOFTC *egl = egl_softc [unit]; volatile SHIO *shio = egl->eglAddr; volatile IOPB *iopb; int ix; ETH_BUF *eth_buf; iopb = &shio->sh_IOPB[EGL_RX_IOPBF]; for (ix = 0; ix < EGL_RX_NBUFF; ix++) { iopb->iopb_OPTION = M_OPT_DMA | M_OPT_IE; iopb->iopb_CMD = CNTR_RECEIVE; iopb->iopb_NVCT = egl->rcv_vec; iopb->iopb_EVCT = egl->rcverr_vec; if (BLOCKMODE) iopb->iopb_TOPT = EGL_TOPT_BLK | DIR_READ; else iopb->iopb_TOPT = EGL_TOPT | DIR_READ; /* use the Host usable buffer region */ if ((eth_buf = egl->egl_rbinfo[ix]) == NULL) GET_ETH_BUF(eth_buf); /* egl_rbinfo[i] always uses iopb at index (EGL_RX_IOPBF+i) */ eth_buf->eth_len = EGL_MTU; egl->egl_rbinfo[ix] = eth_buf; egl->egl_rbinfo[ix]->iopb = (IOPB*)iopb; egl_ioflush (eth_buf); iopb->iopb_BUFF = eth_buf->eth_dat_adr; iopb->iopb_LENGTH = EGL_MTU; iopb->iopb_HBUF = 0; iopb->iopb_PTLF = 0; bzero ((char*)iopb->iopb_NODE, sizeof(iopb->iopb_NODE)); iopb->iopb_SGEC = 0; iopb->iopb_LAN1 = 0; iopb->iopb_LAN3 = 0; iopb++; } iopb = &shio->sh_IOPB[EGL_TX_IOPBF]; for (ix = 0; ix < EGL_TX_NBUFF; ix++) { iopb->iopb_CMD = CNTR_TRANSMIT; iopb->iopb_OPTION = M_OPT_DMA | M_OPT_IE; iopb->iopb_NVCT = egl->xmit_vec; iopb->iopb_EVCT = egl->xmiterr_vec; /* We need to recover any hung transmit buffers if * initialization is due to a HW reset after an error * such as a transmit timeout. */ if ((eth_buf = egl->egl_tbinfo[ix]) != NULL) { egl->egl_tbinfo[ix] = NULL; egl_ioflush (eth_buf); REL_ETH_BUF(eth_buf); } if (BLOCKMODE) iopb->iopb_TOPT = EGL_TOPT_BLK | DIR_WRITE; else iopb->iopb_TOPT = EGL_TOPT | DIR_WRITE; iopb->iopb_HBUF = 0; iopb->iopb_SGEC = 0; iopb->iopb_LAN1 = 0; iopb->iopb_LAN3 = 0; iopb++; } egl->egl_txadd = egl->egl_txrem = EGL_TX_NBUFF-1; egl->egl_quecnt = egl->egl_txcnt = 0; egl->egl_cqe = (CQE *)&shio->sh_CQE[0]; }/********************************************************************************* egl_start - start or re-start output on interface** Get another datagram to send off of the interface queue,* and add it to the transmit packet queue for the interface.*/#ifdef BSD43_DRIVERLOCAL void egl_start ( int unit ) { EGL_SOFTC *egl = egl_softc [unit];#elseLOCAL void egl_start ( EGL_SOFTC * egl ) {#ifdef EGL_DEBUG int unit = egl->egl_if.if_unit;#endif#endif volatile SHIO *shio = egl->eglAddr; volatile IOPB *iopb; volatile CQE *cqe; u_char *bufStart; struct mbuf *m; struct ether_header *eh; ETH_BUF *eth_buf; int len; int index; int s; if (TXFULL(egl->egl_txcnt + egl->egl_quecnt)) {#ifdef EGL_DEBUG logMsg ("egl%d: egl_start - packet queue full\n", unit, 0, 0, 0, 0, 0);#endif /* EGL_DEBUG */ return; /* packet queue is full, can't send anything */ } s = splimp (); IF_DEQUEUE(&egl->egl_if.if_snd, m); if (m == 0) { splx (s); return; } TXINC(egl->egl_txadd); egl->egl_txcnt++; index = egl->egl_txadd; iopb = (IOPB *)&shio->sh_IOPB[EGL_TX_IOPBF + index]; GET_ETH_BUF(eth_buf); bufStart = ð_buf->eth_dat[0]; copy_from_mbufs (bufStart, m, len); /* call output hook if any */ if ((etherOutputHookRtn != NULL) && (* etherOutputHookRtn) (&egl->egl_if, bufStart, len)) { REL_ETH_BUF(eth_buf); splx (s); return; /* output hook has processed this packet */ } eh = (struct ether_header *)bufStart; if ((len - SIZEOF_ETHERHEADER) < ETHERMIN) len = ETHERMIN + SIZEOF_ETHERHEADER; /* must be modulo 4 in order to use block mode transfers */ iopb->iopb_LENGTH = (len + 3) & ~0x3; iopb->iopb_BUFF = eth_buf->eth_dat_adr; eth_buf->eth_len = len; egl->egl_tbinfo[index] = eth_buf; egl_ioflush (eth_buf); if (BLOCKMODE) { /* we can (try and) use block mode transfer, * must be aligned on a long-word boundary */ if (!(iopb->iopb_BUFF & 0x2)) iopb->iopb_TOPT = EGL_TOPT_BLK | DIR_WRITE; else iopb->iopb_TOPT = EGL_TOPT | DIR_WRITE; /* put back to non-block */ } iopb->iopb_PTLF = eh->ether_type; /* * Following code performs an efficient copy of the Ethernet * destination address when the src & dst are word aligned. * This avoids a sequence of 6 one byte writes on the VMEbus. */ if (((ULONG)eh->ether_dhost & 0x3) == 0) { *(int *)iopb->iopb_NODE = *(int *)eh->ether_dhost; *(short *)(iopb->iopb_NODE+4) = *(short *)(eh->ether_dhost+4); } else { bcopy ((char*)eh->ether_dhost, (char*)iopb->iopb_NODE, sizeof(iopb->iopb_NODE)); } bcopy ((char*)egl->egl_enaddr, (char*)eh->ether_shost, sizeof(eh->ether_shost)); /* send */ if (egl->egl_txcnt == 0) {#ifdef EGL_DEBUG logMsg ("egl%d: egl_txcnt is null\n", unit, 0, 0, 0, 0, 0);#endif splx (s); return; /* this should never happen */ } if (egl->egl_qfull != 0) { splx (s); return; } cqe = egl->egl_cqe; if (CQE_BUSY(cqe->cqe_QECR)) { egl->egl_qfull++; /* feed queue is full */ splx (s); return; } TXINC(egl->egl_txrem); egl->egl_txcnt--; index = egl->egl_txrem; cqe->cqe_CTAG = index; cqe->cqe_IOPB_ADDR = (caddr_t)(&shio->sh_IOPB[EGL_TX_IOPBF] + index) - (caddr_t)shio; cqe->cqe_WORK_QUEUE = EGL_XMTQN(0); /* TX work queue 0 */ CQE_GO(cqe->cqe_QECR); egl->egl_quecnt++; if (++egl->egl_cqe == &shio->sh_CQE[MAX_CQE]) egl->egl_cqe = (CQE *)&shio->sh_CQE[0];#ifndef BSD43_DRIVER /* BSD 4.4 ether_output() doesn't bump statistic. */ egl->egl_if.if_opackets++;#endif splx (s); }/********************************************************************************* eglShow - display per unit Eagle driver info** RETURNS: 0 or -1 if unit not present.** NOMANUAL*/int eglShow ( int unit, /* interface unit */ BOOL zap /* zero totals */ ) { static char *e_message [] = { "transmit attempts", " \" DMA completions", " \" LANCE interrupts", " \" good", " \" errors", " \" dones", "receive attempts", " \" starvations", " \" interrupts", " \" good", " \" errors", " \" DMA completions", " \" dones", "Miscellaneous DMA interrupts", "Total LANCE Interrupts", "LANCE Inits", "CSR0 Babble", " \" Collisions", " \" Misses", " \" Memory Errors" }; int ix; volatile SHIO *shio; EGL_SOFTC *egl; if (unit < 0 || unit >= NEGL || (egl = egl_softc [unit]) == NULL) {#ifdef EGL_DEBUG printf ("egl%d: no Eagle driver initialized for unit\n", unit);#endif return (-1); } shio = egl->eglAddr; printf ("egl%d: Firmware revision: ", unit); for (ix = 0; ix < 3; ix++) printf ("%c", shio->sh_CSTB.cstb_FREV [ix]); printf (" Release date: "); for (ix = 0; ix < 8; ix++) printf ("%c", shio->sh_CSTB.cstb_FDATE [ix]); printf ("\n"); for (ix = 0; ix < NELEMENTS(e_message); ix++) { printf (" %-30.30s %4ld\n", e_message [ix], shio->sh_CSB.csb_stat [ix] - egl->CSBstats.csb_stat [ix]); if (zap) egl->CSBstats.csb_stat [ix] = shio->sh_CSB.csb_stat [ix]; } return (0); }/********************************************************************************* egl_tint - Ethernet interface transmit (& error) interrupt*/LOCAL void egl_tint ( int unit, EGL_SOFTC *egl, int index ) { ETH_BUF *eth_buf; eth_buf = egl->egl_tbinfo[index]; egl_ioflush (eth_buf); /* do we need on transmit? */ egl->egl_tbinfo[index] = NULL; REL_ETH_BUF(eth_buf); egl->egl_quecnt--; egl->egl_qfull = 0; /* at least one slot open now */#ifdef BSD43_DRIVER egl_start (unit);#else egl_start (egl);#endif }/********************************************************************************* egl_wait -*/LOCAL int egl_wait ( volatile CRB *crb ) { volatile USHORT *lcrsw = &crb->crb_CRSW; int ix; for (ix = 0; ix < 8000; ix++) { if (*lcrsw & M_CRSW_CRBV) break; DELAY(1000); } /* Check for the Command Response Block Valid bit. Sometimes * the Eagle turns on "Queue Mode Started" just before completing * a command (don't know why, but has been observed). */ if (*lcrsw & M_CRSW_CRBV) { /* Eagle has completed an operation? */ CRB_CLR_DONE(*lcrsw); /* release Eagle */ } if (ix == 0) return (0x1000); /* indicate a timeout occurred */ return (*lcrsw); }#if FALSEvoid egl_delay (int x) { /* use with timexN() from shell for tuning */ DELAY(x); }#endif /* FALSE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -