📄 i82586.c
字号:
*/static inti82586_get_rbd_list(struct ie_softc *sc, u_int16_t *start, u_int16_t *end, int *pktlen){ int off, rbbase = sc->rbds; int rbindex, count = 0; int plen = 0; int rbdstatus; *start = rbindex = sc->rbhead; do { off = IE_RBD_STATUS(rbbase, rbindex); IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ); rbdstatus = sc->ie_bus_read16(sc, off); if ((rbdstatus & IE_RBD_USED) == 0) { /* * This means we are somehow out of sync. So, we * reset the adapter. */#if I82586_DEBUG print_rbd(sc, rbindex);#endif printf("%s: receive descriptors out of sync at %d\n", sc->arpcom.ac_if.if_name, rbindex); return (0); } plen += (rbdstatus & IE_RBD_CNTMASK); if (++rbindex == sc->nrxbuf) rbindex = 0; ++count; } while ((rbdstatus & IE_RBD_LAST) == 0); *end = rbindex; *pktlen = plen; return (count);}/* * Release a range of receive buffer descriptors after we've copied the packet. */static voidi82586_release_rbd_list(struct ie_softc *sc, u_int16_t start, u_int16_t end){ int off, rbbase = sc->rbds; int rbindex = start; do { /* Clear buffer status */ off = IE_RBD_STATUS(rbbase, rbindex); sc->ie_bus_write16(sc, off, 0); if (++rbindex == sc->nrxbuf) rbindex = 0; } while (rbindex != end); /* Mark EOL at new tail */ rbindex = ((rbindex == 0) ? sc->nrxbuf : rbindex) - 1; off = IE_RBD_BUFLEN(rbbase, rbindex); sc->ie_bus_write16(sc, off, IE_RBUF_SIZE|IE_RBD_EOL); /* Remove EOL from current tail */ off = IE_RBD_BUFLEN(rbbase, sc->rbtail); sc->ie_bus_write16(sc, off, IE_RBUF_SIZE); /* New head & tail pointer *//* hmm, why have both? head is always (tail + 1) % NRXBUF */ sc->rbhead = end; sc->rbtail = rbindex;}/* * Drop the packet at the head of the RX buffer ring. * Called if the frame descriptor reports an error on this packet. * Returns 1 if the buffer descriptor ring appears to be corrupt; * and 0 otherwise. */static inti82586_drop_frames(struct ie_softc *sc){ u_int16_t bstart, bend; int pktlen; if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0) return (1); i82586_release_rbd_list(sc, bstart, bend); return (0);}/* * Check the RX frame & buffer descriptor lists for our invariants, * i.e.: EOL bit set iff. it is pointed at by the r*tail pointer. * * Called when the receive unit has stopped unexpectedly. * Returns 1 if an inconsistency is detected; 0 otherwise. * * The Receive Unit is expected to be NOT RUNNING. */static inti82586_chk_rx_ring(struct ie_softc *sc){ int n, off, val; for (n = 0; n < sc->nrxbuf; n++) { off = IE_RBD_BUFLEN(sc->rbds, n); val = sc->ie_bus_read16(sc, off); if ((n == sc->rbtail) ^ ((val & IE_RBD_EOL) != 0)) { /* `rbtail' and EOL flag out of sync */ printf("%s: rx buffer descriptors out of sync at %d\n", sc->arpcom.ac_if.if_name, n); return (1); } /* Take the opportunity to clear the status fields here ? */ } for (n = 0; n < sc->nframes; n++) { off = IE_RFRAME_LAST(sc->rframes, n); val = sc->ie_bus_read16(sc, off); if ((n == sc->rftail) ^ ((val & (IE_FD_EOL|IE_FD_SUSP)) != 0)) { /* `rftail' and EOL flag out of sync */ printf("%s: rx frame list out of sync at %d\n", sc->arpcom.ac_if.if_name, n); return (1); } } return (0);}/* * Read frame NUM from unit UNIT (pre-cached as IE). * * This routine reads the RFD at NUM, and copies in the buffers from the list * of RBD, then rotates the RBD list so that the receiver doesn't start * complaining. Trailers are DROPPED---there's no point in wasting time * on confusing code to deal with them. Hopefully, this machine will * never ARP for trailers anyway. */static intie_readframe(struct ie_softc *sc, int num) /* frame number to read */{ struct ether_header *eh; struct mbuf *m; u_int16_t bstart, bend; int pktlen; if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0) { sc->arpcom.ac_if.if_ierrors++; return (1); } m = ieget(sc, bstart, pktlen); i82586_release_rbd_list(sc, bstart, bend); if (m == 0) { sc->arpcom.ac_if.if_ierrors++; return (0); } /* * Remove the mac header. This is different from the NetBSD * stack. */ eh = mtod(m, struct ether_header *); m->m_data += sizeof (struct ether_header); m->m_len -= sizeof (struct ether_header); m->m_pkthdr.len -= sizeof (struct ether_header);#if I82586_DEBUG if (sc->sc_debug & IED_READFRAME) { printf("%s: frame from ether %s type 0x%x len %d\n", sc->arpcom.ac_if.if_name, ether_sprintf(eh->ether_shost), (u_int)ntohs(eh->ether_type), pktlen); }#endif#if NBPFILTER > 0 /* Check for a BPF filter; if so, hand it up. */ if (sc->arpcom.ac_if.if_bpf != 0) /* Pass it up. */ bpf_mtap(sc->arpcom.ac_if.if_bpf, m);#endif /* NBPFILTER > 0 */ /* * Finally pass this packet up to higher layers. */ ether_input (&sc->arpcom.ac_if, eh, m); sc->arpcom.ac_if.if_ipackets++; #if I82586_DEBUG I82586_TRACE(sc, I82586_RX_OK, sc->arpcom.ac_if.if_ipackets);#endif return (0);}/* * Start transmission on an interface. */voidi82586_start(struct ifnet *ifp){ struct ie_softc *sc = ifp->if_softc; if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; #if I82586_DEBUG I82586_TRACE(sc, I82586_TX_REQ, sc->xmit_busy);#endif rtems_event_send (sc->tx_task, i82586_TX_EVENT);}static voidi82586_tx_task(void *arg){ struct ie_softc *sc = arg; rtems_event_set events; for (;;) { rtems_bsdnet_event_receive (i82586_TX_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, 0, &events); #if I82586_DEBUG I82586_TRACE(sc, I82586_TX_EVT, sc->xmit_busy); if (sc->sc_debug) printf ("%s: =======\n", sc->arpcom.ac_if.if_name);#endif i82586_start_tx(sc); }}static voidi82586_start_tx(struct ie_softc *sc){ struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m0, *m; int buffer, head, xbase; u_short len; int s; #if I82586_DEBUG I82586_TRACE(sc, I82586_START_TX, sc->xmit_busy);#endif if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) {#if I82586_DEBUG I82586_TRACE(sc, I82586_TX_ACTIVE, ifp->if_snd.ifq_len);#endif return; } for (;;) { if (sc->xmit_busy == NTXBUF) { ifp->if_flags |= IFF_OACTIVE; break; } head = sc->xchead; xbase = sc->xbds; IF_DEQUEUE(&ifp->if_snd, m0); if (m0 == 0) break; /* We need to use m->m_pkthdr.len, so require the header */ if ((m0->m_flags & M_PKTHDR) == 0) panic("i82586_start: no header mbuf");#if NBPFILTER > 0 /* Tap off here if there is a BPF listener. */ if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m0);#endif#if I82586_DEBUG if (sc->sc_debug & IED_ENQ) printf("%s: fill buffer %d\n", sc->arpcom.ac_if.if_name, sc->xchead);#endif if (m0->m_pkthdr.len > IE_TBUF_SIZE) printf("%s: tbuf overflow\n", sc->arpcom.ac_if.if_name); buffer = IE_XBUF_ADDR(sc, head); for (m = m0; m != 0; m = m->m_next) { (sc->memcopyout)(sc, mtod(m,caddr_t), buffer, m->m_len); buffer += m->m_len; } len = max(m0->m_pkthdr.len, ETHER_MIN_LEN); m_freem(m0); /* * Setup the transmit buffer descriptor here, while we * know the packet's length. */ sc->ie_bus_write16(sc, IE_XBD_FLAGS(xbase, head), len | IE_TBD_EOL); sc->ie_bus_write16(sc, IE_XBD_NEXT(xbase, head), 0xffff); sc->ie_bus_write24(sc, IE_XBD_BUF(xbase, head), IE_XBUF_ADDR(sc, head)); if (++head == NTXBUF) head = 0; sc->xchead = head;#if I82586_DEBUG I82586_TRACE(sc, I82586_TX_START, sc->xmit_busy);#endif s = splnet(); /* Start the first packet transmitting. */ if (sc->xmit_busy == 0) iexmit(sc); sc->xmit_busy++; splx(s); }}/* * Probe IE's ram setup [ Move all this into MD front-end!? ] * Use only if SCP and ISCP represent offsets into shared ram space. */inti82586_proberam(struct ie_softc *sc){ int result, off; /* Put in 16-bit mode */ off = IE_SCP_BUS_USE(sc->scp); sc->ie_bus_write16(sc, off, 0); IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE); /* Set the ISCP `busy' bit */ off = IE_ISCP_BUSY(sc->iscp); sc->ie_bus_write16(sc, off, 1); IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE); if (sc->hwreset) (sc->hwreset)(sc, CHIP_PROBE); (sc->chan_attn) (sc, CHIP_PROBE); delay(100); /* wait a while... */ /* Read back the ISCP `busy' bit; it should be clear by now */ off = IE_ISCP_BUSY(sc->iscp); IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ); result = sc->ie_bus_read16(sc, off) == 0; /* Acknowledge any interrupts we may have caused. */ ie_ack(sc, IE_ST_WHENCE); return (result);}voidi82586_reset(struct ie_softc *sc, int hard){ int s = splnet(); if (hard) printf("%s: reset\n", sc->arpcom.ac_if.if_name); /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */ sc->arpcom.ac_if.if_timer = 0; sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; /* * Stop i82586 dead in its tracks. */ if (i82586_start_cmd(sc, IE_RUC_ABORT | IE_CUC_ABORT, 0, 0, 0)) printf("%s: abort commands timed out\n", sc->arpcom.ac_if.if_name); /* * This can really slow down the i82586_reset() on some cards, but it's * necessary to unwedge other ones (eg, the Sun VME ones) from certain * lockups. */ if (hard && sc->hwreset) (sc->hwreset)(sc, CARD_RESET); delay(100); ie_ack(sc, IE_ST_WHENCE); if ((sc->arpcom.ac_if.if_flags & IFF_UP) != 0) { i82586_init(&sc->arpcom.ac_if); } splx(s);}static voidsetup_simple_command(struct ie_softc *sc, int cmd, int cmdbuf){ /* Setup a simple command */ sc->ie_bus_write16(sc, IE_CMD_COMMON_STATUS(cmdbuf), 0); sc->ie_bus_write16(sc, IE_CMD_COMMON_CMD(cmdbuf), cmd | IE_CMD_LAST); sc->ie_bus_write16(sc, IE_CMD_COMMON_LINK(cmdbuf), 0xffff); /* Assign the command buffer to the SCB command list */ sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb), cmdbuf);}/* * Run the time-domain reflectometer. */static voidie_run_tdr(struct ie_softc *sc, int cmd){ int result; setup_simple_command(sc, IE_CMD_TDR, cmd); sc->ie_bus_write16(sc, IE_CMD_TDR_TIME(cmd), 0); if (i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0) || (sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd)) & IE_STAT_OK) == 0) result = 0x10000; /* XXX */ else result = sc->ie_bus_read16(sc, IE_CMD_TDR_TIME(cmd)); /* Squash any pending interrupts */ ie_ack(sc, IE_ST_WHENCE); if (result & IE_TDR_SUCCESS) return; if (result & 0x10000) printf("%s: TDR command failed\n", sc->arpcom.ac_if.if_name); else if (result & IE_TDR_XCVR) printf("%s: transceiver problem\n", sc->arpcom.ac_if.if_name); else if (result & IE_TDR_OPEN) printf("%s: TDR detected incorrect termination %d clocks away\n", sc->arpcom.ac_if.if_name, result & IE_TDR_TIME); else if (result & IE_TDR_SHORT) printf("%s: TDR detected a short circuit %d clocks away\n", sc->arpcom.ac_if.if_name, result & IE_TDR_TIME); else printf("%s: TDR returned unknown status 0x%x\n", sc->arpcom.ac_if.if_name, result);}/* * i82586_setup_bufs: set up the buffers * * We have a block of KVA at sc->buf_area which is of size sc->buf_area_sz. * this is to be used for the buffers. The chip indexs its control data * structures with 16 bit offsets, and it indexes actual buffers with * 24 bit addresses. So we should allocate control buffers first so that * we don't overflow the 16 bit offset field. The number of transmit * buffers is fixed at compile time. * */static voidi82586_setup_bufs(struct ie_softc *sc){ int ptr = sc->buf_area; /* memory pool */ int n, r; /* * step 0: zero memory and figure out how many recv buffers and * frames we can have. */ ptr = (ptr + 3) & ~3; /* set alignment and stick with it */ /* * step 1: lay out data structures in the shared-memory area */ /* The no-op commands; used if "nop-chaining" is in effect */ sc->nop_cmds = ptr; ptr += NTXBUF * IE_CMD_NOP_SZ; /* The transmit commands */ sc->xmit_cmds = ptr; ptr += NTXBUF * IE_CMD_XMIT_SZ; /* The transmit buffers descriptors */ sc->xbds = ptr; ptr += NTXBUF * IE_XBD_SZ; /* The transmit buffers */ sc->xbufs = ptr; ptr += NTXBUF * IE_TBUF_SIZE; ptr = (ptr + 3) & ~3; /* re-align.. just in case */ /* Compute free space for RECV stuff */ n = sc->buf_area_sz - (ptr - sc->buf_area); /* Compute size of one RECV frame */ r = IE_RFRAME_SZ + ((IE_RBD_SZ + IE_RBUF_SIZE) * B_PER_F); sc->nframes = n / r; if (sc->nframes <= 0) panic("ie: bogus buffer calc\n"); sc->nrxbuf = sc->nframes * B_PER_F; /* The receice frame descriptors */ sc->rframes = ptr; ptr += sc->nframes * IE_RFRAME_SZ; /* The receive buffer descriptors */ sc->rbds = ptr; ptr += sc->nrxbuf * IE_RBD_SZ; /* The receive buffers */ sc->rbufs = ptr; ptr += sc->nrxbuf * IE_RBUF_SIZE;#if I82586_DEBUG printf("%s: %d frames %d bufs\n", sc->arpcom.ac_if.if_name, sc->nframes, sc->nrxbuf);#endif /* * step 2: link together the recv frames and set EOL on last one */ for (n = 0; n < sc->nframes; n++) { int m = (n == sc->nframes - 1) ? 0 : n + 1; /* Clear status */ sc->ie_bus_write16(sc, IE_RFRAME_STATUS(sc->rframes,n), 0); /* RBD link = NULL */ sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,n), 0xffff); /* Make a circular list */ sc->ie_bus_write16(sc, IE_RFRAME_NEXT(sc->rframes,n), IE_RFRAME_ADDR(sc->rframes,m)); /* Mark last as EOL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -