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

📄 i82586.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 4 页
字号:
    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, prev),                       IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));    off = IE_SCB_STATUS(sc->scb);    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);    if ((sc->ie_bus_read16(sc, off) & IE_CUS_ACTIVE) == 0) {      printf("iexmit: CU not active\n");      i82586_start_transceiver(sc);    }  } else {    sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds,cur),                       0xffff);    sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),                       IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST);    off = IE_SCB_CMDLST(sc->scb);    sc->ie_bus_write16(sc, off, IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);    if (i82586_start_cmd(sc, IE_CUC_START, 0, 0, ASYNC_OPTION))      printf("%s: iexmit: start xmit command timed out\n",             sc->arpcom.ac_if.if_name);  }  sc->arpcom.ac_if.if_timer = 5;}/* * Device timeout/watchdog routine. * Entered if the device neglects to generate an interrupt after a * transmit has been started on it. */voidi82586_watchdog(struct ifnet *ifp){  struct ie_softc *sc = ifp->if_softc;  printf("%s: device timeout\n", ifp->if_name);  ++ifp->if_oerrors;  i82586_reset(sc, 1);}static inti82586_cmd_wait(struct ie_softc *sc){  /* spin on i82586 command acknowledge; wait at most 0.9 (!) seconds */  int i, off;  u_int16_t cmd;  for (i = 0; i < 900000; i++) {    /* Read the command word */    off = IE_SCB_CMD(sc->scb);    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);    if ((cmd = sc->ie_bus_read16(sc, off)) == 0)      return (0);    delay(1);  }  off = IE_SCB_STATUS(sc->scb);  printf("i82586_cmd_wait: timo(%ssync): scb status: 0x%x, cmd: 0x%x\n",         sc->async_cmd_inprogress?"a":"",          sc->ie_bus_read16(sc, off), cmd);  return (1);  /* Timeout */}/* * Send a command to the controller and wait for it to either complete * or be accepted, depending on the command.  If the command pointer * is null, then pretend that the command is not an action command. * If the command pointer is not null, and the command is an action * command, wait for one of the MASK bits to turn on in the command's * status field. * If ASYNC is set, we just call the chip's attention and return. * We may have to wait for the command's acceptance later though. */static inti82586_start_cmd(struct ie_softc *sc, int cmd, int iecmdbuf, int mask, int async){  int i;  int off;  if (sc->async_cmd_inprogress != 0) {    /*     * If previous command was issued asynchronously, wait     * for it now.     */    if (i82586_cmd_wait(sc) != 0)      return (1);    sc->async_cmd_inprogress = 0;  }  off = IE_SCB_CMD(sc->scb);  sc->ie_bus_write16(sc, off, cmd);  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);  (sc->chan_attn)(sc, CARD_RESET);  if (async != 0) {    sc->async_cmd_inprogress = 1;    return (0);  }  if (IE_ACTION_COMMAND(cmd) && iecmdbuf) {    int status;    /*     * Now spin-lock waiting for status.  This is not a very nice     * thing to do, and can kill performance pretty well...     * According to the packet driver, the minimum timeout     * should be .369 seconds.     */    for (i = 0; i < 369000; i++) {      /* Read the command status */      off = IE_CMD_COMMON_STATUS(iecmdbuf);      IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);      status = sc->ie_bus_read16(sc, off);      if (status & mask)        return (0);      delay(1);    }  } else {    /*     * Otherwise, just wait for the command to be accepted.     */    return (i82586_cmd_wait(sc));  }  /* Timeout */  return (1);}/* * Transfer accumulated chip error counters to IF. */static __inline voidi82586_count_errors(struct ie_softc *sc){  int scb = sc->scb;  sc->arpcom.ac_if.if_ierrors +=    sc->ie_bus_read16(sc, IE_SCB_ERRCRC(scb)) +    sc->ie_bus_read16(sc, IE_SCB_ERRALN(scb)) +    sc->ie_bus_read16(sc, IE_SCB_ERRRES(scb)) +    sc->ie_bus_read16(sc, IE_SCB_ERROVR(scb));  /* Clear error counters */  sc->ie_bus_write16(sc, IE_SCB_ERRCRC(scb), 0);  sc->ie_bus_write16(sc, IE_SCB_ERRALN(scb), 0);  sc->ie_bus_write16(sc, IE_SCB_ERRRES(scb), 0);  sc->ie_bus_write16(sc, IE_SCB_ERROVR(scb), 0);}static voidi82586_rx_errors(struct ie_softc *sc, int fn, int status){  char bits[128];  printf("%s: rx error (frame# %d): %s\n", sc->arpcom.ac_if.if_name, fn,         bitmask_snprintf(status, IE_FD_STATUSBITS, bits, sizeof(bits)));}/* * i82586 interrupt entry point. */rtems_isri82586_intr(rtems_vector_number vec, void *arg){  struct ie_softc *sc = arg;#if I82586_DEBUG  static unsigned long icnt = 0;  I82586_TRACE(sc, I82586_INTS_REQ, icnt++);#endif      /*   * Implementation dependent interrupt handling. It must at least   * disabled interrupts from the i82586. It is hoped this can   * happen somewhere outside the i82586.   */  if (sc->intrhook)    (sc->intrhook)(sc, INTR_ENTER);  /*   * Wake the task to handle the interrupt. It will   * enabled the interrupts when it has finished.   */  rtems_event_send (sc->intr_task, i82586_WAKE_EVENT);}/* * i82586 interrupt task. The task is actually an extension of the interrupt * with a context switch in the middle. The RTEMS TCP/IP stack requires a task * be used to talk to the stack as a network semaphore is claimed. This * cannot happen during an interrupt. */static voidi82586_intr_task(void *arg){  struct ie_softc *sc = arg;  rtems_event_set events;  u_int           status;  int             off;  int             reset;    /*   * Not sure this is a good idea but as a out path exists and   * roads lead to it, it seems ok.   */  for (;;) {    rtems_bsdnet_event_receive (i82586_WAKE_EVENT,                                RTEMS_WAIT | RTEMS_EVENT_ANY,                                0, &events);    off = IE_SCB_STATUS(sc->scb);    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);    status = sc->ie_bus_read16(sc, off) & IE_ST_WHENCE;#if I82586_DEBUG    I82586_TRACE(sc, I82586_INTS_IN, status);#endif    reset = 0;        while ((status & IE_ST_WHENCE) != 0) {#if I82586_DEBUG      if (sc->sc_debug)        printf ("%s: -------\n%s: scbstatus=0x%x\n",                sc->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_name, status);#endif    #if 1      /* Ack interrupts FIRST in case we receive more during the ISR. */      ie_ack(sc, status & IE_ST_WHENCE);#endif      i82586_start_cmd(sc, status & IE_ST_WHENCE, 0, 0, ASYNC_OPTION);      if (status & (IE_ST_FR | IE_ST_RNR))        if (i82586_rint(sc, status) != 0) {          reset = 1;          break;        }      if (status & IE_ST_CX)        if (i82586_tint(sc, status) != 0) {          reset = 1;          break;        }#if I82586_DEBUG      if ((status & IE_ST_CNA) && (sc->sc_debug & IED_CNA))        printf("%s: cna; status=0x%x\n", sc->arpcom.ac_if.if_name, status);#endif#if 0      if (sc->intrhook)        (sc->intrhook)(sc, INTR_LOOP);#endif#if 1      /*       * Interrupt ACK was posted asynchronously; wait for       * completion here before reading SCB status again.       *        * If ACK fails, try to reset the chip, in hopes that       * it helps.       */      if (i82586_cmd_wait(sc) != 0) {          reset = 1;          break;        }#endif          IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);      status = sc->ie_bus_read16(sc, off);#if I82586_DEBUG      I82586_TRACE(sc, I82586_INTS_LOOPS, status);#endif    }        if (reset) {#if I82586_DEBUG      printf("%s: intr reset; status=0x%x\n", sc->arpcom.ac_if.if_name, status);#endif      i82586_cmd_wait(sc);      i82586_reset(sc, 1);    }    #if I82586_DEBUG    I82586_TRACE(sc, I82586_INTS_OUT, status);#endif        if (sc->intrhook)      (sc->intrhook)(sc, INTR_EXIT);  }}/* * Process a received-frame interrupt. */inti82586_rint(struct ie_softc *sc, int scbstatus){  static int timesthru = 1024;  int i, status, off;#if I82586_DEBUG  I82586_TRACE(sc, I82586_RX_INT, scbstatus);    if (sc->sc_debug & IED_RINT)    printf("%s: rint: status 0x%x\n",           sc->arpcom.ac_if.if_name, scbstatus);#endif  for (;;) {    int drop = 0;    i = sc->rfhead;    off = IE_RFRAME_STATUS(sc->rframes, i);    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);    status = sc->ie_bus_read16(sc, off);#if I82586_DEBUG    if (sc->sc_debug & IED_RINT)      printf("%s: rint: frame(%d) status 0x%x\n",             sc->arpcom.ac_if.if_name, i, status);#endif    if ((status & IE_FD_COMPLETE) == 0) {      if ((status & IE_FD_OK) != 0) {        printf("%s: rint: weird: ",               sc->arpcom.ac_if.if_name);        i82586_rx_errors(sc, i, status);#if I82586_DEBUG        I82586_TRACE(sc, I82586_RX_ERR, status);#endif        break;      }      if (--timesthru == 0) {        /* Account the accumulated errors */        i82586_count_errors(sc);        timesthru = 1024;      }      break;    } else if ((status & IE_FD_OK) == 0) {      /*       * If the chip is configured to automatically       * discard bad frames, the only reason we can       * get here is an "out-of-resource" condition.       */      i82586_rx_errors(sc, i, status);      drop = 1;      #if I82586_DEBUG      I82586_TRACE(sc, I82586_RX_DROP, status);#endif    }#if I82586_DEBUG    if ((status & IE_FD_BUSY) != 0)      printf("%s: rint: frame(%d) busy; status=0x%x\n",             sc->arpcom.ac_if.if_name, i, status);#endif    /*     * Advance the RFD list, since we're done with     * this descriptor.     */    /* Clear frame status */    sc->ie_bus_write16(sc, off, 0);    /* Put fence at this frame (the head) */    off = IE_RFRAME_LAST(sc->rframes, i);    sc->ie_bus_write16(sc, off, IE_FD_EOL|IE_FD_SUSP);    /* and clear RBD field */    off = IE_RFRAME_BUFDESC(sc->rframes, i);    sc->ie_bus_write16(sc, off, 0xffff);    /* Remove fence from current tail */    off = IE_RFRAME_LAST(sc->rframes, sc->rftail);    sc->ie_bus_write16(sc, off, 0);    if (++sc->rftail == sc->nframes)      sc->rftail = 0;    if (++sc->rfhead == sc->nframes)      sc->rfhead = 0;    /* Pull the frame off the board */    if (drop) {      i82586_drop_frames(sc);      if ((status & IE_FD_RNR) != 0)        sc->rnr_expect = 1;      sc->arpcom.ac_if.if_ierrors++;    } else if (ie_readframe(sc, i) != 0)      return (1);  }  if ((scbstatus & IE_ST_RNR) != 0) {    /*     * Receiver went "Not Ready". We try to figure out     * whether this was an expected event based on past     * frame status values.     */    if ((scbstatus & IE_RUS_SUSPEND) != 0) {      /*       * We use the "suspend on last frame" flag.       * Send a RU RESUME command in response, since       * we should have dealt with all completed frames       * by now.       */      printf("RINT: SUSPENDED; scbstatus=0x%x\n",             scbstatus);      if (i82586_start_cmd(sc, IE_RUC_RESUME, 0, 0, 0) == 0)        return (0);      printf("%s: RU RESUME command timed out\n",             sc->arpcom.ac_if.if_name);      return (1);  /* Ask for a reset */    }    if (sc->rnr_expect != 0) {      /*       * The RNR condition was announced in the previously       * completed frame.  Assume the receive ring is Ok,       * so restart the receiver without further delay.       */      i82586_start_transceiver(sc);      sc->rnr_expect = 0;      return (0);    } else if ((scbstatus & IE_RUS_NOSPACE) != 0) {      /*       * We saw no previous IF_FD_RNR flag.       * We check our ring invariants and, if ok,       * just restart the receiver at the current       * point in the ring.       */      if (i82586_chk_rx_ring(sc) != 0)        return (1);      i82586_start_transceiver(sc);      sc->arpcom.ac_if.if_ierrors++;      return (0);    } else      printf("%s: receiver not ready; scbstatus=0x%x\n",             sc->arpcom.ac_if.if_name, scbstatus);    sc->arpcom.ac_if.if_ierrors++;    return (1);  /* Ask for a reset */  }  return (0);}/* * Process a command-complete interrupt.  These are only generated by the * transmission of frames.  This routine is deceptively simple, since most * of the real work is done by i82586_start(). */inti82586_tint(struct ie_softc *sc, int scbstatus){  struct ifnet *ifp = &sc->arpcom.ac_if;  int status;#if I82586_DEBUG  I82586_TRACE(sc, I82586_TX_INT, sc->xmit_busy);#endif#if I82586_DEBUG  if (sc->xmit_busy <= 0) {    printf("i82586_tint: (%d), WEIRD: xmit_busy=%d, xctail=%d, xchead=%d\n",           sc->trace_flow_in / 2, sc->xmit_busy, sc->xctail, sc->xchead);    I82586_TRACE(sc, I82586_TX_BAD, sc->xctail);    return (0);  }#endif  ifp->if_timer = 0;  ifp->if_flags &= ~IFF_OACTIVE;  status = sc->ie_bus_read16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds,                                                    sc->xctail));#if I82586_DEBUG  if (sc->sc_debug & IED_TINT)    printf("%s: tint: SCB status 0x%x; xmit status 0x%x\n",           sc->arpcom.ac_if.if_name, scbstatus, status);#endif  if ((status & IE_STAT_COMPL) == 0 || (status & IE_STAT_BUSY)) {    printf("i82586_tint: (%d) command still busy; status=0x%x; tail=%d\n",           sc->trace_flow_in / 2, status, sc->xctail);    printf("iestatus = 0x%x\n", scbstatus);/*    sc->sc_debug = IED_ALL; */  }  if (status & IE_STAT_OK) {    ifp->if_opackets++;    ifp->if_collisions += (status & IE_XS_MAXCOLL);  } else {    ifp->if_oerrors++;    /*     * Check SQE and DEFERRED?     * What if more than one bit is set?     */    if (status & IE_STAT_ABORT)      printf("%s: send aborted\n", sc->arpcom.ac_if.if_name);    else if (status & IE_XS_NOCARRIER)      printf("%s: no carrier\n", sc->arpcom.ac_if.if_name);    else if (status & IE_XS_LOSTCTS)      printf("%s: lost CTS\n", sc->arpcom.ac_if.if_name);    else if (status & IE_XS_UNDERRUN)      printf("%s: DMA underrun\n", sc->arpcom.ac_if.if_name);    else if (status & IE_XS_EXCMAX) {      printf("%s: too many collisions\n",             sc->arpcom.ac_if.if_name);      sc->arpcom.ac_if.if_collisions += 16;    }  }  /*   * If multicast addresses were added or deleted while transmitting,   * ie_mc_reset() set the want_mcsetup flag indicating that we   * should do it.   */  if (sc->want_mcsetup) {    ie_mc_setup(sc, IE_XBUF_ADDR(sc, sc->xctail));    sc->want_mcsetup = 0;  }  /* Done with the buffer. */  sc->xmit_busy--;  sc->xctail = (sc->xctail + 1) % NTXBUF;  /* Start the next packet, if any, transmitting. */  if (sc->xmit_busy > 0)    iexmit(sc);  i82586_start_tx(sc);  return (0);}/* * Get a range of receive buffer descriptors that represent one packet.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -