📄 8139too.c
字号:
/* disable magic packet scanning, which is enabled * when PM is enabled above (Config1) */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); } RTL_W32 ( CPlusTxStartAddr, virt_to_bus(tp->TxDescArray) ); //C+ mode only RTL_W32 ( CPlusRxStartAddr, virt_to_bus(tp->RxDescArray) ); //C+ mode only /* Lock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Lock); udelay (10); RTL_W32_F (RxMissed, 0); rtl8139_set_rx_mode (dev); /* no early-rx interrupts */ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16_F (IntrMask, rtl8139_intr_mask); netif_start_queue (dev); DPRINTK ("EXIT\n");}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void rtl8139CP_init_ring (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; int i; DPRINTK ("ENTER\n"); ////////////////////////////////////////////////////////////////////////////// tp->CP_cur_rx = 0; tp->CP_cur_tx = 0; tp->CP_dirty_tx = 0; memset(tp->TxDescArray, 0x0, NUM_CP_TX_DESC*sizeof(struct CPlusTxDesc)); memset(tp->RxDescArray, 0x0, NUM_CP_RX_DESC*sizeof(struct CPlusRxDesc)); for (i=0 ; i<NUM_CP_TX_DESC ; i++){ tp->Tx_skbuff[i]=NULL; } for (i=0; i <NUM_CP_RX_DESC; i++) { if(i==(NUM_CP_RX_DESC-1)) tp->RxDescArray[i].status = 0xC0000000+CP_RX_BUF_SIZE; else tp->RxDescArray[i].status = 0x80000000+CP_RX_BUF_SIZE; tp->RxBufferRing[i]= &(tp->RxBufferRings[i*CP_RX_BUF_SIZE]); tp->RxDescArray[i].buf_addr=virt_to_bus(tp->RxBufferRing[i]); } ////////////////////////////////////////////////////////////////////////////// DPRINTK ("EXIT\n");}static void rtl8139_tx_clear (struct rtl8139_private *tp){ int i; tp->cur_tx = 0; tp->dirty_tx = 0; /* Dump the unsent Tx packets. */ for (i = 0; i < NUM_TX_DESC; i++) { struct ring_info *rp = &tp->tx_info[i]; if (rp->mapping != 0) { pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); rp->mapping = 0; } if (rp->skb) { dev_kfree_skb (rp->skb); rp->skb = NULL; tp->stats.tx_dropped++; } }}static void rtl8139CP_tx_clear (struct rtl8139_private *tp){ int i; tp->CP_cur_tx=0; for (i=0 ; i<NUM_CP_TX_DESC ; i++){ if ( tp->Tx_skbuff[i]!=NULL ) { dev_kfree_skb (tp->Tx_skbuff[i]); tp->Tx_skbuff[i] = NULL; tp->stats.tx_dropped++; } }}static void rtl8139_tx_timeout (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u8 tmp8; DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd), RTL_R16 (IntrStatus), RTL_R8 (MediaStatus)); /* disable Tx ASAP, if not already */ tmp8 = RTL_R8 (ChipCmd); if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); /* Stop a shared interrupt from scavenging while we are. */ spin_lock_irq (&tp->lock); rtl8139_tx_clear (tp); spin_unlock_irq (&tp->lock); /* ...and finally, reset everything */ rtl8139_hw_start (dev); netif_wake_queue (dev);}static void rtl8139CP_tx_timeout (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u8 tmp8; printk ("%s: %s - Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, __FUNCTION__, RTL_R8 (ChipCmd), RTL_R16 (IntrStatus), RTL_R8 (MediaStatus)); /* disable Tx ASAP, if not already */ tmp8 = RTL_R8 (ChipCmd); if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); /* Stop a shared interrupt from scavenging while we are. */ spin_lock_irq (&tp->lock); rtl8139CP_tx_clear (tp); spin_unlock_irq (&tp->lock); /* ...and finally, reset everything */ rtl8139CP_hw_start (dev); netif_wake_queue (dev);}static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev){ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry; /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; assert (tp->tx_info[entry].skb == NULL); assert (tp->tx_info[entry].mapping == 0); // ---------------------------------------------- // For skb->len < 60, padding payload with 0x20. // ---------------------------------------------- if( skb->len < ETH_ZLEN ){ //if data_len < 60 if( (skb->data + ETH_ZLEN) <= skb->end ){ // if data_buf is greater than 60 bytes //printk("%s:memset( skb->data + %d, 0x20, %d )\n", __FUNCTION__, skb->len, ETH_ZLEN - skb->len); memset( skb->data + skb->len, 0x20, (ETH_ZLEN - skb->len) ); // padding data payload with 0x20 skb->len = (skb->len >= ETH_ZLEN) ? skb->len : ETH_ZLEN; // data_len = 60 } else{ printk("%s:(skb->data+ETH_ZLEN) > skb->end\n",__FUNCTION__); // data_buf is less than or equal to 60 bytes } // do nothing } tp->tx_info[entry].skb = skb; if ((long) skb->data & 3) { /* Must use alignment buffer. */ /* tp->tx_info[entry].mapping = 0; */ memcpy (tp->tx_buf[entry], skb->data, skb->len); RTL_W32 (TxAddr0 + (entry * 4), tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); } else { tp->tx_info[entry].mapping = pci_map_single (tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); RTL_W32 (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping); } /* Note: the chip doesn't have auto-pad! */ RTL_W32 (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; spin_lock_irq (&tp->lock); tp->cur_tx++; if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); spin_unlock_irq (&tp->lock); DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); return 0;}static int rtl8139CP_start_xmit (struct sk_buff *skb, struct net_device *dev){ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int CP_entry; struct ethernet_ii_header *eIIHeader; ip_v4_header *IPPacket = NULL; mb(); CP_entry = tp->CP_cur_tx % NUM_CP_TX_DESC; //C+ mode only spin_lock_irq (&tp->lock); if( (tp->TxDescArray[CP_entry].status & 0x80000000)==0 ){ tp->Tx_skbuff[CP_entry] = skb; //C+ mode only tp->TxDescArray[CP_entry].buf_addr=virt_to_bus(skb->data); //C+ mode only if( CP_entry != (NUM_CP_TX_DESC-1) ) tp->TxDescArray[CP_entry].status= 0xB0000000 |( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); else tp->TxDescArray[CP_entry].status= 0xF0000000 |( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); ////////////////////////////////////////////////////////////////////////////// if( skb->ip_summed == CHECKSUM_HW ){ eIIHeader = (struct ethernet_ii_header *) skb->data; // Check for Ethernet_II IP encapsulation // if (eIIHeader->TypeLength == IP_PROTOCOL) { // We need to point the IPPacket past the Ethernet_II header. // IPPacket = (ip_v4_header *) ((uint8_t *) eIIHeader + sizeof(struct ethernet_ii_header)); if (IPPacket->ProtocolCarried == TCP_PROTOCOL) { tp->TxDescArray[CP_entry].status |= (CPlusTxIPchecksumOffload | CPlusTxTCPchecksumOffload); } else if (IPPacket->ProtocolCarried == UDP_PROTOCOL) { tp->TxDescArray[CP_entry].status |= (CPlusTxIPchecksumOffload | CPlusTxUDPchecksumOffload); } } }//end of if( skb->ip_summed == CHECKSUM_HW ) ////////////////////////////////////////////////////////////////////////////// RTL_W8 (CPlusTxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->CP_cur_tx++; //C+ mode only if ( (tp->CP_cur_tx - NUM_CP_TX_DESC) == tp->CP_dirty_tx ) netif_stop_queue (dev); }//end of if( (tp->TxDescArray[CP_entry].status & 0x80000000)==0 ) spin_unlock_irq (&tp->lock); mb();// if ( (tp->CP_cur_tx - NUM_CP_TX_DESC) == tp->CP_dirty_tx )// netif_stop_queue (dev); return 0;}static void rtl8139_tx_interrupt (struct net_device *dev, struct rtl8139_private *tp, void *ioaddr){ unsigned long dirty_tx, tx_left; assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); dirty_tx = tp->dirty_tx; tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus; txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32))); 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. */ DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) tp->stats.tx_window_errors++;#ifdef ETHER_STATS if ((txstatus & 0x0f000000) == 0x0f000000) tp->stats.collisions16++;#endif } else { 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 skb. */ if (tp->tx_info[entry].mapping != 0) { pci_unmap_single(tp->pci_dev, tp->tx_info[entry].mapping, tp->tx_info[entry].skb->len, PCI_DMA_TODEVICE); tp->tx_info[entry].mapping = 0; } dev_kfree_skb_irq (tp->tx_info[entry].skb); tp->tx_info[entry].skb = NULL; dirty_tx++; tx_left--; }#ifndef RTL8139_NDEBUG if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; }#endif /* RTL8139_NDEBUG */ /* only wake the queue if we did work, and the queue is stopped */ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; if (netif_queue_stopped (dev)) netif_wake_queue (dev); }}/* TODO: clean this up! Rx reset need not be this intensive */static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, struct rtl8139_private *tp, void *ioaddr){ u8 tmp8; int tmp_work = 1000; DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", dev->name, rx_status); if (rx_status & RxTooLong) { DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", dev->name, rx_status); /* A.C.: The chip hangs here. */ } tp->stats.rx_errors++; if (rx_status & (RxBadSymbol | RxBadAlign)) tp->stats.rx_frame_errors++; if (rx_status & (RxRunt | RxTooLong)) tp->stats.rx_length_errors++; if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; /* Reset the receiver, based on RealTek recommendation. (Bug?) */ tp->cur_rx = 0; /* disable receive */ tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear; RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb); /* A.C.: Reset the multicast list. */ rtl8139_set_rx_mode (dev); /* XXX potentially temporary hack to * restart hung receiver */ while (--tmp_work > 0) { tmp8 = RTL_R8 (ChipCmd); if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) break; RTL_W8_F (ChipCmd, (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb); } /* G.S.: Re-enable receiver */ /* XXX temporary hack to work around receiver hang */ rtl8139_set_rx_mode (dev); if (tmp_work <= 0) printk (KERN_WARNING PFX "tx/rx enable wait too long\n");}/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the field alignments and semantics. */static void rtl8139_rx_interrupt (struct net_device *dev, struct rtl8139_private *tp, void *ioaddr){ unsigned char *rx_ring; u16 cur_rx; assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); rx_ring = tp->rx_ring; cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int rx_size; unsigned int pkt_size; struct sk_buff *skb; /* read size+status of next frame from DMA ring buffer */ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); rx_size = rx_status >> 16; pkt_size = rx_size - 4; DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx);#if RTL8139_DEBUG > 2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -