數據的發送
在進入到發送函數之前,我們先來看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;