Chinaunix首页 | 论坛 | 博客
  • 博客访问: 265878
  • 博文数量: 52
  • 博客积分: 406
  • 博客等级: 一等列兵
  • 技术积分: 549
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-21 12:34
个人简介

......

文章分类

全部博文(52)

文章存档

2014年(1)

2013年(32)

2012年(19)

我的朋友

分类: LINUX

2013-11-24 16:55:52

II)接收
   在2.6.21.5linux内核中rtl8139网卡驱动的接收只采用NAPI(硬中断+轮询)的方式,所以在产生硬件中断后,对中断状态寄存器 进行了一系列的检查后,屏蔽接收中断,然后触法软中断进行接收,具体过程如下:

    在中断函数开始处先调用spin_lock (&tp->lock); 来进行保护,因为网卡产生的硬件中断要很快要处理完,所以这里采用了自旋锁进行保护。

点击(此处)折叠或打开

  1. /* Receive packets are processed by poll routine.
  2.      If not running start it now. */
  3.     if (status & RxAckBits){
  4.         if (netif_rx_schedule_prep(dev)) {
  5.             RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
  6.             __netif_rx_schedule (dev);
  7.         }
  8.     }


  1. static const u16 rtl8139_norx_intr_mask =
        PCIErr | PCSTimeout | RxUnderrun |
        TxErr | TxOK | RxErr ;


     从rtl8139_norx_intr_mask变量可以看到屏蔽了接收中断。

    

点击(此处)折叠或打开

  1. void __netif_rx_schedule(struct net_device *dev)
  2. {
  3.     unsigned long flags;

  4.     local_irq_save(flags);
  5.     dev_hold(dev);
  6.     list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
  7.     if (dev->quota < 0)
  8.         dev->quota += dev->weight;
  9.     else
  10.         dev->quota = dev->weight;
  11.     __raise_softirq_irqoff(NET_RX_SOFTIRQ);
  12.     local_irq_restore(flags);
  13. }
  local_irq_save的调用将把当前中断状态保存到flags中,然后禁用当前处理器上的中断发送,local_irq_restore恢复中断,并恢复之前的中断状态。 从这可以看出这段代码不能被硬件中断打断。接着增加此设备的引用计数,把接收队列头挂接到软中断调度队列的最后,并触法了软中断NET_RX_SOFTIRQ。此时打开自旋锁,中断调用函数就结束了。现在就要看看软中断NET_RX_SOFTIRQ处理函数:


    static int __init net_dev_init(void) 函数, 在系统启动的时候要进行一系列的初始化,使内核能正常工作,这个函数网络设备初始化函数。

     

点击(此处)折叠或打开

  1. if (dev_proc_init())
  2.         goto out;

  3.     if (netdev_sysfs_init())
  4.         goto out;

  5.     INIT_LIST_HEAD(&ptype_all);
  6.     for (i = 0; i < 16; i++)
  7.         INIT_LIST_HEAD(&ptype_base[i]);

  8.     for (i = 0; i < ARRAY_SIZE(dev_name_head); i++)
  9.         INIT_HLIST_HEAD(&dev_name_head[i]);

  10.     for (i = 0; i < ARRAY_SIZE(dev_index_head); i++)
  11.         INIT_HLIST_HEAD(&dev_index_head[i]);

    在/proc 和/sysfs 目录下建立网络设备的目录。 初始化了ptype_all  ptype_base[i]目录。
   

点击(此处)折叠或打开

  1. for_each_possible_cpu(i) {
  2.         struct softnet_data *queue;

  3.         queue = &per_cpu(softnet_data, i);
  4.         skb_queue_head_init(&queue->input_pkt_queue);
  5.         queue->completion_queue = NULL;
  6.         INIT_LIST_HEAD(&queue->poll_list);
  7.         set_bit(__LINK_STATE_START, &queue->backlog_dev.state);
  8.         queue->backlog_dev.weight = weight_p;
  9.         queue->backlog_dev.poll = process_backlog;
  10.         atomic_set(&queue->backlog_dev.refcnt, 1);
  11.     }

     这段代码就对软中断数据结构进行了初始化。 每个CPU都有一个字节的软中断调度队列。
     INIT_LIST_HEAD(&queue->poll_list); 在这里进行了初始化。

    open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
    open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
    完成了接收和发送软中断处理函数的注册

   

点击(此处)折叠或打开

  1. local_irq_disable();

  2.     while (!list_empty(&queue->poll_list)) {
  3.         struct net_device *dev;

  4.         if (budget <= 0 || jiffies - start_time > 1)
  5.             goto softnet_break;

  6.         local_irq_enable();

  7.         dev = list_entry(queue->poll_list.next,
  8.                  struct net_device, poll_list);
  9.         have = netpoll_poll_lock(dev);

  10.         if (dev->quota <= 0 || dev->poll(dev, &budget)) {
  11.             netpoll_poll_unlock(have);
  12.             local_irq_disable();
  13.             list_move_tail(&dev->poll_list, &queue->poll_list);
  14.             if (dev->quota < 0)
  15.                 dev->quota += dev->weight;
  16.             else
  17.                 dev->quota = dev->weight;
  18.         } else {
  19.             netpoll_poll_unlock(have);
  20.             dev_put(dev);
  21.             local_irq_disable();
  22.         }
  23.     }
  24. out:
  25. #ifdef CONFIG_NET_DMA
  26.     /*
  27.      * There may not be any more sk_buffs coming right now, so push
  28.      * any pending DMA copies to hardware
  29.      */
  30.     if (net_dma_client) {
  31.         struct dma_chan *chan;
  32.         rcu_read_lock();
  33.         list_for_each_entry_rcu(chan, &net_dma_client->channels, client_node)
  34.             dma_async_memcpy_issue_pending(chan);
  35.         rcu_read_unlock();
  36.     }
  37. #endif
  38.     local_irq_enable();
  39.     return;
     在软中断接收处理函数中先关闭所有中断,然后去查找接收队列,如果不为空的话,说明有包,则打开中断调用NAPI注册的回调函数dev->poll = rtl8139_poll进行处理。

    

点击(此处)折叠或打开

  1. static int rtl8139_poll(struct net_device *dev, int *budget)
  2. {
  3.     struct rtl8139_private *tp = netdev_priv(dev);
  4.     void __iomem *ioaddr = tp->mmio_addr;
  5.     int orig_budget = min(*budget, dev->quota);     //取配额和预算较小的那个
  6.     int done = 1;

  7.     spin_lock(&tp->rx_lock);
  8.     if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
  9.         int work_done;

  10.         work_done = rtl8139_rx(dev, tp, orig_budget);
  11.         if (likely(work_done > 0)) {
  12.             *budget -= work_done;     //预算减少
  13.             dev->quota -= work_done;   //配额减少
  14.             done = (work_done < orig_budget);
  15.         }
  16.     }

  17.     if (done) {
  18.         unsigned long flags;
  19.         // 接收完数据包(此时接收的数据包的个数小于配额),把设备队列从softnet软中断调度队列中删除掉,并打开接收硬件中断,从新开始中断过程
  20.         /*
  21.          * Order is important since data can get interrupted
  22.          * again when we think we are done.
  23.          */
  24.         local_irq_save(flags);
  25.         RTL_W16_F(IntrMask, rtl8139_intr_mask);
  26.         __netif_rx_complete(dev);
  27.         local_irq_restore(flags);
  28.     }
  29.     spin_unlock(&tp->rx_lock);

  30.     return !done;
  31. }

最终调用rtl8139_rx函数进行数据包的接收工作
   

点击(此处)折叠或打开

  1. static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
  2.          int budget)
  3. {
  4.     void __iomem *ioaddr = tp->mmio_addr;
  5.     int received = 0;
  6.     unsigned char *rx_ring = tp->rx_ring;
  7.     unsigned int cur_rx = tp->cur_rx;
  8.     unsigned int rx_size = 0;

  9.     DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
  10.          " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
  11.          RTL_R16 (RxBufAddr),
  12.          RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));

  13.     while (netif_running(dev) && received < budget
  14.      && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
  15.         u32 ring_offset = cur_rx % RX_BUF_LEN;
  16.         u32 rx_status;
  17.         unsigned int pkt_size;
  18.         struct sk_buff *skb;

  19.         rmb();

  20.         /* read size+status of next frame from DMA ring buffer */
  21.         rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
  22.         rx_size = rx_status >> 16;
  23.         pkt_size = rx_size - 4;

  24.         if (netif_msg_rx_status(tp))
  25.             printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x,"
  26.                 " cur %4.4x.\n", dev->name, rx_status,
  27.              rx_size, cur_rx);
  28. #if RTL8139_DEBUG > 2
  29.         {
  30.             int i;
  31.             DPRINTK ("%s: Frame contents ", dev->name);
  32.             for (i = 0; i < 70; i++)
  33.                 printk (" %2.2x",
  34.                     rx_ring[ring_offset + i]);
  35.             printk (".\n");
  36.         }
  37. #endif

  38.         /* Packet copy from FIFO still in progress.
  39.          * Theoretically, this should never happen
  40.          * since EarlyRx is disabled.
  41.          */
  42.         if (unlikely(rx_size == 0xfff0)) {
  43.             if (!tp->fifo_copy_timeout)
  44.                 tp->fifo_copy_timeout = jiffies + 2;
  45.             else if (time_after(jiffies, tp->fifo_copy_timeout)) {
  46.                 DPRINTK ("%s: hung FIFO. Reset.", dev->name);
  47.                 rx_size = 0;
  48.                 goto no_early_rx;
  49.             }
  50.             if (netif_msg_intr(tp)) {
  51.                 printk(KERN_DEBUG "%s: fifo copy in progress.",
  52.                  dev->name);
  53.             }
  54.             tp->xstats.early_rx++;
  55.             break;
  56.         }

  57. no_early_rx:
  58.         tp->fifo_copy_timeout = 0;

  59.         /* If Rx err or invalid rx_size/rx_status received
  60.          * (which happens if we get lost in the ring),
  61.          * Rx process gets reset, so we abort any further
  62.          * Rx processing.
  63.          */
  64.         if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
  65.              (rx_size < 8) ||
  66.              (!(rx_status & RxStatusOK)))) {
  67.             rtl8139_rx_err (rx_status, dev, tp, ioaddr);
  68.             received = -1;
  69.             goto out;
  70.         }

  71.         /* Malloc up new buffer, compatible with net-2e. */
  72.         /* Omit the four octet CRC from the length. */

  73.         skb = dev_alloc_skb (pkt_size + 2);
  74.         if (likely(skb)) {
  75.             skb->dev = dev;
  76.             skb_reserve (skb, 2);    /* 16 byte align the IP fields. */
  77. #if RX_BUF_IDX == 3
  78.             wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
  79. #else
  80.             eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
  81. #endif
  82.             skb_put (skb, pkt_size);

  83.             skb->protocol = eth_type_trans (skb, dev);

  84.             dev->last_rx = jiffies;
  85.             tp->stats.rx_bytes += pkt_size;
  86.             tp->stats.rx_packets++;

  87.             netif_receive_skb (skb);
  88.         } else {
  89.             if (net_ratelimit())
  90.                 printk (KERN_WARNING
  91.                     "%s: Memory squeeze, dropping packet.\n",
  92.                     dev->name);
  93.             tp->stats.rx_dropped++;
  94.         }
  95.         received++;

  96.         cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
  97.         RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));

  98.         rtl8139_isr_ack(tp);
  99.     }

  100.     if (unlikely(!received || rx_size == 0xfff0))
  101.         rtl8139_isr_ack(tp);

  102. #if RTL8139_DEBUG > 1
  103.     DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
  104.          " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
  105.          RTL_R16 (RxBufAddr),
  106.          RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
  107. #endif

  108.     tp->cur_rx = cur_rx;

  109.     /*
  110.      * The receive buffer should be mostly empty.
  111.      * Tell NAPI to reenable the Rx irq.
  112.      */
  113.     if (tp->fifo_copy_timeout)
  114.         received = budget;

  115. out:
  116.     return received;
  117. }
     在rtl8139_rx这个函数中我们看到了tp->rx_ring 这个虚拟地址。接收小于burget个数的数据包通过netif_recv_skb递交给上层网络


   
 
阅读(2804) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~