1.网卡驱动收数据包思路记录

来源:互联网 发布:开淘宝店进货渠道 编辑:程序博客网 时间:2024/06/09 16:45
http://www.cnblogs.com/lidp/archive/2009/05/13/1697981.html
根据这个思路走


网卡收到数据包的大概流程,目前只是大概理顺下思路,可能有的地方理解有误。


网卡的工作能力,接收到物理层面上的信号。
1.能够识别出来数据链路层的(L4)层的数据帧。
2.接收到多个数据帧的时候有一定的缓存能力。
3.能够在数据链路层计算收到的帧是否正确。
4.有帧的时候产生中断通知CPU。


驱动工作流程
1.注册中断函数
2.数据到了触发硬中断,硬中断只是将代表当前驱动的napi_struct连接到CPU的softnet_data,然后触发软中断。
3.软中断函数调用poll在一小段时间不断的读取数据帧存放到skb里面。

4.回调netif_receive_skb函数





1.网卡启动
核心函数 request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)
注册中断函数,当有数据包过来的时候会触发中断从而调用e100_intr,从而驱动知道有数据包过来。
static int e100_up(struct nic *nic)
{
int err;


if ((err = e100_rx_alloc_list(nic)))
return err;
if ((err = e100_alloc_cbs(nic)))
goto err_rx_clean_list;
if ((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
e100_start_receiver(nic, NULL);
mod_timer(&nic->watchdog, jiffies);
if ((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)))
goto err_no_irq;
netif_wake_queue(nic->netdev);
napi_enable(&nic->napi);
/* enable ints _after_ enabling poll, preventing a race between
* disable ints+schedule */
e100_enable_irq(nic);
return 0;


err_no_irq:
del_timer_sync(&nic->watchdog);
err_clean_cbs:
e100_clean_cbs(nic);
err_rx_clean_list:
e100_rx_clean_list(nic);
return err;
}


2.中断里面只是告诉CPU有数据到了,将代表网卡的napi_struct通过链表添加在CPU的softnet_data上面,然后触发软中断,
软中断过程中调用注册过来的napi_struct上面的poll函数,在软中断中不断的读取和发送数据。
static irqreturn_t e100_intr(int irq, void *dev_id)
{
struct net_device *netdev = dev_id;
struct nic *nic = netdev_priv(netdev);
u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);


netif_printk(nic, intr, KERN_DEBUG, nic->netdev,
    "stat_ack = 0x%02X\n", stat_ack);


if (stat_ack == stat_ack_not_ours ||/* Not our interrupt */
  stat_ack == stat_ack_not_present)/* Hardware is ejected */
return IRQ_NONE;


/* Ack interrupt(s) */
iowrite8(stat_ack, &nic->csr->scb.stat_ack);


/* We hit Receive No Resource (RNR); restart RU after cleaning */
if (stat_ack & stat_ack_rnr)
nic->ru_running = RU_SUSPENDED;


if (likely(napi_schedule_prep(&nic->napi))) {
e100_disable_irq(nic);
__napi_schedule(&nic->napi);
}


return IRQ_HANDLED;
}


3.poll函数
e100_poll函数在PCI网卡探测成功之后就注册在net_device里面
static int e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *netdev;
struct nic *nic;
netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT);
}
注册完为
struct net_device {
struct list_headnapi_list;//这个链表上面链接这所有的napi_struct
}
struct napi_struct { //napi_struct 里面包含所有的poll函数
int (*poll)(struct napi_struct *, int);
}


static int e100_poll(struct napi_struct *napi, int budget)
{
struct nic *nic = container_of(napi, struct nic, napi);
unsigned int work_done = 0;


e100_rx_clean(nic, &work_done, budget);
e100_tx_clean(nic);


/* If budget not fully consumed, exit the polling mode */
if (work_done < budget) {
napi_complete(napi);
e100_enable_irq(nic);
}


return work_done;
}


4.接收数据的函数e100_rx_clean
e100_rx_clean -> e100_rx_indicate -> netif_receive_skb
原创粉丝点击