Example #1
0
static ssize_t rtl8139_read(dev_cookie cookie, void *buf, off_t pos, ssize_t len)
{
	rtl8139 *rtl = (rtl8139 *)cookie;

	if(len < ETHERNET_MAX_SIZE)
		return ERR_VFS_INSUFFICIENT_BUF;
	return rtl8139_rx(rtl, buf, len);
}
Example #2
0
static void rtl8139_dpc(void *arg) {
  struct dev *dev = (struct dev *) arg;
  struct nic *np = (struct nic *) dev->privdata;
  struct nic *tp = np;
  int boguscnt = np->max_interrupt_work;
  long ioaddr = tp->iobase;
  int link_changed = 0;

  while (1) {
    int status = inpw(ioaddr + IntrStatus);
    
    // Acknowledge all of the current interrupt sources ASAP, but
    // first get an additional status bit from CSCR
    if (status & RxUnderrun) link_changed = inpw(ioaddr + CSCR) & CSCR_LinkChangeBit;
    outpw(ioaddr + IntrStatus, status);

    //kprintf("%s: dpc status=%#4.4x new intstat=%#4.4x\n", dev->name, status, inpw(ioaddr + IntrStatus));

    if ((status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) break;

    if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) {
      // Rx interrupt
      rtl8139_rx(dev);
    }

    if (status & (TxOK | TxErr)) {
      unsigned int dirty_tx = tp->dirty_tx;
      int entries_freed = 0;

      while (tp->cur_tx - dirty_tx > 0) {
        int entry = dirty_tx % NUM_TX_DESC;
        int txstatus = inpd(ioaddr + TxStatus0 + entry * 4);

        if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) break; // It still hasn't been Txed

        // Note: TxCarrierLost is always asserted at 100mbps
        if (txstatus & (TxOutOfWindow | TxAborted)) {
          // There was an major error, log it
          kprintf("%s: Transmit error, Tx status %8.8x\n", dev->name, txstatus);
          tp->stats.tx_errors++;
          if (txstatus & TxAborted) {
            tp->stats.tx_aborted_errors++;
            outpd(ioaddr + TxConfig, TX_DMA_BURST << 8);
          }
          if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++;
          if (txstatus & TxOutOfWindow) tp->stats.tx_window_errors++;
        } else {
          //kprintf("%s: Transmit done, Tx status %8.8x\n", dev->name, txstatus);

          if (txstatus & TxUnderrun) {
            // Add 64 to the Tx FIFO threshold
            if (tp->tx_flag <  0x00300000) tp->tx_flag += 0x00020000;
            tp->stats.tx_fifo_errors++;
          }
          tp->stats.collisions += (txstatus >> 24) & 15;
          tp->stats.tx_bytes += txstatus & 0x7ff;
          tp->stats.tx_packets++;
        }

        // Free the original pbuf
        pbuf_free(tp->tx_pbuf[entry]);
        tp->tx_pbuf[entry] = NULL;
        entries_freed++;
        
        dirty_tx++;
      }

      tp->dirty_tx = dirty_tx;
      release_sem(&tp->tx_sem, entries_freed);
    }

    // Check uncommon events with one test
    if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | RxErr)) {
      if (status == 0xffff) break; // Missing chip!
      rtl_error(dev, status, link_changed);
    }

    if (--boguscnt < 0) {
      kprintf("%s: Too much work at interrupt, IntrStatus=0x%4.4x\n", dev->name, status);
      
      // Clear all interrupt sources
      outpw(ioaddr + IntrStatus, 0xffff);
      break;
    }
  }