注册
设备什么时候注册
1)加载驱动程序时(静态编译进内核的在启动时注册,动态模块加载的在加载时注册)
2)插入热插拔设备时(插入时内核通知其设备驱动注册该设备)
设备的注册实际上是由pci_driver->probe函数执行来完成的(probe何时调用参考前几章) 流程如下图:
其中alloc_netdev分配内存块(包括net_device结构、驱动程序私有数据块以及强制对齐填充数据),
xxx_setup(dev) 初始化net_device结构(仅初始化任何以太网卡所共享的字段和函数指针)
netdev_boot_setup_check 检查用户在加载内核时是否提供了参数,
register_netdev(dev)( 注册中的主要函数 )把新的net_device插入到dev_base中 看下图;
register_netdev流程如下图
因为net_device结构的改变受rtnl_lock rtnl_unlock两个锁保护,所以register_netdev函数在开始时获得锁,在返回前释放锁
,一旦register_netdevice完成了它的工作,便会调用net_set_todo把新的net_device添加到net_todo_list中,这个list包含了
注册已结束的设备。最后rtnl_unlock不仅释放锁,而且还调用netdev_run_todo函数,后者扫描net_todo_list完成注册。
register_netdevice执行如下操作:
1)net_device部分域初始化
2)allow_divert_blk函数分配特性需要的配置块,并连接到dev->divert
3) 执行驱动自定义的初始化函数
4) dev_new_index函数分配唯一标识符
5) 把net_device加到全局链表dev_base中,并将其插入dev_name_base和dev_index_head两个哈希表中(用于查找)
6) 检测特性标志是否有效
7) 设置 dev->state中的__link_state_present标志
8)初始化队列规则、流量控制
9)netdev_chain通知链通知所有对设备感兴趣的子系统
10)调用netdev_run_todo 更新dev->reg_state 并在sysfs文件系统中注册该设备
注销
设备什么时候注销
1)卸载驱动程序
2)移除热插拔设备
设备的注销是由pci_driver->remove函数执行的,流程如下图;
unregister_netdevice执行如下操作;
1)若设备此时没有被禁止,则调用dev_close禁止它
2)从dev_base中删除net_device结构,同时也从两个哈希表中删除该设备
3)调用dev_shutdown函数释放所有与设备相关的队列规则实例
4)发送netdev_unregister通知到netdev_chain通知链使其他内核组件知道注销事件发生
5)释放所有链接到net_device结构的数据块
6)最后调用net_set_todo,dev_put函数减少引用计数。调用net_run_todo函数从sysfs中注销设备,并设置dev->state为
netreg_unregistered,等到所有的引用都释放后,调用dev->destructor结束注销过程
enable,disable网络设备
enable
网络设备注册完后必须enable后才能收发数据(其他设备也一样,这里以网络设备为例)
首先调用dev->open处理设备enable请求,设置dev->state的__link_state_start标志位,标记设备打开并在运行,设置dev-
>flags的iff_up标志位标记设备启动。
调用dev_activate所指函数 初始化流量控制用的排队规则,并启动监视定时器。
发送netdev_up通知给netdev_chain通知链以通知对设备enable感兴趣的内核组件
disable
在设备注销时,首先调用dev_close禁止该网络设备
发送netdev_going_down通知到netdev_chain通知链以通知对设备禁止有兴趣的内核组件
调用dev_deactivate函数禁止出口队列规则,确保设备不再用于传输,并停止监视定时器
清除dev->state的__link_state_start
若已调度了轮询读设备入队列数据包,则等待此动作完成
清除dev->flags的iff_up
发送netdev_down通知给netdev_chain通知链,通知对设备禁止感兴趣的内核组件