Linux内核--网络栈实现分析(十一)--驱动程序层(下)

本文分析基于Linux Kernel 1.2.13

转载作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870

更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。


在博文Linux内核--网络栈实现分析(三)--驱动程序层(链路层)(上)中对网络设备结构,网络设备初始化等函数有了初步认识,并列出了设备的发送和接收函数。

设备接口层会调用函数设备驱动层ei_start_xmit()函数发送数据,这里没有详细分析。

  1. static int ei_start_xmit(struct sk_buff *skb, struct device *dev)  
  2. {  
  3.     int e8390_base = dev->base_addr;  
  4.     struct ei_device *ei_local = (struct ei_device *) dev->priv;//取出网卡设备的私有数据,和具体的网卡型号有关,在ethdev_init()函数中已经分配空间  
  5.     int length, send_length;  
  6.     unsigned long flags;  
  7.       
  8. /* 
  9.  *  We normally shouldn't be called if dev->tbusy is set, but the 
  10.  *  existing code does anyway. If it has been too long since the 
  11.  *  last Tx, we assume the board has died and kick it. 
  12.  */  
  13.    
  14.     if (dev->tbusy) {    /* Do timeouts, just like the 8003 driver. */  
  15.         ........................................  
  16.         ........................................  
  17.     }  
  18.       
  19.     /* Sending a NULL skb means some higher layer thinks we've missed an 
  20.        tx-done interrupt. Caution: dev_tint() handles the cli()/sti() 
  21.        itself. */  
  22.     if (skb == NULL) {//该条件似乎不会发生,这用于处理内核中的BUG  
  23.         dev_tint(dev);//发送设备中的所有缓存的数据包  
  24.         return 0;  
  25.     }  
  26.       
  27.     length = skb->len;  
  28.     if (skb->len <= 0)  
  29.         return 0;  
  30.   
  31.     save_flags(flags);  
  32.     cli();  
  33.   
  34.     /* Block a timer-based transmit from overlapping. */  
  35.     if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {  
  36.     printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",  
  37.         dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,  
  38.         ei_local->tx2, ei_local->lasttx);  
  39.     restore_flags(flags);  
  40.     return 1;  
  41.     }  
  42.   
  43.     /* Mask interrupts from the ethercard. */  
  44.     outb(0x00, e8390_base + EN0_IMR);  
  45.     ei_local->irqlock = 1;  
  46.     restore_flags(flags);  
  47.   
  48.     send_length = ETH_ZLEN < length ? length : ETH_ZLEN;  
  49.   
  50.     if (ei_local->pingpong) {  
  51.         int output_page;  
  52.         if (ei_local->tx1 == 0) {  
  53.             output_page = ei_local->tx_start_page;  
  54.             ei_local->tx1 = send_length;  
  55.             if (ei_debug  &&  ei_local->tx2 > 0)  
  56.                 printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",  
  57.                        dev->name, ei_local->tx2, ei_local->lasttx,  
  58.                        ei_local->txing);  
  59.         } else if (ei_local->tx2 == 0) {  
  60.             output_page = ei_local->tx_start_page + 6;  
  61.             ei_local->tx2 = send_length;  
  62.             if (ei_debug  &&  ei_local->tx1 > 0)  
  63.                 printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",  
  64.                        dev->name, ei_local->tx1, ei_local->lasttx,  
  65.                        ei_local->txing);  
  66.         } else {    /* We should never get here. */  
  67.             if (ei_debug)  
  68.                 printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",  
  69.                     dev->name, dev->interrupt, ei_local->tx1,   
  70.                     ei_local->tx2, ei_local->lasttx);  
  71.             ei_local->irqlock = 0;  
  72.             dev->tbusy = 1;  
  73.             outb_p(ENISR_ALL, e8390_base + EN0_IMR);  
  74.             return 1;  
  75.         }  
  76.         ei_block_output(dev, length, skb->data, output_page);  
  77.         if (! ei_local->txing) {  
  78.             ei_local->txing = 1;  
  79.             NS8390_trigger_send(dev, send_length, output_page);  
  80.             dev->trans_start = jiffies;  
  81.             if (output_page == ei_local->tx_start_page)  
  82.                 ei_local->tx1 = -1, ei_local->lasttx = -1;  
  83.             else  
  84.                 ei_local->tx2 = -1, ei_local->lasttx = -2;  
  85.         } else  
  86.             ei_local->txqueue++;  
  87.   
  88.         dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);  
  89.     } else {  /* No pingpong, just a single Tx buffer. */  
  90.         ei_block_output(dev, length, skb->data, ei_local->tx_start_page);  
  91.         ei_local->txing = 1;  
  92.         NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);  
  93.         dev->trans_start = jiffies;  
  94.         dev->tbusy = 1;  
  95.     }  
  96.       
  97.     /* Turn 8390 interrupts back on. */  
  98.     ei_local->irqlock = 0;  
  99.     outb_p(ENISR_ALL, e8390_base + EN0_IMR);  
  100.   
  101.     dev_kfree_skb (skb, FREE_WRITE);  
  102.       
  103.     return 0;  

其中的dev_tint()函数是将设备的所有缓存队列中的数据全部调用dev_queue_xmit()发送全部数据包。

  1. /* 
  2.  *  This routine is called when an device driver (i.e. an 
  3.  *  interface) is ready to transmit a packet. 
  4.  */  
  5. //该函数功能:遍历设备的缓冲队列,对所有的数据包调用dev_queue_xmit()函数发送数据  
  6. void dev_tint(struct device *dev)  
  7. {  
  8.     int i;  
  9.     struct sk_buff *skb;  
  10.     unsigned long flags;  
  11.       
  12.     save_flags(flags);    
  13.     /* 
  14.      *  Work the queues in priority order 
  15.      */  
  16.        
  17.     for(i = 0;i < DEV_NUMBUFFS; i++)   
  18.     {  
  19.         /* 
  20.          *  Pull packets from the queue 
  21.          */  
  22.            
  23.   
  24.         cli();  
  25.         while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)  
  26.         {  
  27.             /* 
  28.              *  Stop anyone freeing the buffer while we retransmit it 
  29.              */  
  30.             skb_device_lock(skb);  
  31.             restore_flags(flags);  
  32.             /* 
  33.              *  Feed them to the output stage and if it fails 
  34.              *  indicate they re-queue at the front. 
  35.              */  
  36.             dev_queue_xmit(skb,dev,-i - 1);//注意优先级的计算方式,在函数dev_queue_xmit()中优先级若<0则计算pri=-pri-1=-(-i-1)-1=i,  
  37.                                //这样做的目的就是为了得到正确的where值,函数(dev_queue_xmit())中  
  38.             /* 
  39.              *  If we can take no more then stop here. 
  40.              */  
  41.             if (dev->tbusy)  
  42.                 return;  
  43.             cli();  
  44.         }  
  45.     }  
  46.     restore_flags(flags);  
  47. }  

驱动层严格的说不属于内核网络栈的内容,和硬件关系密切,何况这种网卡硬件设备可能已经不用了,这里就没有详细分析,如果对网卡驱动有兴趣可以看一下之前的分析的ARM-Linux下的DM9000网卡驱动的分析,链接如下:

  1. ARM-Linux驱动--DM9000网卡驱动分析(一)
  2. ARM-Linux驱动--DM9000网卡驱动分析(二)
  3. ARM-Linux驱动--DM9000网卡驱动分析(三)
  4. ARM-Linux驱动--DM9000网卡驱动分析(四)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值