免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Linux內(nèi)核分析 - 網(wǎng)絡(luò)[二]:網(wǎng)卡驅(qū)動接收報文

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

上篇講到通過中斷,最終網(wǎng)卡調(diào)用了b44_rx()來接收報文

 

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

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

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

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

 

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

#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()來說,B44_DMARX_ADDR儲存了環(huán)形緩沖的基地址,B44_DMARX_PTR存儲了環(huán)形緩沖最后一個緩沖區(qū)號,這兩個寄存器都由處理來設(shè)置;B44_DMARX_STAT儲存了狀態(tài)及網(wǎng)卡當(dāng)前處理到的緩沖區(qū)號,這個寄存器只能由網(wǎng)卡來設(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映射的總線地址,這個地址將會寫入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進行DMA映射,并將映射地址存儲在rx_ring

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

 

DMA的大致流程:

       不準確,但可以參考下大致意思

 

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

 

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

prod  = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK;

prod /= sizeof(struct dma_desc);

cons = bp->rx_cons;

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

 

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

處理報文當(dāng)前時刻網(wǎng)卡接收到的所有報文,每處理一個報文cons都會加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ū)后會用到。

 

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

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

 

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

len = le16_to_cpu(rh->len);

….

len -= 4;

CPU取得控制權(quán)后,取得報文頭,再從報文頭取出報文長度len,len-=4表示忽略了最后4節(jié)字的CRC,從這里可以看出,B440X網(wǎng)卡驅(qū)動不會檢查CRC校驗。而每個報文數(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作為傳送報文的中間量,在第三句為其分配了len + 2的空間(為了IP頭對齊,稍后提到)。b44_recycle_rx()函數(shù)很關(guān)鍵,它作了如下工作:

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

2.       rx_buffers[cons].skb = NULL

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

簡單來說,就是將cons號緩沖區(qū)交由CPU處理,而用rx_prod號緩沖區(qū)代替其給網(wǎng)卡使用。

   

  
                  

a.       b44_recycle_rx                          b. b44_recycle_rx

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

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

 

skb_reserve(copy_skb, 2);

skb_put(copy_skb, len);

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

 

 

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

skb = copy_skb;

CPU將報文從skb拷貝到copy_skb中,跳過了網(wǎng)卡報頭的額外信息,因為這部分信息在上層協(xié)議站是沒用的,所以去掉。在函數(shù)開始時說過skb是保存了cons號的地址,因為在b44_recycle_rx()cons號不再引用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()將報文交由上層協(xié)議棧處理,這是下一節(jié)的內(nèi)容,然后CPU處理下一個報文,rx_prodcons各加1,它們代表的含義開頭有說明。

 

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

 

bp->rx_cons = cons;

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

 

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux內(nèi)核napi機制分析
Linux網(wǎng)卡數(shù)據(jù)包的接收
談?wù)凬API機制
linux網(wǎng)絡(luò)設(shè)備應(yīng)用與驅(qū)動編程學(xué)習(xí)4——模板與實例(A)
linux協(xié)議棧之鏈路層上的數(shù)據(jù)傳輸之二
NAPI 技術(shù)在 Linux 網(wǎng)絡(luò)驅(qū)動上的應(yīng)用和完善
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服