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

    曙海教育集團(tuán)論壇Linux專(zhuān)區(qū)Linux驅(qū)動(dòng)開(kāi)發(fā) → NAPI技術(shù)在Linux網(wǎng)絡(luò)驅(qū)動(dòng)上的應(yīng)用


      共有9114人關(guān)注過(guò)本帖樹(shù)形打印

    主題:NAPI技術(shù)在Linux網(wǎng)絡(luò)驅(qū)動(dòng)上的應(yīng)用

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


    加好友 發(fā)短信
    等級(jí):青蜂俠 帖子:1393 積分:14038 威望:0 精華:0 注冊(cè):2010-11-12 11:08:23
    NAPI技術(shù)在Linux網(wǎng)絡(luò)驅(qū)動(dòng)上的應(yīng)用  發(fā)帖心情 Post By:2010-11-24 11:29:37

    這個(gè)方法通常被網(wǎng)絡(luò)層在向驅(qū)動(dòng)的接收循環(huán)隊(duì)列獲取新的數(shù)據(jù)包時(shí)刻調(diào)用,而驅(qū)動(dòng)的接收循環(huán)隊(duì)列中可以向網(wǎng)絡(luò)層交付的包數(shù)量則在 dev->quota 字段中表示,我們來(lái)看 8139cp 中 POLL 的原型:

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

      參數(shù) budget 的上層任務(wù)所需要底層傳遞的數(shù)據(jù)包的數(shù)量,這個(gè)數(shù)值不能超過(guò)netdev_max_backlog 的值。   

      總而言之,POLL 方法被網(wǎng)絡(luò)層調(diào)用,只負(fù)責(zé)按照網(wǎng)絡(luò)層的要求值("預(yù)算"值)提交對(duì)應(yīng)數(shù)量的數(shù)據(jù)包。8139CP 的 POLL 方法注冊(cè)通常在設(shè)備驅(qū)動(dòng)程序模塊初始化(調(diào)用 probe)的時(shí)候進(jìn)行,如下:

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

      {

      … …

      dev->poll = cp_rx_poll;

      … …

      }

      

      設(shè)備的 POLL 方法正如前所說(shuō)的是被網(wǎng)絡(luò)層上的軟中斷 net_rx_action 調(diào)用,我們現(xiàn)在來(lái)看具體的流程:

      

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

      {

       struct cp_private *cp = netdev_priv(dev);

       unsigned rx_tail = cp->rx_tail;

       /*設(shè)定每次進(jìn)行調(diào)度的時(shí)候從設(shè)備發(fā)送到網(wǎng)絡(luò)層次最大的數(shù)據(jù)包的大小*/

      unsigned rx_work = dev->quota;

       unsigned rx;

      

      rx_status_loop:

       rx = 0;

      /*重新打開(kāi)NIC中斷,在 cp_interrupt 中斷句柄中中斷關(guān)閉了,現(xiàn)在 POLl 已經(jīng)開(kāi)始處理環(huán)行緩沖隊(duì)列中的數(shù)據(jù),

      所以中斷可以打開(kāi),準(zhǔn)備接收新的數(shù)據(jù)包*/

       cpw16(IntrStatus, cp_rx_intr_mask);  

       while (1) {/*POLL循環(huán)的開(kāi)始*/

       u32 status, len;

       dma_addr_t mapping;

       struct sk_buff *skb, *new_skb;

       struct cp_desc *desc;

       unsigned buflen;

      /*從下標(biāo)為rx_tail的內(nèi)存中的環(huán)行緩沖隊(duì)列接收隊(duì)列rx_skb上"摘下"套接字緩沖區(qū)*/

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

       if (!skb)

       BUG();

      

       desc = &cp->rx_ring[rx_tail];

      /*檢查在 NIC 的環(huán)形隊(duì)列(rx_ring)上的最后的數(shù)據(jù)接收狀態(tài),是否有出現(xiàn)接收或者 FIFO 的錯(cuò)誤,是否*/

       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;

      /*創(chuàng)建新的套接字緩沖區(qū)*/

       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;

      /*解除原先映射的環(huán)行隊(duì)列上的映射區(qū)域*/

       pci_unmap_single(cp->pdev, mapping,

       buflen, PCI_DMA_FROMDEVICE);

      /*檢查套接字緩沖區(qū)(sk_buff)上得到的數(shù)據(jù)校驗(yàn)和是否正確*/

       /* Handle checksum offloading for incoming packets. */

       if (cp_rx_csum_ok(status))

       skb->ip_summed = CHECKSUM_UNNECESSARY;

       else

       skb->ip_summed = CHECKSUM_NONE;

      /*按照數(shù)據(jù)的實(shí)際大小重新定義套接字緩沖區(qū)的大小*/

       skb_put(skb, len);  

       mapping =

       cp->rx_skb[rx_tail].mapping =

      /*DMA影射在前面新創(chuàng)建的套接字緩沖區(qū)虛擬地址new_buf->tail到實(shí)際的物理地址上,

      并且把這個(gè)物理地址掛在接收緩沖區(qū)的隊(duì)列中*/

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

       buflen, PCI_DMA_FROMDEVICE);

      /*把新建立的緩沖區(qū)的虛擬地址掛在接收緩沖區(qū)的隊(duì)列中,在下一次訪問(wèn)rx_skb數(shù)組的這個(gè)結(jié)構(gòu)時(shí)候,

      POLL方法會(huì)從這個(gè)虛擬地址讀出接收到的數(shù)據(jù)包*/

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

      /*在cp_rx_skb調(diào)用netif_rx_skb,填充接收數(shù)據(jù)包隊(duì)列,等待網(wǎng)絡(luò)層在Bottom half隊(duì)列中調(diào)用ip_rcv接收網(wǎng)絡(luò)數(shù)據(jù),

      這個(gè)函數(shù)替代了以前使用的netif_rx*/

       cp_rx_skb(cp, skb, desc);

       rx++;  

      rx_next:

      /*把前面映射的物理地址掛在NIC設(shè)備的環(huán)行隊(duì)列上(也就是rx_ring上,它是在和NIC中物理存儲(chǔ)區(qū)進(jìn)行了DMA映射的,

      而不是驅(qū)動(dòng)在內(nèi)存中動(dòng)態(tài)建立的),準(zhǔn)備提交給下層(NIC)進(jìn)行數(shù)據(jù)傳輸*/

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

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

      /*在相應(yīng)的傳輸寄存器中寫(xiě)入控制字,把rx_ring的控制權(quán)從驅(qū)動(dòng)程序交還給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);

      /*步進(jìn)到下一個(gè)接收緩沖隊(duì)列的下一個(gè)單元*/

       rx_tail = NEXT_RX(rx_tail);

      

       if (!rx_work--)

       break;  

       cp->rx_tail = rx_tail;

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

      就等待有數(shù)據(jù)到來(lái)的時(shí)候再次喚醒軟中斷執(zhí)行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) {

      /*如果仍然有數(shù)據(jù)達(dá)到,那么返回POLL方法循環(huán)的開(kāi)始,繼續(xù)接收數(shù)據(jù)*/

       if (cpr16(IntrStatus) & cp_rx_intr_mask)

       goto rx_status_loop;

      /*這里表示數(shù)據(jù)已經(jīng)接收完畢,而且沒(méi)有新的接收中斷產(chǎn)生了,這個(gè)時(shí)候使能NIC的接收中斷,

      并且調(diào)用__netif_rx_complete把已經(jīng)完成POLL的設(shè)備從poll_list上摘除,等待下一次中斷產(chǎn)生的時(shí)候,

      再次把設(shè)備掛上poll_list隊(duì)列中。*/

       local_irq_disable();

       cpw16_f(IntrMask, cp_intr_mask);

       __netif_rx_complete(dev);

       local_irq_enable();  

       return 0; /* done */

       }  

       return 1; /* not done */

      }  

      其他的使用 NAPI 的驅(qū)動(dòng)程序和 8139CP 大同小異,只是使用了網(wǎng)絡(luò)層專(zhuān)門(mén)提供的 POLL 方法--proecess_backlog(/net/dev.c),在 NIC 中斷接收到了數(shù)據(jù)包后,調(diào)用網(wǎng)絡(luò)層上的 netif_rx(/net/dev.c)將硬件中斷中接收到數(shù)據(jù)幀存入 sk_buff 結(jié)構(gòu), 然后檢查硬件幀頭,識(shí)別幀類(lèi)型, 放入接收隊(duì)列(softnet_data 結(jié)構(gòu)中的 input_pkt_queue 隊(duì)列上), 激活接收軟中斷作進(jìn)一步處理. 軟中斷函數(shù)(net_rx_action)提取接收包,而 process_backlog(也就是 POLL 方法)向上層提交數(shù)據(jù)。


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

    返回版面帖子列表

    NAPI技術(shù)在Linux網(wǎng)絡(luò)驅(qū)動(dòng)上的應(yīng)用








    簽名
    主站蜘蛛池模板: 欧美理论电影在线| 92国产福利久久青青草原| 日韩欧美亚洲每的更新在线| 免费a级黄色毛片| 色偷偷亚洲综合网亚洲| 国产精品综合一区二区三区| 中文天堂最新版www官网在线| 日韩午夜在线视频不卡片| 亚洲综合精品第一页| 精品国产一区二区三区色欲| 国产无套露脸大学生视频| 99精品热视频| 好男人电影直播在线观看| 久久精品免费一区二区三区 | 久久精品久噜噜噜久久| 欧美人与动性行为另类| 免费久久人人爽人人爽av| 美国十次啦大导航| 国产成人精品三级在线| 99RE66在线观看精品免费| 好爽好紧好多水| 久久人爽人人爽人人片av| 暖暖直播在线观看| 亚洲精品国产高清不卡在线| 目中无人在线观看免费高清完整电影 | 天天色天天操天天| 久久久www成人免费精品| 日韩a在线观看| 亚洲国产91在线| 欧美日韩视频在线观看高清免费网站 | 亚洲免费在线视频| 欧美牲交a欧美牲交aⅴ图片| 免费黄色大片网站| 精品成人一区二区三区四区| 国产免费一期二期三期四期| 黄瓜视频免费看| 国产精品无码一区二区在线| av电影在线播放| 天天夜碰日日摸日日澡| 中国黄色一级大片| 成人爽a毛片在线视频网站|