6410 linux DM9000收包机制

  • 中断接收

DM9000网卡注册的中断函数为dm9000_interrupt(),该中断函数调用dm9000_rx()从网卡的buffer中读取接收到的数据,将数据接收到skb中之后,调用netif_rx()处理该数据包,最后的结果是将数据包传递给上层处理。

我们看看netif_rx()函数代码主要部分:

int netif_rx(struct sk_buff *skb)
{
    int ret;
    ......
#ifdef CONFIG_RPS
    ......
#else
    {
        unsigned int qtail;
        ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
        put_cpu();
    }
#endif
    return ret;
}

在enqueue_to_backlog()中,通过__skb_queue_tail(&sd->input_pkt_queue, skb)将skb接入per cpu 变量softnet_data的链中。接着在enqueue_to_backlog()中调用____napi_schedule()。

if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) {
    if (!rps_ipi_queued(sd)) {
        printk(KERN_INFO "skedu napi\r\n");
        ____napi_schedule(sd, &sd->backlog);
    }
}

我们进入____napi_schedule()函数看看做了什么

static inline void ____napi_schedule(struct softnet_data *sd,
                     struct napi_struct *napi)
{
    list_add_tail(&napi->poll_list, &sd->poll_list);
    __raise_softirq_irqoff(NET_RX_SOFTIRQ);
}

该函数将napi->poll_list加入sd->poll_list中,并置位了系统注册的软中断的第NET_RX_SOFTIRQ位。最后函数从DM9000的中断函数中返回退出。Linux中负责将skb传递给上层的函数是__netif_receive_skb(),那么该函数是怎么被调用的呢?

  • 软中断处理函数net_rx_action()
    当软中断被调度执行后,net_rx_action()函数会被调用。
static void net_rx_action(struct softirq_action *h)
{
    ......
    while (!list_empty(&sd->poll_list)) {
        ......
        n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list);
        ......
        if (test_bit(NAPI_STATE_SCHED, &n->state)) {
            work = n->poll(n, weight);
            trace_napi_poll(n);
        }
        ......
        if (unlikely(work == weight)) {
            if (unlikely(napi_disable_pending(n))) {
                local_irq_enable();
                napi_complete(n);
                local_irq_disable();
            } else
                list_move_tail(&n->poll_list, &sd->poll_list);
        }
    ......
}

简化之后,该函数首先从poll_list中取出一个napi_struct ,即____napi_schedule()函数中加入到poll_list中的napi_struct,然后调用该napi_struct的poll函数。查找代码,找出poll函数指针指向的函数原型process_backlog(),在process_backlog()函数中执行__netif_receive_skb(skb)将skb传递给上层。

  • 软中断什么时候被调用?

这个问题,我在网上搜了好一会儿工夫,最后发现,每次cpu执行完中断函数后,例如dm9000_interrupt()函数,在cpu退出中断asm_do_IRQ()前调用irq_exit(),在irq_exit()中执行软中断。在软中断中唤醒软中断处理任务,然后,cpu中断彻底退出,等到系统调度任务的时候,软终端所唤醒的任务得以被调度执行。具体来说,就是net_rx_action()函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值