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); }
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; } }