⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i82586.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 4 页
字号:
 */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 + -