`
isiqi
  • 浏览: 16555815 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Tg3 Gbit NIC Driver Analysis

阅读更多
1, 驱动模块的加载和卸载
如果网络设备(包括wireless)是PCI规范的,则先是向内核注册该PCI设备(pci_register_driver),然后由pci_driver数据结构中的probe函数指针所指向的侦测函数来初始化该PCI设备,并且同时注册和初始化该网络设备。
如果网络设备(包括wireless)是PCMCIA规范的,则先是向内核注册该PCMCIA设备(register_pccard_driver),然后driver_info_t数据结构中的attach函数指针所指向的侦测函数来初始化该PCMCIA设备,并且同时注册和初始化该网络设备。

static int __init tg3_init(void)
{
//先注册成PCI设备,并初始化,如果是其他的ESIA,PCMCIA,用其他函数
return pci_module_init(&tg3_driver);
}

static void __exit tg3_cleanup(void)
{
pci_unregister_driver(&tg3_driver);//注销PCI设备
}

module_init(tg3_init); //驱动模块的加载
module_exit(tg3_cleanup); //驱动模块的卸载

申明为PCI设备:
static struct pci_driver tg3_driver = {
.name = DRV_MODULE_NAME,
.id_table = tg3_pci_tbl, //此驱动所支持的网卡系列,vendor_id, device_id
.probe = tg3_init_one, //初始化网络设备的回调函数
.remove = __devexit_p(tg3_remove_one), //注销网络设备的回调函数
.suspend = tg3_suspend, //设备挂起函数
.resume = tg3_resume //设备恢复函数
};

2,PCI设备探测函数probe,初始化网络设备
static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
//初始化设备,使I/O,memory可用,唤醒设备
pci_enable_device(pdev);
//申请内存空间,配置网卡的I/O,memory资源
pci_request_regions(pdev, DRV_MODULE_NAME);
pci_set_master(pdev);
//设置DMA属性
pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff);
//网卡 I/O,memory资源的启始地址
tg3reg_base = pci_resource_start(pdev, 0);
//网卡I/O,memory资源的大小
tg3reg_len = pci_resource_len(pdev, 0);
//分配并设置网络设备
dev = alloc_etherdev(sizeof(*tp));
//申明为内核设备模块
SET_MODULE_OWNER(dev);
//初始化私有结构中的各成员值
tp = dev->priv;
tp->pdev = pdev;
tp->dev = dev;
……
//锁的初始化
spin_lock_init(&tp->lock);
//映射I/O,memory地址到私有域中的寄存器结构
tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
dev->irq = pdev->irq;
//网络设备回调函数赋值
dev->open = tg3_open;
dev->stop = tg3_close;
dev->get_stats = tg3_get_stats;
dev->set_multicast_list = tg3_set_rx_mode;
dev->set_mac_address = tg3_set_mac_addr;
dev->do_ioctl = tg3_ioctl;
dev->tx_timeout = tg3_tx_timeout;
dev->hard_start_xmit= tg3_start_xmit;
//网卡的MAC地址赋值dev->addr
tg3_get_device_address(tp);
//注册网络设备
register_netdev(dev);
//把网络设备指针地址放入PCI设备中的设备指针中
pci_set_drvdata(pdev, dev);
}

3,注销网络设备
static void __devexit tg3_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
//注销网络设备
unregister_netdev(dev);
//取消地址映射
iounmap((void *) ((struct tg3 *)(dev->priv))->regs);
//释放网络设备
kfree(dev);
//释放PCI资源
pci_release_regions(pdev);
//停用PCI设备
pci_disable_device(pdev);
//PCI设备中的设备指针赋空
pci_set_drvdata(pdev, NULL);
}

4,打开网络设备
static int tg3_open(struct net_device *dev)
{
//分配一个中断
request_irq(dev->irq, tg3_interrupt, SA_SHIRQ, dev->name, dev);
/* int request_irq(unsigned int irq,
void (*handler)(int irq, void *dev_id, struct pt_regs *regs),
unsigned long irqflags,
const char * devname,
void *dev_id);
irq是要申请的硬件中断号。在Intel平台,范围0--15。handler是向系统登记的中断处理函数。这是一个回调函数,中断发生时,系统调用这个函数,传入的参数包括硬件中断号,device id,寄存器值。dev_id就是下面的request_irq时传递给系统的参数dev_id。irqflags是中断处理的一些属性。比较重要的有SA_INTERRUPT,标明中断处理程序是快速处理程序(设置SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT)。快速处理程序被调用时屏蔽所有中断。慢速处理程序不屏蔽。还有一个SA_SHIRQ属性,设置了以后运行多个设备共享中断。dev_id在中断共享时会用到。一般设置为这个设备的device结构本身或者NULL。中断处理程序可以用dev_id找到相应的控制这个中断的设备,或者用rq2dev_map找到中断对应的设备。*/
//初始化硬件
tg3_init_hw(tp);
//初始化收包和发包的缓冲区
tg3_init_rings(tp);
//初始化定时器
init_timer(&tp->timer);
tp->timer.expires = jiffies + tp->timer_offset;
tp->timer.data = (unsigned long) tp;
tp->timer.function = tg3_timer; //超时回调函数
add_timer(&tp->timer);
//允许网卡开始传输包
netif_start_queue(dev);
}

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);
}

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 SIOCETHTOOL:
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)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。
分享到:
评论

相关推荐

    DDR3 2Gbit

    DDR3 SDRAM uses a double data rate architecture to achieve high-speed operation. The double data rate architecture is an 8n-prefetch architecture with an interface de- signed to transfer two data ...

    ixy:从头开始编写的用于Intel 10 Gbit NIC的简单而快速的用户空间网络驱动程序

    ixy-1000行代码中的用户空间网络驱动程序ixy是一个简单的用户空间数据包处理框架。 它需要对网络适配器的独占控制,并在用户空间中实现整个驱动程序。 它的体系结构与和相似,并且与(似乎相似)netmap,pfq,pf_...

    博科4Gbit/sec助力波兰最大电子商务网站

    在这个案例中,博科4Gbit/sec技术在波兰最大的电子商务网站allegro的存储区域网络(SAN)整合项目中发挥了重要作用。allegro选择博科,主要是看中了其4Gbit/sec技术的广泛验证和IBM提供的出色OEM支持,这确保了新...

    YDT 2402.1-2012 接入网技术要求 10Gbit∕s无源光网络(XG-PON) 第3部分.pdf

    YDT 2402.1-2012 接入网技术要求 10Gbit/s 无源光网络(XG-PON) 第3部分 本文档为 YDT 2402.1-2012 标准的第 3 部分,主要规定了 10Gbit/s 无源光网络(XG-PON)的技术要求。XG-PON 是一种基于无源光网络的接入网...

    YDT 2804.2-2015 40Gbit∕s∕100Gbit∕s强度调制可插拔光收发合一模块 第2部分:4×25Gbit∕s.pdf

    根据给定文件信息,该文件标题为《YDT 2804.2-2015 40Gbit/s/100Gbit/s强度调制可插拔光收发合一模块 第2部分:4×25Gbit/s.pdf》,并带有“光模块”的标签。尽管提供的部分内容是重复的无效网址,并没有提供实际的...

    支持40 Gbit_s路由器的传输技术研究.pdf

    《支持40 Gbit/s路由器的传输技术研究》 在当今信息化社会,互联网的快速发展对网络设备的性能提出了更高的要求。核心路由器作为网络中的关键节点,其传输速度直接影响到整个网络的运行效率。本文主要探讨了支持40 ...

    40 Gbit/s 光纤通信系统的光放和色散管理研究.pdf

    本文以40 Gbit/s光纤通信系统为背景,重点研究了光放大技术和色散管理两个关键领域的发展和应用。40 Gbit/s光纤通信系统的出现,代表着数据传输速率的显著提升,同时对光放大器和色散管理提出了更高要求。 在光纤...

    10Gbit_sEPON对称OLT光模块的设计.pdf

    802.3av 协议的要求,1.25Gbit/s 突发接收的建立时间必须 μs。为了满足这个要求,本文设计了一种特殊的接收电路,能够快速地建立接收,提高灵敏度。实验结果表明,该模块在突发接收条件下的接收建立时间和灵敏度均...

    PMC推出100Gbit_s OTN芯片助力大数据时代光网络带宽虚拟化.pdf

    PMC推出100Gbit_s OTN芯片助力大数据时代光网络带宽虚拟化.pdf

    高速40Gbit_sWDM的发展

    【高速40Gbit/s WDM技术概述】 随着信息技术的飞速发展,尤其是大数据业务对骨干网络带宽需求的激增,高速WDM(波分复用)技术逐渐成为业界焦点。从2.5 Gbit/s和10 Gbit/s的广泛应用,到40 Gbit/s WDM的快速发展,...

    Marvell FastLinQ Edge Network Adapter Drivers Version 3.1.7.0 WH

    AQtion AQC107 AQtion AQC107S AQtion AQC108 AQC108S AQtion AQC109 AQtion AQC109S AQtion AQC100 AQtion AQC100S AQtion AQC111 AQTion AQC111C AQtion AQC111S ...AQtion AQC112C AQtion AQC112C...SANLink3 N1 10Gbit

    用HIFN5NP4GS3网络处理器设计8Gbit_s线速路由器.pdf

    用HIFN5NP4GS3网络处理器设计8Gbit_s线速路由器.pdf

    40Gbit-s高速光传输技术的应用与挑战宣贯.pdf

    40Gbit/s高速光传输技术是应对互联网流量急剧增长的解决方案,特别是在骨干IP网络核心路由器的高速互联和超级计算机或数据中心之间的高速连接方面。这一技术的发展源于互联网业务和技术的繁荣,尤其是近几年来数据...

    10Gbit/s XFP光模块的设计.pdf

    3. 密集波分光通信模块:基于标准化的密集波分光通信模块成为其必不可少的一部分,10Gbit/s XFP光模块以其价格低、体积小和应用环境广泛等优点,已经成为主流产品。 应用前景 1. 光网络系统:该模块可应用于光网络...

    IP v6学习-OSPFv3实验(基于eNSP)

    OSPFv3是一种用于IPv6网络的开放式最短路径优先(OSPF)路由协议。它是OSPFv2协议的扩展版本,专门设计用于支持IPv6协议栈。OSPFv3在IPv6环境下提供了强大的路由功能,允许网络管理员有效地管理复杂的IPv6网络拓扑...

    用于以太网的40Gbit_sCFP光模块设计.pdf

    【部分内容】: 40Gbit/s CFP光模块由发射单元、接收单元和控制单元构成,遵循IEEE 802.3ba标准,利用CWDM技术实现在单模光纤上的长距离传输。此模块旨在满足40Gbps以太网的应用要求。 详细内容: 40Gbit/s CFP光...

    marvell_aqtion网卡最新驱动

    marvell_aqtion网卡驱动固件3.1.6.0 ... AQtion AQN-108Aquantia AQtion 10Gbit Network Adapter Aquantia AQtion 5Gbit Network Adapter Aquantia AQtion 2.5Gbit Network Adapter Aquantia Felici

    NAND FLASH 资料 1GBIT

    本资料介绍的是镁光(Micron)生产的1GBit NAND Flash存储器的数据手册,型号包括NAND01GR3B2C、NAND01GW3B2C、NAND01GR4B2C以及NAND01GW4B2C。这些器件均为单层单元(Single Level Cell, SLC)NAND Flash存储器,...

Global site tag (gtag.js) - Google Analytics