5.关闭网络设备
static int tg3_close(struct net_device *dev)
{
//停止网卡传输包
netif_stop_queue(dev);
netif_carrier_off(tp->dev);
//去除定时器
del_timer_sync(&tp->timer);
//释放收包和发包的缓冲区
tg3_free_rings(tp);
//释放中断
free_irq(dev->irq, dev);
}
[NextPage]
6.硬件处理数据包发送
static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
len = (skb->len - skb->data_len);
//以DMA方式向网卡物理设备传输包。如果是wireless的话,需要根据802.11协议及硬件的规范从新填充
//硬件帧头,然后提交给硬件发送。
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
//硬件发送
tg3_set_txd(tp, entry, mapping, len, base_flags, mss_and_is_end);
//记录发包开始时间
dev->trans_start = jiffies;
}
7.中断处理收包,发包
static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
//如果要收包
tg3_rx(tp);
//如果要发包
tg3_tx(tp);
}
8.发包
static void tg3_tx(struct tg3 *tp)
{
struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
struct sk_buff *skb = ri->skb;
//以DMA方式向网卡传输包完毕
pci_unmap_single(tp->pdev, pci_unmap_addr(ri, mapping),
(skb->len - skb->data_len), PCI_DMA_TODEVICE);
ri->skb = NULL;
dev_kfree_skb_irq(skb);
}
9.收包
static int tg3_rx(struct tg3 *tp, int budget)
{
struct sk_buff *copy_skb;
//分配一个包
copy_skb = dev_alloc_skb(len + 2);
copy_skb->dev = tp->dev;
//修改包头空间
skb_reserve(copy_skb, 2);
//加入数据到包中
skb_put(copy_skb, len);
//以DMA方式从网卡传输回数据
pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
memcpy(copy_skb->data, skb->data, len);
skb = copy_skb;
//解析包的协议
skb->protocol = eth_type_trans(skb, tp->dev);
//把包送到协议层
netif_rx(skb);
//记录收包时间
tp->dev->last_rx = jiffies;
}
10.读取包的网卡收发包的状态,统计数据
static struct net_device_stats *tg3_get_stats(struct net_device *dev)
{
//从硬件相关的寄存器读取数据,累加
//stats->rx_packets, stats->tx_packets, stats->rx_bytes, stats->tx_bytes等
}
11.用户的ioctl命令系统调用
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
switch(cmd) {
//ethtool程序命令的调用
case SIO*HTOOL:
return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data);
//mii程序命令的调用
case SIOCGMIIREG: {
err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval)
data->val_out = mii_regval;
return err;
}
……
}
}
12.PCI设备的挂起和恢复函数
static int tg3_suspend(struct pci_dev *pdev, u32 state)
{
//停用网卡的中断寄存器
tg3_disable_ints(tp);
//停止网卡收发包
netif_device_detach(dev);
//停止网卡某些硬件,fireware的一些功能
tg3_halt(tp);
//设置网卡的电源状态
tg3_set_power_state(tp, state);
}
static int tg3_resume(struct pci_dev *pdev)
{
//恢复网卡电源
tg3_set_power_state(tp, 0);
//允许网卡收发包
netif_device_attach(dev);
//初始化收发包的缓冲区
tg3_init_rings(tp);
//初始化网卡硬件
tg3_init_hw(tp);
//打开网卡中断寄存器
tg3_enable_ints(tp);
}
13.参数设置
在驱动程序里还提供一些方法供系统对设备的参数进行设置和读取信息。一般只有超级用户(root)权限才能对设备参数进行设置。设置方法有:
tg3_set_mac_addr (dev->set_mac_address)
当用户调用ioctl类型为SIOCSIFHWADDR时是要设置这个设备的mac地址。一般对mac地址的设置没有太大意义的。
dev->set_config()
当用户调用ioctl时类型为SIOCSIFMAP时,系统会调用驱动程序的set_config方法
用户会传递一个ifmap结构包含需要的I/O、中断等参数。
总结:
所有的Linux网络驱动程序遵循通用的接口。设计时采用的是面向对象的方法。一个设备就是一个对象(net_device 结构),它内部有自己的数据和方法。一个网络设备最基本的方法有初始化,发送和接收。
Linux网络驱动程序的体系结构可以划分为四层:
网络协议接口,网络设备接口,设备驱动功能,网络设备和网络媒介层
网络驱动程序,最主要的工作就是完成设备驱动功能层。在Linux中所有网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合。由数据结构struct net_device来表示网络设备在内核中的运行情况,即网络设备接口。它既包括纯软件网络设备接口,如环路(Loopback),也包括硬件网络设备接口,如以太网卡。而由以dev_base为头指针的设备链表来集体管理所有网络设备,该设备链表中的每个元素代表一个网络设备接口。数据结构net_device中有很多供系统访问和协议层调用的设备方法,包括初始化,打开和关闭网络设备的open和stop函数,处理数据包发送的hard_start_xmit函数,以及中断处理函数等。
网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。
5.关闭网络设备
static int tg3_close(struct net_device *dev)
{
//停止网卡传输包
netif_stop_queue(dev);
netif_carrier_off(tp->dev);
//去除定时器
del_timer_sync(&tp->timer);
//释放收包和发包的缓冲区
tg3_free_rings(tp);
//释放中断
free_irq(dev->irq, dev);
}
[NextPage]
6.硬件处理数据包发送
static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
len = (skb->len - skb->data_len);
//以DMA方式向网卡物理设备传输包。如果是wireless的话,需要根据802.11协议及硬件的规范从新填充
//硬件帧头,然后提交给硬件发送。
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
//硬件发送
tg3_set_txd(tp, entry, mapping, len, base_flags, mss_and_is_end);
//记录发包开始时间
dev->trans_start = jiffies;
}
7.中断处理收包,发包
static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
//如果要收包
tg3_rx(tp);
//如果要发包
tg3_tx(tp);
}
8.发包
static void tg3_tx(struct tg3 *tp)
{
struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
struct sk_buff *skb = ri->skb;
//以DMA方式向网卡传输包完毕
pci_unmap_single(tp->pdev, pci_unmap_addr(ri, mapping),
(skb->len - skb->data_len), PCI_DMA_TODEVICE);
ri->skb = NULL;
dev_kfree_skb_irq(skb);
}
9.收包
static int tg3_rx(struct tg3 *tp, int budget)
{
struct sk_buff *copy_skb;
//分配一个包
copy_skb = dev_alloc_skb(len + 2);
copy_skb->dev = tp->dev;
//修改包头空间
skb_reserve(copy_skb, 2);
//加入数据到包中
skb_put(copy_skb, len);
//以DMA方式从网卡传输回数据
pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
memcpy(copy_skb->data, skb->data, len);
skb = copy_skb;
//解析包的协议
skb->protocol = eth_type_trans(skb, tp->dev);
//把包送到协议层
netif_rx(skb);
//记录收包时间
tp->dev->last_rx = jiffies;
}
10.读取包的网卡收发包的状态,统计数据
static struct net_device_stats *tg3_get_stats(struct net_device *dev)
{
//从硬件相关的寄存器读取数据,累加
//stats->rx_packets, stats->tx_packets, stats->rx_bytes, stats->tx_bytes等
}
11.用户的ioctl命令系统调用
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
switch(cmd) {
//ethtool程序命令的调用
case SIO*HTOOL:
return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data);
//mii程序命令的调用
case SIOCGMIIREG: {
err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval)
data->val_out = mii_regval;
return err;
}
……
}
}
12.PCI设备的挂起和恢复函数
static int tg3_suspend(struct pci_dev *pdev, u32 state)
{
//停用网卡的中断寄存器
tg3_disable_ints(tp);
//停止网卡收发包
netif_device_detach(dev);
//停止网卡某些硬件,fireware的一些功能
tg3_halt(tp);
//设置网卡的电源状态
tg3_set_power_state(tp, state);
}
static int tg3_resume(struct pci_dev *pdev)
{
//恢复网卡电源
tg3_set_power_state(tp, 0);
//允许网卡收发包
netif_device_attach(dev);
//初始化收发包的缓冲区
tg3_init_rings(tp);
//初始化网卡硬件
tg3_init_hw(tp);
//打开网卡中断寄存器
tg3_enable_ints(tp);
}
13.参数设置
在驱动程序里还提供一些方法供系统对设备的参数进行设置和读取信息。一般只有超级用户(root)权限才能对设备参数进行设置。设置方法有:
tg3_set_mac_addr (dev->set_mac_address)
当用户调用ioctl类型为SIOCSIFHWADDR时是要设置这个设备的mac地址。一般对mac地址的设置没有太大意义的。
dev->set_config()
当用户调用ioctl时类型为SIOCSIFMAP时,系统会调用驱动程序的set_config方法
用户会传递一个ifmap结构包含需要的I/O、中断等参数。
总结:
所有的Linux网络驱动程序遵循通用的接口。设计时采用的是面向对象的方法。一个设备就是一个对象(net_device 结构),它内部有自己的数据和方法。一个网络设备最基本的方法有初始化,发送和接收。
Linux网络驱动程序的体系结构可以划分为四层:
网络协议接口,网络设备接口,设备驱动功能,网络设备和网络媒介层
网络驱动程序,最主要的工作就是完成设备驱动功能层。在Linux中所有网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合。由数据结构struct net_device来表示网络设备在内核中的运行情况,即网络设备接口。它既包括纯软件网络设备接口,如环路(Loopback),也包括硬件网络设备接口,如以太网卡。而由以dev_base为头指针的设备链表来集体管理所有网络设备,该设备链表中的每个元素代表一个网络设备接口。数据结构net_device中有很多供系统访问和协议层调用的设备方法,包括初始化,打开和关闭网络设备的open和stop函数,处理数据包发送的hard_start_xmit函数,以及中断处理函数等。
网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。
举报