乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux內(nèi)核分析 - 網(wǎng)絡(luò)[二]:網(wǎng)卡驅(qū)動(dòng)接收?qǐng)?bào)文

       杰的個(gè)人圖書(shū)館 2012-04-11

      糾結(jié)了好多天,終于弄懂了B440X的處理。

      上篇講到通過(guò)中斷,最終網(wǎng)卡調(diào)用了b44_rx()來(lái)接收?qǐng)?bào)文

       

      對(duì)這個(gè)函數(shù)中的一些參數(shù),可以這樣理解:

      bp->rx_cons – 處理器處理到的緩沖區(qū)號(hào)

      bp->rx_pending – 分配的緩沖區(qū)個(gè)數(shù)

      bp->rx_prod – 當(dāng)前緩沖區(qū)的最后一個(gè)緩沖號(hào)

       

      這里要參數(shù)B440X的手冊(cè)了解下寄存器的作用:

      #define B44_DMARX_ADDR        0x0214UL /* DMA RX Descriptor Ring Address */

      #define B44_DMARX_PTR  0x0218UL /* DMA RX Last Posted Descriptor */

      #define B44_DMARX_STAT 0x021CUL /* DMA RX Current Active Desc. + Status */

      b44_rx()來(lái)說(shuō),B44_DMARX_ADDR儲(chǔ)存了環(huán)形緩沖的基地址,B44_DMARX_PTR存儲(chǔ)了環(huán)形緩沖最后一個(gè)緩沖區(qū)號(hào),這兩個(gè)寄存器都由處理來(lái)設(shè)置;B44_DMARX_STAT儲(chǔ)存了狀態(tài)及網(wǎng)卡當(dāng)前處理到的緩沖區(qū)號(hào),這個(gè)寄存器只能由網(wǎng)卡來(lái)設(shè)置。

       

      網(wǎng)卡中DMA也很重要:

      在網(wǎng)卡初始化階段,b44_open() -> b44_alloc_consistent()

      bp->rx_buffers = kzalloc(size, gfp);  // size = B44_RX_RING_SIZE * sizeof(struct ring_info)

      bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);

           // size = DMA_TABLE_BYTES

      rx_ringDMA映射的虛擬地址,rx_rind_dmaDMA映射的總線(xiàn)地址,這個(gè)地址將會(huì)寫(xiě)入B44_DMARX_ADDR寄存器,作為環(huán)形緩沖的基地址。

      bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);

      稍后在rx_init_rings() -> b44_alloc_rx_skb()

      mapping = ssb_dma_map_single(bp->sdev, skb->data,RX_PKT_BUF_SZ,DMA_FROM_DEVICE);

      rx_buffers進(jìn)行DMA映射,并將映射地址存儲(chǔ)在rx_ring

      dp->addr = cpu_to_le32((u32) mapping + bp->dma_offset); // dprx_ring中一個(gè)

       

      DMA的大致流程:

             不準(zhǔn)確,但可以參考下大致意思

       

      網(wǎng)卡讀取B44_DMARX_ADDRB44_DMARX_STAT寄存器,得到下一個(gè)處理的struct dma_desc,然后根據(jù)dma_desc中的addr找到報(bào)文緩沖區(qū),通過(guò)DMA處理器將網(wǎng)卡收到報(bào)文拷貝到addr地址處,這個(gè)過(guò)程CPU是不參與的。

       

              prod – 網(wǎng)卡[硬件]處理到的緩沖區(qū)號(hào)

      prod  = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK;

      prod /= sizeof(struct dma_desc);

      cons = bp->rx_cons;

      根據(jù)上面分析,prod讀取B44_DMARX_STAT寄存器,存儲(chǔ)網(wǎng)卡當(dāng)前處理到的緩沖區(qū)號(hào);cons存儲(chǔ)處理器處理到的緩沖區(qū)號(hào)。

       

      while (cons != prod && budget > 0) {

      處理報(bào)文當(dāng)前時(shí)刻網(wǎng)卡接收到的所有報(bào)文,每處理一個(gè)報(bào)文cons都會(huì)加1,由于是環(huán)形緩沖,因此這里用相等,而不是大小比較。

       

      struct ring_info *rp = &bp->rx_buffers[cons];

      struct sk_buff *skb = rp->skb;

      dma_addr_t map = rp->mapping;

      skbmap保存了當(dāng)關(guān)地址,下面在交換緩沖區(qū)后會(huì)用到。

       

      ssb_dma_sync_single_for_cpu(bp->sdev, map,RX_PKT_BUF_SZ,DMA_FROM_DEVICE);

      CPU取得rx_buffer[cons]的控制權(quán),此時(shí)網(wǎng)卡不能再處理該緩沖區(qū)。

       

      rh = (struct rx_header *) skb->data;

      len = le16_to_cpu(rh->len);

      ….

      len -= 4;

      CPU取得控制權(quán)后,取得報(bào)文頭,再?gòu)膱?bào)文頭取出報(bào)文長(zhǎng)度len,len-=4表示忽略了最后4節(jié)字的CRC,從這里可以看出,B440X網(wǎng)卡驅(qū)動(dòng)不會(huì)檢查CRC校驗(yàn)。而每個(gè)報(bào)文數(shù)據(jù)最前面添加了網(wǎng)卡的頭部信息struct rx_header,這里是28字節(jié)。

       

      struct sk_buff *copy_skb;

      b44_recycle_rx(bp, cons, bp->rx_prod);

      copy_skb = netdev_alloc_skb(bp->dev, len + 2);

      copy_skb作為傳送報(bào)文的中間量,在第三句為其分配了len + 2的空間(為了IP頭對(duì)齊,稍后提到)b44_recycle_rx()函數(shù)很關(guān)鍵,它作了如下工作:

      1.       將緩沖區(qū)號(hào)cons賦值給緩沖區(qū)號(hào)rx_prod;

      2.       rx_buffers[cons].skb = NULL

      3.       將緩沖區(qū)號(hào)rx_prod控制權(quán)給網(wǎng)卡

      簡(jiǎn)單來(lái)說(shuō),就是將cons號(hào)緩沖區(qū)交由CPU處理,而用rx_prod號(hào)緩沖區(qū)代替其給網(wǎng)卡使用。

                               

      a.       b44_recycle_rx                          b. b44_recycle_rx

      以起始狀態(tài)為例,緩沖區(qū)rx_ring分配了512個(gè),但rx_buffers僅分配了200個(gè),此時(shí)cons = 0,rx_prod = 200。執(zhí)行b44_recycle_rx()后,網(wǎng)卡處理緩沖區(qū)變?yōu)?/span>1~200,而0號(hào)緩沖區(qū)交由CPU處理,將報(bào)文拷貝,并向上送至協(xié)議棧。注意rx_ringrx_buffer是不同的。

      這樣做的好處在于,不用等待CPU處理完0號(hào)緩沖區(qū),網(wǎng)卡的緩沖區(qū)數(shù)保持200,而不會(huì)減少,這也是rx_pending = 200的原因所在。

       

      skb_reserve(copy_skb, 2);

      skb_put(copy_skb, len);

      關(guān)于skb的操作自己去了解,這里skb_reserve()在報(bào)文頭部保留了兩個(gè)字節(jié),我們知道鏈路層報(bào)頭是14字節(jié),正常IP報(bào)文會(huì)從14字節(jié)開(kāi)始,這樣就不是4字節(jié)對(duì)齊了,所以在頭部保留2字節(jié),使IP報(bào)文從16字節(jié)開(kāi)始。

       

       

      skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET,copy_skb->data, len);

      skb = copy_skb;

      CPU將報(bào)文從skb拷貝到copy_skb中,跳過(guò)了網(wǎng)卡報(bào)頭的額外信息,因?yàn)檫@部分信息在上層協(xié)議站是沒(méi)用的,所以去掉。在函數(shù)開(kāi)始時(shí)說(shuō)過(guò)skb是保存了cons號(hào)的地址,因?yàn)樵?/span>b44_recycle_rx()cons號(hào)不再引用skb指向的空間,而僅由skb引用,這樣便可以向上層傳送,而不用額外復(fù)制。

       

      netif_receive_skb(skb);

      received++;

      budget--;

      next_pkt:

           bp->rx_prod = (bp->rx_prod + 1) & (B44_RX_RING_SIZE - 1);

           cons = (cons + 1) & (B44_RX_RING_SIZE - 1);

      netif_receive_skb()將報(bào)文交由上層協(xié)議棧處理,這是下一節(jié)的內(nèi)容,然后CPU處理下一個(gè)報(bào)文,rx_prodcons各加1,它們代表的含義開(kāi)頭有說(shuō)明。

       

      如此循環(huán),直到cons == prod,此時(shí)網(wǎng)卡收到的報(bào)文都已被CPU處理,更新變量:

       

      bp->rx_cons = cons;

      bw32(bp, B44_DMARX_PTR, cons * sizeof(struct dma_desc));

       

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶(hù) 評(píng)論公約

        類(lèi)似文章 更多