r1000_n.c
来自「LINUX下面的RTL8169的驱动原码」· C语言 代码 · 共 2,072 行 · 第 1/4 页
C
2,072 行
else{
if (netif_queue_stopped (dev)){
netif_wake_queue (dev);
}
}
return 0;
}
//======================================================================================================
static void r1000_tx_interrupt (struct net_device *dev, struct r1000_private *priv, unsigned long ioaddr)
{
unsigned long dirty_tx, tx_left=0;
int entry = priv->cur_tx % NUM_TX_DESC;
int txloop_cnt = 0;
assert (dev != NULL);
assert (priv != NULL);
assert (ioaddr != NULL);
dirty_tx = priv->dirty_tx;
tx_left = priv->cur_tx - dirty_tx;
while( (tx_left > 0) && (txloop_cnt < max_interrupt_work) ){
if( (le32_to_cpu(priv->TxDescArray[entry].status) & OWNbit) == 0 ){
#ifdef R1000_DYNAMIC_CONTROL
r1000_callback_tx(&(priv->rt), 1, priv->Tx_skbuff[dirty_tx % NUM_TX_DESC]->len);
#endif //end #ifdef R1000_DYNAMIC_CONTROL
dev_kfree_skb_irq( priv->Tx_skbuff[dirty_tx % NUM_TX_DESC] );
priv->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
priv->stats.tx_packets++;
dirty_tx++;
tx_left--;
entry++;
}
txloop_cnt ++;
}
if (priv->dirty_tx != dirty_tx) {
priv->dirty_tx = dirty_tx;
if (netif_queue_stopped (dev))
netif_wake_queue (dev);
}
}
//======================================================================================================
static void r1000_rx_interrupt (struct net_device *dev, struct r1000_private *priv, unsigned long ioaddr)
{
struct pci_dev *pdev = priv->pci_dev;
int cur_rx;
int pkt_size = 0 ;
int rxdesc_cnt = 0;
int ret;
struct sk_buff *n_skb = NULL;
struct sk_buff *cur_skb;
struct sk_buff *rx_skb;
struct RxDesc *rxdesc;
assert (dev != NULL);
assert (priv != NULL);
assert (ioaddr != NULL);
cur_rx = priv->cur_rx;
rxdesc = &priv->RxDescArray[cur_rx];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE);
#endif
while ( ((le32_to_cpu(rxdesc->status) & OWNbit)== 0) && (rxdesc_cnt < max_interrupt_work) ){
rxdesc_cnt++;
if( le32_to_cpu(rxdesc->status) & RxRES ){
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
priv->stats.rx_errors++;
if ( le32_to_cpu(rxdesc->status) & (RxRWT|RxRUNT) )
priv->stats.rx_length_errors++;
if ( le32_to_cpu(rxdesc->status) & RxCRC)
priv->stats.rx_crc_errors++;
}
else{
pkt_size=(int)(le32_to_cpu(rxdesc->status) & 0x00001FFF)-4;
if( pkt_size > priv->rx_pkt_len ){
printk("%s: Error -- Rx packet size(%d) > mtu(%d)+14\n", dev->name, pkt_size, dev->mtu);
pkt_size = priv->rx_pkt_len;
}
DBG_PRINT("%s: RX pkt_size = %d\n", __FUNCTION__, pkt_size);
{// -----------------------------------------------------
rx_skb = priv->Rx_skbuff[cur_rx];
n_skb = R1000_ALLOC_RXSKB(MAX_RX_SKBDATA_SIZE);
if( n_skb != NULL ) {
skb_reserve (n_skb, 8); // 16 byte align the IP fields. //
// Indicate rx_skb
if( rx_skb != NULL ){
rx_skb->dev = dev;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
pci_dma_sync_single(pdev, priv->rx_skbuff_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE);
#endif
skb_put ( rx_skb, pkt_size );
rx_skb->protocol = eth_type_trans ( rx_skb, dev );
ret = R1000_NETIF_RX (rx_skb);
// dev->last_rx = jiffies;
priv->stats.rx_bytes += pkt_size;
priv->stats.rx_packets++;
#ifdef R1000_DYNAMIC_CONTROL
r1000_callback_rx( &(priv->rt), 1, pkt_size);
#endif //end #ifdef R1000_DYNAMIC_CONTROL
}//end if( rx_skb != NULL )
priv->Rx_skbuff[cur_rx] = n_skb;
}
else{
DBG_PRINT("%s: Allocate n_skb failed!\n",__FUNCTION__ );
priv->Rx_skbuff[cur_rx] = rx_skb;
}
// Update rx descriptor
if( cur_rx == (NUM_RX_DESC-1) ){
priv->RxDescArray[cur_rx].status = cpu_to_le32((OWNbit | EORbit) | (unsigned long)priv->hw_rx_pkt_len);
}
else{
priv->RxDescArray[cur_rx].status = cpu_to_le32(OWNbit | (unsigned long)priv->hw_rx_pkt_len);
}
cur_skb = priv->Rx_skbuff[cur_rx];
if( cur_skb != NULL ){
priv->rx_skbuff_dma_addr[cur_rx] = pci_map_single(pdev, cur_skb->data, MAX_RX_SKBDATA_SIZE, PCI_DMA_FROMDEVICE);
rxdesc->buf_addr = cpu_to_le32(priv->rx_skbuff_dma_addr[cur_rx]);
}
else{
DBG_PRINT("%s: %s() cur_skb == NULL\n", dev->name, __FUNCTION__);
}
}//------------------------------------------------------------
}// end of if( priv->RxDescArray[cur_rx].status & RxRES )
cur_rx = (cur_rx +1) % NUM_RX_DESC;
rxdesc = &priv->RxDescArray[cur_rx];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE);
#endif
}// end of while ( (priv->RxDescArray[cur_rx].status & 0x80000000)== 0)
if( rxdesc_cnt >= max_interrupt_work ){
DBG_PRINT("%s: Too much work at Rx interrupt.\n", dev->name);
}
priv->cur_rx = cur_rx;
}
//======================================================================================================
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
#else
static irqreturn_t r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
#endif
{
struct net_device *dev = (struct net_device *) dev_instance;
struct r1000_private *priv = dev->priv;
int boguscnt = max_interrupt_work;
unsigned long ioaddr = priv->ioaddr;
int status = 0;
// irqreturn_int interrupt_handled = IRQ_NONE;
int interrupt_handled = IRQ_NONE;
RTL_W16 ( IntrMask, 0x0000);
do {
status = RTL_R16(IntrStatus);
if (status == 0xFFFF)
break;
RTL_W16( IntrStatus, status );
if ( (status & r1000_intr_mask ) == 0 )
break;
else
interrupt_handled = IRQ_HANDLED;
// Rx interrupt
// if (status & (RxOK | RxErr /* | LinkChg | RxOverflow | RxFIFOOver*/)){
r1000_rx_interrupt (dev, priv, ioaddr);
// }
// Tx interrupt
// if (status & (TxOK | TxErr)) {
spin_lock (&priv->lock);
r1000_tx_interrupt (dev, priv, ioaddr);
spin_unlock (&priv->lock);
// }
if ((status & TxOK)&&(status & TxDescUnavail))
RTL_W8(TxPoll,0x40);
boguscnt--;
} while (boguscnt > 0);
if (boguscnt <= 0) {
DBG_PRINT("%s: Too much work at interrupt!\n", dev->name);
RTL_W16( IntrStatus, 0xffff); // Clear all interrupt sources
}
RTL_W16 ( IntrMask, r1000_intr_mask);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
return interrupt_handled;
#endif
}
//======================================================================================================
static int r1000_close (struct net_device *dev)
{
struct r1000_private *priv = dev->priv;
unsigned long ioaddr = priv->ioaddr;
int i;
// -----------------------------------------
r1000_delete_timer( &(priv->r1000_timer) );
netif_stop_queue (dev);
spin_lock_irq (&priv->lock);
/* Stop the chip's Tx and Rx processes. */
RTL_W8 ( ChipCmd, 0x00);
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16 ( IntrMask, 0x0000);
/* Update the error counts. */
priv->stats.rx_missed_errors += RTL_R32(RxMissed);
RTL_W32( RxMissed, 0);
spin_unlock_irq (&priv->lock);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
synchronize_irq ();
#else
synchronize_irq (dev->irq);
#endif
free_irq (dev->irq, dev);
r1000_tx_clear (priv);
//2004-05-11
if(priv->txdesc_space != NULL){
pci_free_consistent(
priv->pci_dev,
priv->sizeof_txdesc_space,
priv->txdesc_space,
priv->txdesc_phy_dma_addr
);
priv->txdesc_space = NULL;
}
if(priv->rxdesc_space != NULL){
pci_free_consistent(
priv->pci_dev,
priv->sizeof_rxdesc_space,
priv->rxdesc_space,
priv->rxdesc_phy_dma_addr
);
priv->rxdesc_space = NULL;
}
priv->TxDescArray = NULL;
priv->RxDescArray = NULL;
{//-----------------------------------------------------------------------------
for(i=0;i<NUM_RX_DESC;i++){
if( priv->Rx_skbuff[i] != NULL ) {
R1000_FREE_RXSKB ( priv->Rx_skbuff[i] );
}
}
}//-----------------------------------------------------------------------------
DBG_PRINT("%s: %s() alloc_rxskb_cnt = %d\n", dev->name, __FUNCTION__, alloc_rxskb_cnt );
return 0;
}
//======================================================================================================
static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc (int length, unsigned char *data)
{
int crc = -1;
while (--length >= 0) {
unsigned char current_octet = *data++;
int bit;
for (bit = 0; bit < 8; bit++, current_octet >>= 1)
crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
}
return crc;
}
//======================================================================================================
static void r1000_set_rx_mode (struct net_device *dev)
{
struct r1000_private *priv = dev->priv;
unsigned long ioaddr = priv->ioaddr;
unsigned long flags;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
u32 tmp=0;
if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next)
{
set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
}
#else
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next)
{
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
rx_mode |= AcceptMulticast;
}
#endif
}
spin_lock_irqsave (&priv->lock, flags);
tmp = r1000_rx_config | rx_mode | (RTL_R32(RxConfig) & rtl_chip_info[priv->chipset].RxConfigMask);
RTL_W32 ( RxConfig, tmp);
if((priv->mcfg==MCFG_METHOD_11)||(priv->mcfg==MCFG_METHOD_12)||
(priv->mcfg==MCFG_METHOD_13)||(priv->mcfg==MCFG_METHOD_14)||
(priv->mcfg==MCFG_METHOD_15)){
RTL_W32 ( MAR0 + 0, 0xFFFFFFFF);
RTL_W32 ( MAR0 + 4, 0xFFFFFFFF);
}else{
RTL_W32 ( MAR0 + 0, mc_filter[0]);
RTL_W32 ( MAR0 + 4, mc_filter[1]);
}
spin_unlock_irqrestore (&priv->lock, flags);
}//end of r1000_set_rx_mode (struct net_device *dev)
//================================================================================
struct net_device_stats *r1000_get_stats(struct net_device *dev)
{
struct r1000_private *priv = dev->priv;
return &priv->stats;
}
//================================================================================
static struct pci_driver r1000_pci_driver = {
name: MODULENAME,
id_table: r1000_pci_tbl,
probe: r1000_init_one,
remove: r1000_remove_one,
suspend: NULL,
resume: NULL,
};
//======================================================================================================
static int __init r1000_init_module (void)
{
return pci_module_init (&r1000_pci_driver); // pci_register_driver (drv)
}
//======================================================================================================
static void __exit r1000_cleanup_module (void)
{
pci_unregister_driver (&r1000_pci_driver);
}
#ifdef R1000_JUMBO_FRAME_SUPPORT
static int r1000_change_mtu(struct net_device *dev, int new_mtu)
{
struct r1000_private *priv = dev->priv;
unsigned long ioaddr = priv->ioaddr;
if( new_mtu > MAX_JUMBO_FRAME_MTU ){
printk("%s: Error -- new_mtu(%d) > MAX_JUMBO_FRAME_MTU(%d).\n", dev->name, new_mtu, MAX_JUMBO_FRAME_MTU);
return -1;
}
dev->mtu = new_mtu;
priv->curr_mtu_size = new_mtu;
priv->tx_pkt_len = new_mtu + ETH_HDR_LEN;
priv->rx_pkt_len = new_mtu + ETH_HDR_LEN;
priv->hw_rx_pkt_len = priv->rx_pkt_len + 8;
RTL_W8 ( Cfg9346, Cfg9346_Unlock);
RTL_W16 ( RxMaxSize, (unsigned short)priv->hw_rx_pkt_len );
RTL_W8 ( Cfg9346, Cfg9346_Lock);
DBG_PRINT("-------------------------- \n");
DBG_PRINT("dev->mtu = %d \n", dev->mtu);
DBG_PRINT("priv->curr_mtu_size = %d \n", priv->curr_mtu_size);
DBG_PRINT("priv->rx_pkt_len = %d \n", priv->rx_pkt_len);
DBG_PRINT("priv->tx_pkt_len = %d \n", priv->tx_pkt_len);
DBG_PRINT("RTL_W16( RxMaxSize, %d )\n", priv->hw_rx_pkt_len);
DBG_PRINT("-------------------------- \n");
r1000_close (dev);
r1000_open (dev);
return 0;
}
#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT
//======================================================================================================
module_init(r1000_init_module);
module_exit(r1000_cleanup_module);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?