网络子系统6_设备开启与关闭 .
2013-12-19 20:55
405 查看
// 网络设备开启
// 函数主要任务:
// 1.设置dev->state=__LINK_STATE_START
// 2.调用驱动程序的回调函数open
// 3.设置dev->flags |= IFF_UP表示设备开启
// 4.更新多播列表,
// 5.激活设备
// 6.通知监听器,设置dev->flags
// 设备开启之后应该具备的特征:
// 1.dev->state, 表示设备可以进行传输接收
// 2.dev->flags,表示设备已经开启
// 3.设备使用了正确的队列规则
1.1 int dev_open(struct net_device *dev)
{
int ret = 0;
//检查设备是否已经开启
if (dev->flags & IFF_UP)
return 0;
//检查设备是否存在
if (!netif_device_present(dev))
return -ENODEV;
//设置设备可以进行接收
set_bit(__LINK_STATE_START, &dev->state);
if (dev->open) {
//如果驱动程序提供了open函数,则调用
ret = dev->open(dev);
if (ret)
clear_bit(__LINK_STATE_START, &dev->state);
}
if (!ret) {
//设置开启标志
dev->flags |= IFF_UP;
//加载多播地址列表
dev_mc_upload(dev);
//激活设备,使能传输队列
dev_activate(dev);
//向netdev_chain通知有设备开启
notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
}
return ret;
}
// 加载设备多播地址
// 调用路径:dev_open->dev_mc_upload
// ip地址,mac地址之间的映射,参照http://blog.csdn.net/hxg130435477/article/details/8049271
1.2 void dev_mc_upload(struct net_device *dev)
{
spin_lock_bh(&dev->xmit_lock);
__dev_mc_upload(dev);
spin_unlock_bh(&dev->xmit_lock);
}
// 调用路径:dev_open->dev_mc_upload->__dev_mc_upload
// 通过驱动程序的回调函数,设置设备的l2多播地址列表
1.3 static void __dev_mc_upload(struct net_device *dev)
{
//设备应该处于关闭状态
if (!(dev->flags&IFF_UP))
return;
//设备驱动提供了设置多播地址的方法
if (dev->set_multicast_list == NULL ||
!netif_device_present(dev))
return;
//调用设备提供的设置多播地址的方法
dev->set_multicast_list(dev);
}
// 调用路径:dev_open->dev_activate
// 函数主要任务:
// 1.更新设备的队列规则
// 1.1 如果设备没有使用队列规则,则dev->qdisc设置为noqueue_disc,防止不正确的使用该驱动的队列规则
// 1.2 如果设备使用队列规则:
// 1.2.1 如果设置第一次被激活,则分配新的队列规则,保存在dev->qdisc_sleeping
// 1.2.2 如果设备非第一次被激活
// 1.2.3 设置dev->qdisc=dev->qdisc_sleeping
// 2.启动看门狗
1.4 void dev_activate(struct net_device *dev)
{
//设备没有关联队列规则
if (dev->qdisc_sleeping == &noop_qdisc) {
struct Qdisc *qdisc;
//设备存在传输队列
//dev->tx_queue_len的值由设备驱动程序设置
if (dev->tx_queue_len) {
//创建先进先出队列
qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops);
if (qdisc == NULL) {
printk(KERN_INFO "%s: activation failed\n", dev->name);
return;
}
//将队列规则添加到dev的队列规则链表头
//说明一个dev可以有多个队列规则
write_lock_bh(&qdisc_tree_lock);
list_add_tail(&qdisc->list, &dev->qdisc_list);
write_unlock_bh(&qdisc_tree_lock);
} else {
//如果驱动程序没有提供tx_queue_len,即=0
//设置默认的队列
qdisc = &noqueue_qdisc;
}
write_lock_bh(&qdisc_tree_lock);
//设置dev的qdisc_sleeping
dev->qdisc_sleeping = qdisc;
write_unlock_bh(&qdisc_tree_lock);
}
spin_lock_bh(&dev->queue_lock);
//设置qdisc_sleep到qdisc字段
rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping);
if (dev->qdisc != &noqueue_qdisc) {
dev->trans_start = jiffies;
//唤醒看门狗
dev_watchdog_up(dev);
}
spin_unlock_bh(&dev->queue_lock);
}
// 设备关闭
// 函数主要任务:
// 1.向netdev_chain发送消息NETDEV_GOING_DOWN
// 2.deactivate设备,
// 3.清除dev->state的__LINK_STATE_START
// 4.等待设备完成数据接收
// 5.调用驱动程序提供的关闭函数
// 6清除dev->flags中的IFF_UP
// 7.向netdev_chain发送消息NETDEV_DOWN
2.1 int dev_close(struct net_device *dev)
{
//设备已经关闭,则直接返回
if (!(dev->flags & IFF_UP))
return 0;
//向netdev_chain发送设备正在关闭消息
notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
//关闭设备队列规则
dev_deactivate(dev);
//设置设备关闭传输
clear_bit(__LINK_STATE_START, &dev->state);
//内存屏障
smp_mb__after_clear_bit();
//设备还在接收输入流量
while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
//调度当前线程等待
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(1);
}
//驱动提供了停止函数,则调用
if (dev->stop)
dev->stop(dev);
//清除IFF_UP标志,表示设备已被关闭
dev->flags &= ~IFF_UP;
//通知netdev_chain已关闭消息
notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
return 0;
}
// 网络设备的看门狗:
// 1.当网络设备由于被开启而激活传输时,同时激活设备驱动程序的开门狗机制。
// 2.看门狗的定时周期由驱动程序通过dev->watchdog_time指定
// 3.看门狗的定时器由驱动程序通过dev->watchdog_timer提供
// 调用路径:dev_activate->dev_watchdog_up
3.1 static void dev_watchdog_up(struct net_device *dev)
{
//在获取dev->xmit_lock传输锁时设置看门狗定时器
spin_lock_bh(&dev->xmit_lock);
__netdev_watchdog_up(dev);
spin_unlock_bh(&dev->xmit_lock);
}
// 调用路径dev_activate->dev_watchdog_up->__netdev_watchdog_up
void __netdev_watchdog_up(struct net_device *dev)
{
if (dev->tx_timeout) {
if (dev->watchdog_timeo <= 0)//设备驱动没有设置看门狗的到期时间
dev->watchdog_timeo = 5*HZ;
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
dev_hold(dev);
}
}
// 函数主要任务:
// 1.设置dev->state=__LINK_STATE_START
// 2.调用驱动程序的回调函数open
// 3.设置dev->flags |= IFF_UP表示设备开启
// 4.更新多播列表,
// 5.激活设备
// 6.通知监听器,设置dev->flags
// 设备开启之后应该具备的特征:
// 1.dev->state, 表示设备可以进行传输接收
// 2.dev->flags,表示设备已经开启
// 3.设备使用了正确的队列规则
1.1 int dev_open(struct net_device *dev)
{
int ret = 0;
//检查设备是否已经开启
if (dev->flags & IFF_UP)
return 0;
//检查设备是否存在
if (!netif_device_present(dev))
return -ENODEV;
//设置设备可以进行接收
set_bit(__LINK_STATE_START, &dev->state);
if (dev->open) {
//如果驱动程序提供了open函数,则调用
ret = dev->open(dev);
if (ret)
clear_bit(__LINK_STATE_START, &dev->state);
}
if (!ret) {
//设置开启标志
dev->flags |= IFF_UP;
//加载多播地址列表
dev_mc_upload(dev);
//激活设备,使能传输队列
dev_activate(dev);
//向netdev_chain通知有设备开启
notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
}
return ret;
}
// 加载设备多播地址
// 调用路径:dev_open->dev_mc_upload
// ip地址,mac地址之间的映射,参照http://blog.csdn.net/hxg130435477/article/details/8049271
1.2 void dev_mc_upload(struct net_device *dev)
{
spin_lock_bh(&dev->xmit_lock);
__dev_mc_upload(dev);
spin_unlock_bh(&dev->xmit_lock);
}
// 调用路径:dev_open->dev_mc_upload->__dev_mc_upload
// 通过驱动程序的回调函数,设置设备的l2多播地址列表
1.3 static void __dev_mc_upload(struct net_device *dev)
{
//设备应该处于关闭状态
if (!(dev->flags&IFF_UP))
return;
//设备驱动提供了设置多播地址的方法
if (dev->set_multicast_list == NULL ||
!netif_device_present(dev))
return;
//调用设备提供的设置多播地址的方法
dev->set_multicast_list(dev);
}
// 调用路径:dev_open->dev_activate
// 函数主要任务:
// 1.更新设备的队列规则
// 1.1 如果设备没有使用队列规则,则dev->qdisc设置为noqueue_disc,防止不正确的使用该驱动的队列规则
// 1.2 如果设备使用队列规则:
// 1.2.1 如果设置第一次被激活,则分配新的队列规则,保存在dev->qdisc_sleeping
// 1.2.2 如果设备非第一次被激活
// 1.2.3 设置dev->qdisc=dev->qdisc_sleeping
// 2.启动看门狗
1.4 void dev_activate(struct net_device *dev)
{
//设备没有关联队列规则
if (dev->qdisc_sleeping == &noop_qdisc) {
struct Qdisc *qdisc;
//设备存在传输队列
//dev->tx_queue_len的值由设备驱动程序设置
if (dev->tx_queue_len) {
//创建先进先出队列
qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops);
if (qdisc == NULL) {
printk(KERN_INFO "%s: activation failed\n", dev->name);
return;
}
//将队列规则添加到dev的队列规则链表头
//说明一个dev可以有多个队列规则
write_lock_bh(&qdisc_tree_lock);
list_add_tail(&qdisc->list, &dev->qdisc_list);
write_unlock_bh(&qdisc_tree_lock);
} else {
//如果驱动程序没有提供tx_queue_len,即=0
//设置默认的队列
qdisc = &noqueue_qdisc;
}
write_lock_bh(&qdisc_tree_lock);
//设置dev的qdisc_sleeping
dev->qdisc_sleeping = qdisc;
write_unlock_bh(&qdisc_tree_lock);
}
spin_lock_bh(&dev->queue_lock);
//设置qdisc_sleep到qdisc字段
rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping);
if (dev->qdisc != &noqueue_qdisc) {
dev->trans_start = jiffies;
//唤醒看门狗
dev_watchdog_up(dev);
}
spin_unlock_bh(&dev->queue_lock);
}
// 设备关闭
// 函数主要任务:
// 1.向netdev_chain发送消息NETDEV_GOING_DOWN
// 2.deactivate设备,
// 3.清除dev->state的__LINK_STATE_START
// 4.等待设备完成数据接收
// 5.调用驱动程序提供的关闭函数
// 6清除dev->flags中的IFF_UP
// 7.向netdev_chain发送消息NETDEV_DOWN
2.1 int dev_close(struct net_device *dev)
{
//设备已经关闭,则直接返回
if (!(dev->flags & IFF_UP))
return 0;
//向netdev_chain发送设备正在关闭消息
notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
//关闭设备队列规则
dev_deactivate(dev);
//设置设备关闭传输
clear_bit(__LINK_STATE_START, &dev->state);
//内存屏障
smp_mb__after_clear_bit();
//设备还在接收输入流量
while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
//调度当前线程等待
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(1);
}
//驱动提供了停止函数,则调用
if (dev->stop)
dev->stop(dev);
//清除IFF_UP标志,表示设备已被关闭
dev->flags &= ~IFF_UP;
//通知netdev_chain已关闭消息
notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
return 0;
}
// 网络设备的看门狗:
// 1.当网络设备由于被开启而激活传输时,同时激活设备驱动程序的开门狗机制。
// 2.看门狗的定时周期由驱动程序通过dev->watchdog_time指定
// 3.看门狗的定时器由驱动程序通过dev->watchdog_timer提供
// 调用路径:dev_activate->dev_watchdog_up
3.1 static void dev_watchdog_up(struct net_device *dev)
{
//在获取dev->xmit_lock传输锁时设置看门狗定时器
spin_lock_bh(&dev->xmit_lock);
__netdev_watchdog_up(dev);
spin_unlock_bh(&dev->xmit_lock);
}
// 调用路径dev_activate->dev_watchdog_up->__netdev_watchdog_up
void __netdev_watchdog_up(struct net_device *dev)
{
if (dev->tx_timeout) {
if (dev->watchdog_timeo <= 0)//设备驱动没有设置看门狗的到期时间
dev->watchdog_timeo = 5*HZ;
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
dev_hold(dev);
}
}
// 网络设备开启 // 函数主要任务: // 1.设置dev->state=__LINK_STATE_START // 2.调用驱动程序的回调函数open // 3.设置dev->flags |= IFF_UP表示设备开启 // 4.更新多播列表, // 5.激活设备 // 6.通知监听器,设置dev->flags // 设备开启之后应该具备的特征: // 1.dev->state, 表示设备可以进行传输接收 // 2.dev->flags,表示设备已经开启 // 3.设备使用了正确的队列规则 1.1 int dev_open(struct net_device *dev) { int ret = 0; //检查设备是否已经开启 if (dev->flags & IFF_UP) return 0; //检查设备是否存在 if (!netif_device_present(dev)) return -ENODEV; //设置设备可以进行接收 set_bit(__LINK_STATE_START, &dev->state); if (dev->open) { //如果驱动程序提供了open函数,则调用 ret = dev->open(dev); if (ret) clear_bit(__LINK_STATE_START, &dev->state); } if (!ret) { //设置开启标志 dev->flags |= IFF_UP; //加载多播地址列表 dev_mc_upload(dev); //激活设备,使能传输队列 dev_activate(dev); //向netdev_chain通知有设备开启 notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return ret; } // 加载设备多播地址 // 调用路径:dev_open->dev_mc_upload // ip地址,mac地址之间的映射,参照http://blog.csdn.net/hxg130435477/article/details/8049271 1.2 void dev_mc_upload(struct net_device *dev) { spin_lock_bh(&dev->xmit_lock); __dev_mc_upload(dev); spin_unlock_bh(&dev->xmit_lock); } // 调用路径:dev_open->dev_mc_upload->__dev_mc_upload // 通过驱动程序的回调函数,设置设备的l2多播地址列表 1.3 static void __dev_mc_upload(struct net_device *dev) { //设备应该处于关闭状态 if (!(dev->flags&IFF_UP)) return; //设备驱动提供了设置多播地址的方法 if (dev->set_multicast_list == NULL || !netif_device_present(dev)) return; //调用设备提供的设置多播地址的方法 dev->set_multicast_list(dev); } // 调用路径:dev_open->dev_activate // 函数主要任务: // 1.更新设备的队列规则 // 1.1 如果设备没有使用队列规则,则dev->qdisc设置为noqueue_disc,防止不正确的使用该驱动的队列规则 // 1.2 如果设备使用队列规则: // 1.2.1 如果设置第一次被激活,则分配新的队列规则,保存在dev->qdisc_sleeping // 1.2.2 如果设备非第一次被激活 // 1.2.3 设置dev->qdisc=dev->qdisc_sleeping // 2.启动看门狗 1.4 void dev_activate(struct net_device *dev) { //设备没有关联队列规则 if (dev->qdisc_sleeping == &noop_qdisc) { struct Qdisc *qdisc; //设备存在传输队列 //dev->tx_queue_len的值由设备驱动程序设置 if (dev->tx_queue_len) { //创建先进先出队列 qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops); if (qdisc == NULL) { printk(KERN_INFO "%s: activation failed\n", dev->name); return; } //将队列规则添加到dev的队列规则链表头 //说明一个dev可以有多个队列规则 write_lock_bh(&qdisc_tree_lock); list_add_tail(&qdisc->list, &dev->qdisc_list); write_unlock_bh(&qdisc_tree_lock); } else { //如果驱动程序没有提供tx_queue_len,即=0 //设置默认的队列 qdisc = &noqueue_qdisc; } write_lock_bh(&qdisc_tree_lock); //设置dev的qdisc_sleeping dev->qdisc_sleeping = qdisc; write_unlock_bh(&qdisc_tree_lock); } spin_lock_bh(&dev->queue_lock); //设置qdisc_sleep到qdisc字段 rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping); if (dev->qdisc != &noqueue_qdisc) { dev->trans_start = jiffies; //唤醒看门狗 dev_watchdog_up(dev); } spin_unlock_bh(&dev->queue_lock); } // 设备关闭 // 函数主要任务: // 1.向netdev_chain发送消息NETDEV_GOING_DOWN // 2.deactivate设备, // 3.清除dev->state的__LINK_STATE_START // 4.等待设备完成数据接收 // 5.调用驱动程序提供的关闭函数 // 6清除dev->flags中的IFF_UP // 7.向netdev_chain发送消息NETDEV_DOWN 2.1 int dev_close(struct net_device *dev) { //设备已经关闭,则直接返回 if (!(dev->flags & IFF_UP)) return 0; //向netdev_chain发送设备正在关闭消息 notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); //关闭设备队列规则 dev_deactivate(dev); //设置设备关闭传输 clear_bit(__LINK_STATE_START, &dev->state); //内存屏障 smp_mb__after_clear_bit(); //设备还在接收输入流量 while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) { //调度当前线程等待 current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } //驱动提供了停止函数,则调用 if (dev->stop) dev->stop(dev); //清除IFF_UP标志,表示设备已被关闭 dev->flags &= ~IFF_UP; //通知netdev_chain已关闭消息 notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); return 0; } // 网络设备的看门狗: // 1.当网络设备由于被开启而激活传输时,同时激活设备驱动程序的开门狗机制。 // 2.看门狗的定时周期由驱动程序通过dev->watchdog_time指定 // 3.看门狗的定时器由驱动程序通过dev->watchdog_timer提供 // 调用路径:dev_activate->dev_watchdog_up 3.1 static void dev_watchdog_up(struct net_device *dev) { //在获取dev->xmit_lock传输锁时设置看门狗定时器 spin_lock_bh(&dev->xmit_lock); __netdev_watchdog_up(dev); spin_unlock_bh(&dev->xmit_lock); } // 调用路径dev_activate->dev_watchdog_up->__netdev_watchdog_up void __netdev_watchdog_up(struct net_device *dev) { if (dev->tx_timeout) { if (dev->watchdog_timeo <= 0)//设备驱动没有设置看门狗的到期时间 dev->watchdog_timeo = 5*HZ; if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo)) dev_hold(dev); } }
相关文章推荐
- 网络子系统6_设备开启与关闭&nbsp;.
- 网络子系统26_设备传输的开启和关闭
- 网络子系统32_网桥设备的开启与关闭
- 网络子系统5_设备队列规则&nbsp;.
- 网络子系统5_设备队列规则&nbsp;.
- 网络子系统6_设备开启与关闭
- android关闭或开启移动网络数据(关闭后,设备不可以上网,但可以打电话和发短信)
- selinux&nbsp;安全开启与关闭
- Ubuntu 12.04 or 14.04 下USB存储设备自动挂载和自动打开功能的开启和关闭
- JAVA&nbsp;线程&nbsp;开启线程&nbsp;一个类…
- MySQL 开启与关闭远程访问&&授权前需执行GRANT USAGE ON *.* TO 'cai'@'%' IDENTIFIED BY 'caigan2015';才能终端访问
- 【ARM&Linux】Linux子系统之网络子系统-网卡驱动分析
- 网络子系统68_路由表处理设备ip配置事件
- 实现开启和关闭android移动网络(做AppWidget开发的收获)
- Linux&nbsp;kernel&nbsp;I2C设备总结
- 【安卓开机动画】火爆网络 Su…
- Android 蓝牙设备的开启与关闭功能的实现
- android中如何通过代码来开启和关闭移动网络
- 多核CPU关闭&开启
- linux powerpc i2c驱动 之 i2c设备…