Windows XP Windows 7 Windows 2003 Windows Vista Windows教程綜合 Linux 系統教程
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟件教程
 Windows教程網 >> Linux系統教程 >> Linux教程 >> linux協議棧之鏈路層上的數據傳輸-數據發送

linux協議棧之鏈路層上的數據傳輸-數據發送

日期:2017/2/7 14:39:47      編輯:Linux教程
 

數據的發送

在進入到發送函數之前,我們先來看e100_up()->e100_alloc_cbs函數:

static int e100_alloc_cbs(struct nic *nic)

{

struct cb *cb;

unsigned int i, count = nic->params.cbs.count;



nic->cuc_cmd = cuc_start;

nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;

nic->cbs_avail = 0;

 

//線性DMA映射,這裡返回的是虛擬地址,供CPU使用的

nic->cbs = pci_alloc_consistent(nic->pdev,

sizeof(struct cb) * count, &nic->cbs_dma_addr);

if(!nic->cbs)

return -ENOMEM;

//建立環形的發送緩沖區

for(cb = nic->cbs, i = 0; i < count; cb++, i++) {

cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;

cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1;



cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);

cb->link = cpu_to_le32(nic->cbs_dma_addr +

((i+1) % count) * sizeof(struct cb));

cb->skb = NULL;

}

//初始化各指針,使其指向緩沖初始位置

nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;

nic->cbs_avail = count;



return 0;

}

在這一段代碼裡,完成了發送的准備工作,建立了發送環形緩存。在發送數劇時,只要把數據送入緩存即可

數據最終會調用dev-> hard_start_xmit函數。在e100代碼裡,也就是e100_xmit_frame(). 進入裡面看下:

static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)

{

struct nic *nic = netdev_priv(netdev);

int err;



if(nic->flags & ich_10h_workaround) {

e100_exec_cmd(nic, cuc_nop, 0);

udelay(1);

}

err = e100_exec_cb(nic, skb, e100_xmit_prepare);

switch(err) {

case -ENOSPC:

/* We queued the skb, but now we're out of space. */

netif_stop_queue(netdev);

break;

case -ENOMEM:

/* This is a hard error - log it. */

DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n");

netif_stop_queue(netdev);

return 1;

}



netdev->trans_start = jiffies;

return 0;

}

繼續跟蹤進 e100_exec_cb(nic, skb, e100_xmit_prepare);

static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb,

void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))

{

struct cb *cb;

unsigned long flags;

int err = 0;



spin_lock_irqsave(&nic->cb_lock, flags);



if(unlikely(!nic->cbs_avail)) {

err = -ENOMEM;

goto err_unlock;

}

 

//將skb 推入環形發送緩沖

//cb_to_use:發送緩沖當前的使用位置

cb = nic->cb_to_use;

nic->cb_to_use = cb->next;

nic->cbs_avail--;

cb->skb = skb;



if(unlikely(!nic->cbs_avail))

err = -ENOSPC;



cb_prepare(nic, cb, skb);



/* Order is important otherwise we'll be in a race with h/w:

* set S-bit in current first, then clear S-bit in previous. */

cb->command |= cpu_to_le16(cb_s);

wmb();

cb->prev->command &= cpu_to_le16(~cb_s);

//當發送數據不為空。將余下數劇全部發送

while(nic->cb_to_send != nic->cb_to_use) {

if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd,

nic->cb_to_send->dma_addr))) {

/* Ok, here's where things get sticky. It's

* possible that we can't schedule the command

* because the controller is too busy, so

* let's just queue the command and try again

* when another command is scheduled. */

break;

} else {

nic->cuc_cmd = cuc_resume;

nic->cb_to_send = nic->cb_to_send->next;

}

}



err_unlock:

spin_unlock_irqrestore(&nic->cb_lock, flags);



return err;

}

在這裡我們看到,發送數據過程主要由e100_exec_cmd完成。跟蹤進去

static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)

{

unsigned long flags;

unsigned int i;

int err = 0;

Copyright © Windows教程網 All Rights Reserved