📄 if_lnsgi.c
字号:
/* * tbuf_err (TMD1.ERR) is an "OR" of LCOL, LCAR, UFLO or RTRY. * Note that BUFF is not indicated in TMD1.ERR. * We should therefore check both tbuf_err and tbuf_buff * here for error conditions. */ if ((tmd->lnTMD1 & TMD_ERR) || (tmd->lnTMD3 & TMD_BUFF)) { ls->ls_if.if_oerrors++; /* output error */ ls->ls_if.if_opackets--; /* check for no carrier */ if (tmd->lnTMD3 & TMD_LCAR) logMsg ("ln%d lnInt: no carrier\n", ls->ls_if.if_unit, 0, 0, 0, 0, 0); /* every lnsgiLogCount errors show other interesting bits of tmd3 */ if ((tmd->lnTMD3 & 0xfc00) && lnsgiLogCount && (ls->ls_if.if_oerrors % lnsgiLogCount) == 0) logMsg ("ln%d lnInt: xmit error, status(tmd3)=0x%x, err count=%d\n", ls->ls_if.if_unit, tmd->lnTMD3 & 0xfc00, ls->ls_if.if_oerrors, 0, 0, 0); /* restart chip on fatal errors */ /* * The following code handles the situation where the transmitter * shuts down due to an underflow error. This is a situation that * will occur if the DMA cannot keep up with the transmitter. * It will occur if the LANCE is being held off from DMA access * for too long or due to significant memory latency. DRAM fresh * or slow memory could influence this. Many implementation use a * dedicated LANCE buffer. This can be static RAM to eliminate * refresh conflicts or dual-port RAM so that the LANCE can have * free run of this memory during its DMA transfers. */ if ((tmd->lnTMD3 & TMD_BUFF) || (tmd->lnTMD3 & TMD_UFLO)) {/* logMsg ("ln%d lnInt: xmit error, tmd3=0x%x. (%s/%d)\n", * ls->ls_if.if_unit, tmd->tbuf_tmd3 & 0xffff, * __FILE__, __LINE__); */ lnCsrIntWrite (ls, 0, lncsr_STOP); /* stop the LANCE */ (void) netJobAdd ((FUNCPTR) lnInit, ls->ls_if.if_unit, 0, 0, 0, 0); return; } } tmd->lnTMD1 &= 0xff; /* clear high byte */ tmd->lnTMD3 = 0; /* clear all error & stat stuff */ sysWbFlush (); /* now bump the tmd disposal index pointer around the ring */ *pDindex = (*pDindex + 1) & (*pTsize - 1); } if (ls->ls_if.if_snd.ifq_head != NULL && (ls->ls_flags & LS_START_OUTPUT_FLAG) == 0) { ls->ls_flags |= LS_START_OUTPUT_FLAG;#ifdef BSD43_DRIVER (void) netJobAdd ( (FUNCPTR)lnStartOutput, ls->ls_if.if_unit, 0, 0, 0, 0);#else (void) netJobAdd ( (FUNCPTR)lnStartOutput, (int)ls, 0, 0, 0, 0);#endif } }/********************************************************************************* lnHandleCsr0Err - task level interrupt service for csr0 errors*/LOCAL void lnHandleCsr0Err ( FAST struct ls_softc *ls, u_short status ) { if (status & lncsr_CERR) /* collision error */ ls->ls_if.if_collisions++; if (status & (lncsr_BABL | lncsr_MISS | lncsr_MERR)) { ++ls->csr0Errs; ++ls->ls_if.if_ierrors; /* every lnsgiLogCount errors show interesting bits of csr0 */ if (lnsgiLogCount && (ls->csr0Errs % lnsgiLogCount) == 0) logMsg ("ln%d lnInt: csr0 error, csr0=0x%x, err count=%d\n", ls->ls_if.if_unit, status, ls->csr0Errs, 0, 0, 0); /* * restart chip on fatal error */ if (status & lncsr_MERR) /* memory error */ (void) netJobAdd ((FUNCPTR) lnInit, ls->ls_if.if_unit, 0, 0, 0, 0); } }/********************************************************************************* lnHandleRecvInt - 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 lnHandleRecvInt ( FAST struct ls_softc *ls ) { FAST ln_rmd *rmd; FAST int oldIndex; do { ls->ls_flags |= LS_RCV_HANDLING_FLAG; while ((rmd = lnGetFullRMD (ls)) != NULL) { /* RMD available */ oldIndex = ls->ls_rindex; if (lnRecv (ls, rmd) == OK) { for (; oldIndex != ls->ls_rindex; oldIndex = (oldIndex + 1) & (ls->ls_rsize - 1)) { rmd = ls->ls_rring + oldIndex; cacheClearEntry (rmd, sizeof(ln_rmd)); LN_RMD_GIVE_TO_LANCE (rmd); sysWbFlush (); } } else break; } /* * There is a RACE right here. The ISR could add a receive packet * and check the boolean below, and decide to exit. Thus the * packet could be dropped if we don't double check before we * return. */ ls->ls_flags &= ~LS_RCV_HANDLING_FLAG; } while (lnGetFullRMD (ls) != NULL); /* this double check solves the RACE */ }/********************************************************************************* lnRecv -** Process Ethernet receive completion:* If input error just drop packet.* Otherwise purge input buffered data path and examine * packet to determine type. If can't determine length* from type, then have to drop packet. Otherwise decapsulate* packet based on type and pass to type-specific higher-level* input routine.** RETURNS: ERROR if RMD shouldn't be returned back to LANCE yet.* Otherwise, returns OK to return the RMD back to LANCE.*/LOCAL STATUS lnRecv ( struct ls_softc *ls, FAST ln_rmd *rmd ) { FAST struct ether_header *eh; FAST struct mbuf *m; FAST u_char *pData; FAST ln_rmd *nextRmd; int ix, len; int off = 0;#ifdef BSD43_DRIVER u_short ether_type;#endif /* * If both STP and ENP are set, LANCE didn't try to * use data chaining. */ if (((rmd->lnRMD1 & lnrmd1_STP) == lnrmd1_STP) && ((rmd->lnRMD1 & lnrmd1_ENP) == lnrmd1_ENP)) { len = rmd->rbuf_mcnt; ls->ls_rindex = (ls->ls_rindex + 1) & (ls->ls_rsize - 1); sysWbFlush (); } else if (((rmd->lnRMD1 & lnrmd1_STP) == lnrmd1_STP) && ((rmd->lnRMD1 & lnrmd1_ENP) == 0)) { /* STP is set but ENP is not set, so LANCE is trying * to use data chaining. We scan the following sequence of * RMD's to find the last buffer in this data chain. */ ix = (ls->ls_rindex + 1) & (ls->ls_rsize - 1); do { nextRmd = ls->ls_rring + ix; /* next rmd */ /* Return if the next rmd is not ready. Try later. */ cacheClearEntry(rmd, sizeof(ln_rmd)); if ((nextRmd->lnRMD1 & lnrmd1_OWN) != 0) return (ERROR); ix = (ix + 1) & (ls->ls_rsize - 1); } /* end of packet? */ while ((nextRmd->lnRMD1 & lnrmd1_ENP) == 0); /* This last RMD contains the valid MCNT. */ ls->ls_rindex = ix; sysWbFlush (); len = nextRmd->rbuf_mcnt; } else { ls->ls_rindex = (ls->ls_rindex + 1) & (ls->ls_rsize - 1); sysWbFlush (); ++ls->ls_if.if_ierrors; if (lnsgiLogCount && (ls->ls_if.if_ierrors % lnsgiLogCount) == 0) logMsg ("ln%d lnRecv: receive error, stp %d enp %d\n", ls->ls_if.if_unit, (rmd->lnRMD1 & lnrmd1_STP) >> 9, (rmd->lnRMD1 & lnrmd1_ENP) >> 8, 0, 0, 0); return (OK); /* intentional */ } /* eh = (struct ether_header *)(rmd->rbuf_ladr | (rmd->rbuf_hadr << 16)); ItoK (eh, struct ether_header *, ls->memBase); */ ++ls->ls_if.if_ipackets; /* bump statistic */ eh = (struct ether_header *) ((u_int) ls->rmd_ring.r_bufs + (u_int) ((((u_int)rmd - (u_int)ls->ls_rring) / sizeof(ln_rmd)) * ls->bufSize)); cacheClearEntry (eh, len); /* call input hook if any */ if ((etherInputHookRtn != NULL) && (* etherInputHookRtn) (&ls->ls_if, (char *)eh, len)) return (OK);#ifdef BSD43_DRIVER /* This legacy code is not correct for the BSD 4.4 stack. It would * also treat multicast addresses like alien packets, and not send * them up the stack. The higher-level protocols in the new stack * can handle these addresses, and will discard them if they do not * match an existing multicast group. */ /* do software filter if controller is in promiscuous mode */ if (ls->ls_flags & LS_PROMISCUOUS_FLAG) if ( (bcmp ( (char *)eh->ether_dhost, /* not our adrs? */ (char *)ls->ls_enaddr, sizeof (eh->ether_dhost)) != 0) && (bcmp ( (char *)eh->ether_dhost, /* not broadcast? */ (char *)etherbroadcastaddr, sizeof (eh->ether_dhost)) != 0)) return (OK);#endif if (len >= sizeof (struct ether_header)) len -= sizeof (struct ether_header); else len = 0; pData = ( (u_char *)eh) + (sizeof (struct ether_header)); #ifdef BSD43_DRIVER check_trailer (eh, pData, &len, &off, &ls->ls_if); if (len == 0) return (OK); ether_type = eh->ether_type;#endif m = NULL; /* * we can loan out receive buffers from LANCE receive ring if: * * 1) canLoanRmd is TRUE. canLoanRmd is set to TRUE if memWidth * is NONE (no special restriction in copying data in terms of * size and boundary conditions) and each of the buffers in the * LANCE ring is big enough to hold the maximum sized ethernet * frame (data-chaining is not being used for the input). * 2) trailer protocol is not being used for the given input ethernet frame. * 3) there is available free buffers that can be used to replace the * rbuf to be loaned out in the free list 'freeBufs'. * 4) size of the input ethernet frame is large enough to be used with * clustering. */ if (ls->canLoanRmds && off == 0 && ls->nFree > 0 && USE_CLUSTER (len)) { m = build_cluster (pData, len, &ls->ls_if, MC_LANCE, &(ls->loanRefCnt [ls->ls_rindex]), lnRmdFree, (int) ls, (int) eh, NULL); if (m != NULL) { FAST char *pBuf; /* get a free buffer from the free list to replace the * rbuf loaned out. replace the rbuf pointers in the RMD * to point to the new buffer. */ pBuf = ls->freeBufs [--ls->nFree]; rmd->rbuf_ladr = (int) pBuf; rmd->lnRMD1 = (rmd->lnRMD1 & ~lnrmd1_HADR) | (((int) pBuf >> 16) & lnrmd1_HADR); sysWbFlush (); } } if (m == NULL)#ifdef BSD43_DRIVER /* * Instead of calling copy_to_mbufs (), we call bcopy_to_mbufs () * with ls->memWidth as an addtional argument to specify unit of a * copy op. * * Most drivers would use macro copy_to_mbufs (), which will in turn * call bcopy_to_mbufs () telling it to use the normal bcopy (). Some * of the on-board LANCE hardware implementations require that you * copy the data by certain number of bytes from dedicated memory * to system memory, so LANCE driver has a ln_bcopy () routine that * conforms to this requirement. */ m = bcopy_to_mbufs (pData, len, off, (struct ifnet *) &ls->ls_if, ls->memWidth);#else m = copy_to_mbufs (pData, len, 0, &ls->ls_if);#endif if (m == NULL) ls->ls_if.if_ierrors++; else#ifdef BSD43_DRIVER do_protocol_with_type (ether_type, m, &ls->ls_ac, len);#else do_protocol (eh, m, &ls->ls_ac, len);#endif return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* lnOutput -** Ethernet output routine.* Encapsulate a packet of type family for the local net.* Use trailer local net encapsulation if enough data in first* packet leaves a multiple of 512 bytes of data in remainder.*/LOCAL int lnOutput ( FAST struct ifnet *ifp, FAST struct mbuf *m0, struct sockaddr *dst ) { return (ether_output (ifp, m0, dst, (FUNCPTR) lnStartOutput, &ls_softc [ifp->if_unit]->ls_ac)); }#endif/********************************************************************************* lnStartOutput - start pending output** Start output to LANCE.* Queue up all pending datagrams for which transmit buffers are available.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -