<dfn id="is4kg"></dfn>
  • <ul id="is4kg"></ul>
  • <abbr id="is4kg"></abbr>
  • <ul id="is4kg"></ul>
    <bdo id="is4kg"></bdo>

    曙海教育集團論壇Linux專區Linux驅動開發 → NAPI技術在Linux網絡驅動上的應用


      共有9115人關注過本帖樹形打印

    主題:NAPI技術在Linux網絡驅動上的應用

    美女呀,離線,留言給我吧!
    wangxinxin
      1樓 個性首頁 | 博客 | 信息 | 搜索 | 郵箱 | 主頁 | UC


    加好友 發短信
    等級:青蜂俠 帖子:1393 積分:14038 威望:0 精華:0 注冊:2010-11-12 11:08:23
    NAPI技術在Linux網絡驅動上的應用  發帖心情 Post By:2010-11-24 11:29:37

    這個方法通常被網絡層在向驅動的接收循環隊列獲取新的數據包時刻調用,而驅動的接收循環隊列中可以向網絡層交付的包數量則在 dev->quota 字段中表示,我們來看 8139cp 中 POLL 的原型:

      static int cp_rx_poll (struct net_device *dev, int *budget)   

      參數 budget 的上層任務所需要底層傳遞的數據包的數量,這個數值不能超過netdev_max_backlog 的值。   

      總而言之,POLL 方法被網絡層調用,只負責按照網絡層的要求值("預算"值)提交對應數量的數據包。8139CP 的 POLL 方法注冊通常在設備驅動程序模塊初始化(調用 probe)的時候進行,如下:

      static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)

      {

      … …

      dev->poll = cp_rx_poll;

      … …

      }

      

      設備的 POLL 方法正如前所說的是被網絡層上的軟中斷 net_rx_action 調用,我們現在來看具體的流程:

      

      static int cp_rx_poll (struct net_device *dev, int *budget)

      {

       struct cp_private *cp = netdev_priv(dev);

       unsigned rx_tail = cp->rx_tail;

       /*設定每次進行調度的時候從設備發送到網絡層次最大的數據包的大小*/

      unsigned rx_work = dev->quota;

       unsigned rx;

      

      rx_status_loop:

       rx = 0;

      /*重新打開NIC中斷,在 cp_interrupt 中斷句柄中中斷關閉了,現在 POLl 已經開始處理環行緩沖隊列中的數據,

      所以中斷可以打開,準備接收新的數據包*/

       cpw16(IntrStatus, cp_rx_intr_mask);  

       while (1) {/*POLL循環的開始*/

       u32 status, len;

       dma_addr_t mapping;

       struct sk_buff *skb, *new_skb;

       struct cp_desc *desc;

       unsigned buflen;

      /*從下標為rx_tail的內存中的環行緩沖隊列接收隊列rx_skb上"摘下"套接字緩沖區*/

       skb = cp->rx_skb[rx_tail].skb;

       if (!skb)

       BUG();

      

       desc = &cp->rx_ring[rx_tail];

      /*檢查在 NIC 的環形隊列(rx_ring)上的最后的數據接收狀態,是否有出現接收或者 FIFO 的錯誤,是否*/

       status = le32_to_cpu(desc->opts1);

       if (status & DescOwn)

       break;

      

       len = (status & 0x1fff) - 4;

       mapping = cp->rx_skb[rx_tail].mapping;

      

       if ((status & (FirstFrag   LastFrag)) != (FirstFrag   LastFrag)) {

       /* we don't support incoming fragmented frames.

       * instead, we attempt to ensure that the

       * pre-allocated RX skbs are properly sized such

       * that RX fragments are never encountered

       */

       cp_rx_err_acct(cp, rx_tail, status, len);

       cp->net_stats.rx_dropped++;

       cp->cp_stats.rx_frags++;

       goto rx_next;

       }

      

       if (status & (RxError   RxErrFIFO)) {

       cp_rx_err_acct(cp, rx_tail, status, len);

       goto rx_next;

       }

      

       if (netif_msg_rx_status(cp))

       printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",

       cp->dev->name, rx_tail, status, len);

      

       buflen = cp->rx_buf_sz + RX_OFFSET;

      /*創建新的套接字緩沖區*/

       new_skb = dev_alloc_skb (buflen);

       if (!new_skb) {

       cp->net_stats.rx_dropped++;

       goto rx_next;

       }

      

       skb_reserve(new_skb, RX_OFFSET);

       new_skb->dev = cp->dev;

      /*解除原先映射的環行隊列上的映射區域*/

       pci_unmap_single(cp->pdev, mapping,

       buflen, PCI_DMA_FROMDEVICE);

      /*檢查套接字緩沖區(sk_buff)上得到的數據校驗和是否正確*/

       /* Handle checksum offloading for incoming packets. */

       if (cp_rx_csum_ok(status))

       skb->ip_summed = CHECKSUM_UNNECESSARY;

       else

       skb->ip_summed = CHECKSUM_NONE;

      /*按照數據的實際大小重新定義套接字緩沖區的大小*/

       skb_put(skb, len);  

       mapping =

       cp->rx_skb[rx_tail].mapping =

      /*DMA影射在前面新創建的套接字緩沖區虛擬地址new_buf->tail到實際的物理地址上,

      并且把這個物理地址掛在接收緩沖區的隊列中*/

       pci_map_single(cp->pdev, new_skb->tail,

       buflen, PCI_DMA_FROMDEVICE);

      /*把新建立的緩沖區的虛擬地址掛在接收緩沖區的隊列中,在下一次訪問rx_skb數組的這個結構時候,

      POLL方法會從這個虛擬地址讀出接收到的數據包*/

       cp->rx_skb[rx_tail].skb = new_skb;

      /*在cp_rx_skb調用netif_rx_skb,填充接收數據包隊列,等待網絡層在Bottom half隊列中調用ip_rcv接收網絡數據,

      這個函數替代了以前使用的netif_rx*/

       cp_rx_skb(cp, skb, desc);

       rx++;  

      rx_next:

      /*把前面映射的物理地址掛在NIC設備的環行隊列上(也就是rx_ring上,它是在和NIC中物理存儲區進行了DMA映射的,

      而不是驅動在內存中動態建立的),準備提交給下層(NIC)進行數據傳輸*/

       cp->rx_ring[rx_tail].opts2 = 0;

       cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);

      /*在相應的傳輸寄存器中寫入控制字,把rx_ring的控制權從驅動程序交還給NIC硬件*/

       if (rx_tail == (CP_RX_RING_SIZE - 1))

       desc->opts1 = cpu_to_le32(DescOwn   RingEnd  

       cp->rx_buf_sz);

       else

       desc->opts1 = cpu_to_le32(DescOwn   cp->rx_buf_sz);

      /*步進到下一個接收緩沖隊列的下一個單元*/

       rx_tail = NEXT_RX(rx_tail);

      

       if (!rx_work--)

       break;  

       cp->rx_tail = rx_tail;

      /*遞減配額值quota,一旦quota遞減到0表示這次的POLL傳輸已經完成了使命,

      就等待有數據到來的時候再次喚醒軟中斷執行POLL方法*/

       dev->quota -= rx;

       *budget -= rx;  

       /* if we did not reach work limit, then we're done with

       * this round of polling

       */

       if (rx_work) {

      /*如果仍然有數據達到,那么返回POLL方法循環的開始,繼續接收數據*/

       if (cpr16(IntrStatus) & cp_rx_intr_mask)

       goto rx_status_loop;

      /*這里表示數據已經接收完畢,而且沒有新的接收中斷產生了,這個時候使能NIC的接收中斷,

      并且調用__netif_rx_complete把已經完成POLL的設備從poll_list上摘除,等待下一次中斷產生的時候,

      再次把設備掛上poll_list隊列中。*/

       local_irq_disable();

       cpw16_f(IntrMask, cp_intr_mask);

       __netif_rx_complete(dev);

       local_irq_enable();  

       return 0; /* done */

       }  

       return 1; /* not done */

      }  

      其他的使用 NAPI 的驅動程序和 8139CP 大同小異,只是使用了網絡層專門提供的 POLL 方法--proecess_backlog(/net/dev.c),在 NIC 中斷接收到了數據包后,調用網絡層上的 netif_rx(/net/dev.c)將硬件中斷中接收到數據幀存入 sk_buff 結構, 然后檢查硬件幀頭,識別幀類型, 放入接收隊列(softnet_data 結構中的 input_pkt_queue 隊列上), 激活接收軟中斷作進一步處理. 軟中斷函數(net_rx_action)提取接收包,而 process_backlog(也就是 POLL 方法)向上層提交數據。


    支持(0中立(0反對(0單帖管理 | 引用 | 回復 回到頂部

    返回版面帖子列表

    NAPI技術在Linux網絡驅動上的應用








    簽名
    主站蜘蛛池模板: 成年女人色费视频免费| 色狠狠一区二区| 幻女free性zozo交| 亚洲人成电影在线观看青青| 狠狠躁夜夜躁av网站中文字幕| 国产欧美视频在线| 一本大道香蕉大vr在线吗视频| 日本动漫h在线| 亚洲日韩欧美一区二区三区| 窝窝人体色www| 国产呦系列呦交| 91丨九色丨首页| 尹人久久久香蕉精品| 久热中文字幕在线| 欧美叉叉叉BBB网站| 女教师巨大乳孔中文字幕| 国产欧美高清在线观看| gogo免费在线观看| 日本三级片网站| 亚洲国产精品欧美日韩一区二区| 男人添女人下部全视频| 国产特级毛片AAAAAA视频| jealousvue熟睡入侵中| 成人性生话视频| 久草福利资源网站免费| 欧美亚洲桃花综合| 伊人五月天综合| 亚洲欧美小视频| 葫芦里不卖药葫芦娃app | 无码人妻丰满熟妇啪啪网站| 亚洲国产一二三| 欧美最猛黑人xxxxx猛交| 公交车上性配合享受视频| 色综合天天综合网国产成人网| 国产毛片女人18水多| 99精品国产丝袜在线拍国语| 少妇丰满爆乳被呻吟进入| 久久久久亚洲av无码去区首| 日本漫画囗工番库本全彩| 亚洲丝袜第一页| 欧美人与动欧交视频|