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

📄 if_8139.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
  rltk8139_info = (Rltk8139_t *)(sc->driver_private);#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_send(%s, %08x, %d, %d, %08lx)\n",              sc->dev_name, sg_list, sg_len, total_len, key);#endif  CYG_ASSERT(total_len <= TX_BUF_SIZE, "packet too long");  /*   * Get the next free descriptor to send. We lock out all interrupts   * and scheduling because we really, really do not want to be interrupted   * at this point.   *   * IMPORTANT NOTE: the RealTek data sheet does not really make this clear,   * but when they talk about a 'ring' of transmit descriptors, they   * _really_ mean it, i.e. you _must_ use descriptor #1 after descriptor   * #0 even if transmission of descriptor #0 has already completed.   */  cyg_drv_isr_lock();  /*   * Sanity check to see if '_send' was called even though there is no free   * descriptor. This is probably unnecessary.   */  if (rltk8139_info->tx_num_free_desc == 0) {      cyg_drv_isr_unlock();#ifdef DEBUG_RLTK8139_DRIVER    diag_printf("rltk8139_send(%s): no free descriptor available\n",                sc->dev_name);#endif    return;  }  /*   * Get the free descriptor and advance the descriptor counter modulo   * TX_NUM_DESC. We assume that TX_NUM_DESC will always be a power of 2.   */  desc = rltk8139_info->tx_free_desc;  rltk8139_info->tx_free_desc = (rltk8139_info->tx_free_desc + 1)    & (NUM_TX_DESC - 1);  /* Decrement the number of free descriptors */  rltk8139_info->tx_num_free_desc -= 1;  /* Reenable interrupts at this point */  cyg_drv_isr_unlock();  /*   * Determine the buffer memory to use and tell the hardware about it.   * Since we use fixed buffer addresses, we do not need to set up TSADx.   * Memorize the key so we can call the tx_done callback correctly.   *   * While it would be possible to set TSADx to the packet directly if   * it is stored in a linear memory area with 32 bit alignment, it seems   * this happens so seldomly that it's simply not worth the extra   * runtime check.   */  tx_buffer = CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer                                      + TX_BUF_SIZE * desc);  rltk8139_info->tx_desc_key[desc] = key;  /*   * Copy the data to the designated position. Note that unlike the eCos   * Intel 82559 driver, we simply assume that all the scatter/gather list   * elements' lengths will add up to total_len exactly, and don't check   * to make sure.   */  for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {    memcpy(tx_buffer, (void *)(sg_list->buf), sg_list->len);    tx_buffer += sg_list->len;  }  /*   * Make sure the packet has the minimum ethernet packet size, padding   * with zeros if necessary.   */  if (total_len < MIN_ETH_FRAME_SIZE) {    memset(tx_buffer, 0, MIN_ETH_FRAME_SIZE - total_len);    total_len = MIN_ETH_FRAME_SIZE;  }  /*   * Flush the data cache here if necessary. This ensures the 8139 can   * read the correct data from the transmit buffer.   */#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY  HAL_DCACHE_FLUSH(rltk8139_info->tx_buffer + TX_BUF_SIZE * desc, total_len);#endif  /*   * Now setup the correct transmit descriptor to actually send the data.   * The early TX threshold is incremented by the driver until we reach a   * size that prevents transmit underruns. (An earlier attempt to calculate   * this parameter from the packet size didn't work).   */  OUTL((rltk8139_info->tx_threshold << ERTXTH_SHIFT) | (total_len & SIZE),       rltk8139_info->base_address + TSD0 + (desc<<2));}/* * This routine actually retrieves data from the receive ring by * copying it into the specified scatter/gather buffers. Again, * we assume the scatter/gather list is OK and don't check against * total length. */static voidrltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,              int sg_len){  Rltk8139_t *rltk8139_info;  struct eth_drv_sg *last_sg;  cyg_uint8 *rx_buffer;  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  rx_buffer = rltk8139_info->rx_current;  /*   * Invalidate the cache line(s) mapped to the receive buffer   * if necessary.   */#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY  HAL_DCACHE_INVALIDATE(rx_buffer, rltk8139_info->rx_size);#endif  for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {    memcpy((void *)(sg_list->buf), rx_buffer, sg_list->len);    rx_buffer += sg_list->len;  }}/* * This function does all the heavy lifting associated with interrupts. */static voidrltk8139_deliver(struct eth_drv_sc *sc){  Rltk8139_t *rltk8139_info;  cyg_uint16 status, pci_status;  cyg_uint32 tsd;  int desc;  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  /*   * The RealTek data sheet claims that reading the ISR will clear   * it. This is incorrect; to clear a bit in the ISR, a '1' must be   * written to the ISR instead. We immediately clear the interrupt   * bits at this point.   */  status = INW(rltk8139_info->base_address + ISR);  OUTW(status, rltk8139_info->base_address + ISR);#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_deliver(%s): %04x\n", sc->dev_name, status);#endif  /*   * Check for a PCI error. This seems like a very serious error to   * me, so we will reset the chip and hope for the best.   */  if (status & IR_SERR) {    cyg_pci_read_config_uint16(rltk8139_info->pci_device_id,                               CYG_PCI_CFG_STATUS, &pci_status);    cyg_pci_write_config_uint16(rltk8139_info->pci_device_id,                                CYG_PCI_CFG_STATUS, pci_status);#ifdef DEBUG_RLTK8139_DRIVER    diag_printf("rltk8139_deliver(%s): PCI error %04x\n",                sc->dev_name, pci_status);#endif    rltk8139_reset(sc);    return;  }  /* Check for transmission complete (with errors or not) */  if ((status & IR_TER) || (status & IR_TOK)) {    /*     * Figure out which descriptors' status must be checked. We lock out     * interrupts while manipulating the descriptor list because we do not     * want to be interrupted at this point.     */    while (1) {      cyg_drv_isr_lock();      /* Check if all descriptors are ready, in which case we are done. */      if (rltk8139_info->tx_num_free_desc >= NUM_TX_DESC) {          cyg_drv_isr_unlock();        break;      }      desc = (rltk8139_info->tx_free_desc              - (NUM_TX_DESC - rltk8139_info->tx_num_free_desc))        & (NUM_TX_DESC - 1);      cyg_drv_isr_unlock();      /* Get the current status of the descriptor */      tsd = INL(rltk8139_info->base_address + TSD0 + (desc<<2));      /*       * If a transmit FIFO underrun occurred, increment the threshold       * value.       */      if ((tsd & TUN) && (rltk8139_info->tx_threshold < 64))        rltk8139_info->tx_threshold += 1;      /*       * Check if a transmission completed OK. RealTek's data sheet implies       * that a successful transmission that experiences underrun will only       * set TUN. This is not true; TOK is set for all successful       * transmissions.       */      if (tsd & TOK) {        (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], 0);      }      else if (tsd & TABT) {        /*         * Set the CLRABT bit in TCR. Since I haven't encountered any         * transmission aborts so far, I don't really know if this code         * will work or not.         */        OUTL(INL(rltk8139_info->base_address + TCR) & CLRABT,             rltk8139_info->base_address + TCR);        (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], -1);      }      else {        /*         * This descriptor is not ready. Since the descriptors are used         * in a ring, this means that no more descriptors are ready.         */        break;      }      /*       * Clear the saved key value. This is not really necessary, since       * the key value is never used to determine if a descriptor is       * valid or not. However, clearing it is a tidier IMO.       */      rltk8139_info->tx_desc_key[desc] = 0;      /*       * Increment the free descriptor count and go through the loop again       * to see if more descriptors are ready.       */      cyg_drv_isr_lock();      rltk8139_info->tx_num_free_desc += 1;      cyg_drv_isr_unlock();    }  }  if (status & IR_ROK) {    /*     * Received a frame. Note that '_deliver' does not actually copy any     * data; it just determines how many bytes are available and tells     * the generic ethernet driver about it, which then calls into     * the '_recv' function to copy the data.     */    cyg_uint16 rx_pos;    cyg_uint32 header, length;    /*     * CAPR contains the index into the receive buffer. It is controlled     * completely in software. For some reason, CAPR points 16 bytes     * before the actual start of the packet.     */    rx_pos = (INW(rltk8139_info->base_address + CAPR) + 16) % RX_BUF_LEN;    /*     * Loop until the rx buffer is empty. I have no idea how the 8139     * determines if the buffer still contains a packet; it may check     * that CAPR points 16 bytes before CBR.     */    while (!(INB(rltk8139_info->base_address + CR) & BUFE)) {      /*       * Invalidate the data cache for the cache line containing the header       * if necessary.       */#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY      HAL_DCACHE_INVALIDATE(&rltk8139_info->rx_ring[rx_pos],                            sizeof(cyg_uint32));#endif      /*       * The 8139 prepends each packet with a 32 bit packet header that       * contains a 16 bit length and 16 bit status field, in little-endian       * byte order.       */      header = HAL_LE32TOC(*((volatile cyg_uint32 *)CYGARC_UNCACHED_ADDRESS(&rltk8139_info->rx_ring[rx_pos])));      /*       * If the 8139 is still copying data for this packet into the       * receive ring, it will set packet length to 0xfff0. This shouldn't       * ever happen because we do not use early receive.       */      if ((header >> 16) == 0xFFF0)        break;      /*       * Since the 8139 appends the ethernet CRC to every packet, we       * must subtract 4 from the length to get the true packet length.       */      length = (header >> 16) - 4;      /*       * Check if the packet was received correctly. The OpenBSD driver       * resets the chip if this is not the case; we attempt to salvage       * following packets by doing nothing.       */      if (!(header & HDR_ROK)) {      }      else {        /*         * Packet was received OK. Determine from where to start copying         * bytes. This is saved in the driver private area so rlt8139_recv         * doesn't have to redetermine this information. Then, inform         * the generic ethernet driver about the packet.         */        rltk8139_info->rx_current = CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring + rx_pos + 4);        rltk8139_info->rx_size = length;        /* Tell eCos about the packet */        (sc->funs->eth_drv->recv)(sc, length);      }      /*       * Update CAPR. CAPR must be aligned to a 32 bit boundary, and should       * point 16 bytes before it's actual position.       */      rx_pos = ((rx_pos + length + 8 + 3) & ~3) % RX_BUF_LEN;      OUTW((rx_pos - 16) % RX_BUF_LEN, rltk8139_info->base_address + CAPR);    }  }  if (status & IR_RXOVW) {    /*     * In case of a receive buffer overflow, the RealTek data sheet claims we     * should update CAPR and then write a '1'爐o ROK in ISR. However, none of     * the other 8139 drivers I have looked at do this, so we will just reset     * the chip instead.     */#ifdef DEBUG_RLTK8139_DRIVER    diag_printf("rltk8139_deliver(%s): receive buffer overflow\n",                sc->dev_name);#endif    rltk8139_reset(sc);    return;  }  if (status & IR_FOVW) {    /*     * Rx FIFO overflow. According to RealTek's data sheet, this is cleared     * by writing a '1' to RXOVW. Again, none of the 8139 drivers I have     * seen actually do this, so we reset the chip instead.     */#ifdef DEBUG_RLTK8139_DRIVER    diag_printf("rltk8139_deliver(%s): receive FIFO overflow\n",                sc->dev_name);#endif    rltk8139_reset(sc);    return;  }#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE  /* Finally, reenable interrupts */#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139  OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);#else  cyg_interrupt_unmask(rltk8139_info->vector);#endif#endif}/* * '_poll' does the same thing as '_deliver'. It is called periodically when * the ethernet driver is operated in non-interrupt mode, for instance by * RedBoot. */static voidrltk8139_poll(struct eth_drv_sc *sc){  Rltk8139_t *rltk8139_info;  cyg_uint16 isr;#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_poll(%s)\n", sc->dev_name);#endif  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  /*   * Get the current interrupt status. If anything changed, call   * _deliver.   */  if ((isr = INW(rltk8139_info->base_address + ISR)))    rltk8139_deliver(sc);}/* * Return the interrupt vector used by this device. */static intrltk8139_int_vector(struct eth_drv_sc *sc){  return ((Rltk8139_t *)(sc->driver_private))->vector;}/* * Quick and dirty register dump. This is somewhat dangerous, since * we read the register space 32 bits at a time, regardless of actual * register sizes. */#ifdef DEBUG_RLTK8139_DRIVERvoidrltk8139_print_state(struct eth_drv_sc *sc) {  int i;  Rltk8139_t *rltk8139_info;  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  for (i = IDR0; i < FFER; i += 16) {    diag_printf("8139 reg address 0x%02x = 0x%08x", i,                INL(rltk8139_info->base_address + i));    diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 4));    diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 8));    diag_printf(" 0x%08x\n", INL(rltk8139_info->base_address + i + 12));  }}#endif

⌨️ 快捷键说明

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