说实话,在这码半天代码,分析了半天,是了神马啊?是因为我们出来江湖混,迟早是要还的,现在我们分析的文件早已超出了dm9000.c,我们完全可以就使用内核提供的接口,而不过问它怎么实现的,但是作为一个有刨根问底精神的人,我们还是需要知道内幕的
正像前几天一个媒体人说到:纳税人有权知道内幕!这句强有力的呐喊。就像人梁宏达,在刘翔事件出来之后第一时间就进行了内幕分析:刘翔跑不跑?问问局领导!刘翔行不行?问问孙海平!刘翔伤没伤?问问赞助商!伤势大不大?问问冬日娜!我了个去。。尼玛,这种刨根问底精神值得学习啊!
继续贴代码:
我了个去。。还没看到函数的尾部?诚实的告诉你,忍一忍快了,谁让咱是生活在这个世纪的劳苦大众,还要修行呢?唉。。继续吧
5819行, dev->pcpu_refcnt这个东东是什么呢?由其字面意思,我们可以推断,这是每个cpu的数据中一个叫做引用技术的东东。percpu data 是内核为smp系统中不同CPU之间的数据保护方式,系统为每个CPU维护一段私有的空间,在这段空间中的数据只有这个CPU能访问。但是这种方式不提供 对异步函数访问的保护,因此在同一个CPU上还要另外的同步原语的协作。
那么这个赋值函数alloc_percpu(int)呢?它是给系统中每个处理器分配一个指定类型的对象。
5823行。dev_addr_init设备地址的初始化,我们暂且搁置,一会儿回过头来看。
5826行,dev_mc_init(dev);初始化了一个多播mac地址链表
5827行,dev_uc_init(dev);初始化了一个单播mac地址链表
5829行,是一个与init_net网络空间结构相关的操作,在CONFIG_NET_NS配置的情况下才会得到执行。
5831行,GSO_MAX_SIZE表示网络接口一次能够处理的最大的buffer的大小,一般该值为64KB。
5833-5838 初始化"n-tuple"过滤器链表,初始化napi链表,链路监视链表等一些链表数据结构。
5839调用传进来的setup初始化网络设备,setup函数也是稍事再看。先把这个函数讲完
5841-5844设备发送队列的个数,调用分配接收队列函数,分配队列,分配队列函数也是一会儿一并来看
终于,这个函数快结束了,我们赶紧继续,把下一段代码贴上:
我们欣慰的看到,还剩为数不多的几行代码,5846-5851行和接收队列一样,这里是分配发送队列
5853拷贝传进来的设备名字
5854设置网络设备的组为0
5855返回设置好的net_dev,我去。。终于结束了,嗯?什么还有呢?额。。下面的是出错处理函数,这个真不用讲吧?相信大家都可以自己看明白的,因为很easy啊。。呵呵。。
回过头来想想,这个函数就是分配一个net_dev的空间,然后将其各个成员赋值,这其中有三个函数我们遗留下来了,没有分析,我们现在开始一并解决啊。
1.5823行dev_addr_init 2.5839行setup(dev) 3.5843行的netif_alloc_netdev_queues和5849行的netif_alloc_rx_queues
先看dev_addr_init ,上代码,额。。肚子疼啊。。尼玛可能是着凉了,唉,这年头真应该自己对自己好点儿,不要乱吃东西啊。不管了,先贴上代码,再去如厕。
讲到这儿,我不知道层次够不够深了,希望你的思路还能回来,如果你是个程序的初学者,额,没办法,多看两遍吧。否则别真出不去了,不想讲了半天连个主旨都没有啊。说到这儿了,再继续阐述这个函数之前,我提醒一下读者,这是在讲alloc_netdev_mqs里的一个函数,就是分配网络设备,并初始化发送和接收队列的那个函数,它的顶层封装使我们在 驱动的probe函数里看到的那个alloc_etherdev函数。好了我们又总结回来了,现在你的思路应该略微清晰了吧?咱们继续这个函数,再进一层的就先不深入了,否则这个dm9000将一个半月够呛讲完了,越讲越内核了,脱离了驱动的本质了。
好的,先说下一个这个函数的作用,有个宏观的认识,这个函数主要是初始化设备的地址列表,并且创建第一个元素。
251行 你可以进入函数内部看看,就是初始化一个链表结构,很简单。
253行 实际的创建第一个设备地址元素
好的,第二个未阐述的问题setup(dev),我们知道这个函数是函数入口参数传递过来的一个函数指针,我们退到上一层,可以看到,其实它就是ether_setup,也很简单,不过为了保持完整性,咱们还是贴一下代码:
可以看到,全部是初始化net_device的成员函数,
336填充硬件head的操作函数,贴一下header_ops简单看一下吧:
它的赋值是一个全局函数,我们也大概看一下,先不仔细分析,这涉及到了网络协议层
协议层的东西,咱们有时间再看,只不过咱们目前的关注重点不在此
继续ether_setup 337行
#define ARPHRD_ETHER1/* Ethernet 10Mbps*/
初始化的时候默认当作一个10M的网卡
338行 #define ETH_HLEN14/* Total octets in header.*/
ether层的头长度为14
339行 #define ETH_DATA_LEN1500/* Max. octets in payload*/
负载内容的最大长度为1500
340行 #define ETH_ALEN6/* Octets in one ethernet addr*/
一个网卡地址的长度为6
341 每个队列最大的帧数1000
342 支持广播和多播
344广播地址赋值0xff,长度为6
好了,最后一个未阐述问题,其实也是两个:netif_alloc_netdev_queues和netif_alloc_rx_queues
一个一个的来,先netif_alloc_netdev_queues,我去。。累啊。。尼玛不管了,上代码:
主要就是分配num_tx_queues个发送队列,然后调用netdev_init_one_queue初始化每一个发送队列,还是不太难理解的,至于这个发送队列还是属于协议层范畴,还是先掠过吧,以后时间咱们再慢慢的咀嚼。
好,下一个netif_alloc_rx_queues,上代码:
我了个去,这不是和发送队列的分配一样吗?嗯??额。。唔。。虽然不是在玩儿连连看,不过这少了点儿什么好像真能看出来吧?嗯。。对啊。。少了一个初始化函数啊。。不过你看看这个接收队列的结构体倒是没发送队列那么复杂,怪不得人家没那道工序,原来人家很简单嘛。。
嘘,长出一口气。。总算是讲完了,虽然不是那么完美吧。。但是这个函数终究是告一段落了。。我们知道驱动里这个alloc_etherdev其实就是做了两件事儿,一:分配一个net_device 二:给它做了一个基本的初始化,人家叫做generic init,我了个去。。果然是专业啊 。。尼玛回国头来看看,alloc_etherdev也像当年的干露露一样露的那么彻底,原来,就是那么回事儿。唉!浮生啊,神马都是浮云。。云淡分清之后,回去吃点儿鸡翅补补。。