原创文章,转载请注明: 转载自pagefault
本文链接地址: intel万兆网卡驱动简要分析
这里分析的驱动代码是给予linux kernel 3.4.4
对应的文件在drivers/net/ethernet/intel 目录下,这个分析不涉及到很细节的地方,主要目的是理解下数据在协议栈和驱动之间是如何交互的。
首先我们知道网卡都是pci设备,因此这里每个网卡驱动其实就是一个pci驱动。并且intel这里是把好几个万兆网卡(82599/82598/x540)的驱动做在一起的。
首先我们来看对应的pci_driver的结构体,这里每个pci驱动都是一个pci_driver的结构体,而这里是多个万兆网卡共用这个结构体ixgbe_driver.
1
2
3
4
5
6
7
8
9
10
11
12
|
static
struct
pci_driver ixgbe_driver = {
.name = ixgbe_driver_name,
.id_table = ixgbe_pci_tbl,
.probe = ixgbe_probe,
.
remove
= __devexit_p(ixgbe_remove),
#ifdef CONFIG_PM
.suspend = ixgbe_suspend,
.resume = ixgbe_resume,
#endif
.shutdown = ixgbe_shutdown,
.err_handler = &ixgbe_err_handler
};
|
然后是模块初始化方法,这里其实很简单,就是调用pci的驱动注册方法,把ixgbe挂载到pci设备链中。 这里不对pci设备的初始化做太多介绍,我以前的blog有这方面的介绍,想了解的可以去看看。这里我们只需要知道最终内核会调用probe回调来初始化ixgbe。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
char
ixgbe_driver_name[] =
"ixgbe"
;
static
const
char
ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver"
;
static
int
__init ixgbe_init_module(
void
)
{
int
ret;
pr_info(
"%s - version %s\n"
, ixgbe_driver_string, ixgbe_driver_version);
pr_info(
"%s\n"
, ixgbe_copyright);
#ifdef CONFIG_IXGBE_DCA
dca_register_notify(&dca_notifier);
#endif
ret = pci_register_driver(&ixgbe_driver);
return
ret;
}
|
这里不去追究具体如何调用probe的细节,我们直接来看probe函数,这个函数中通过硬件的信息来确定需要初始化那个驱动(82598/82599/x540),然后核心的驱动结构就放在下面的这个数组中。
1
2
3
4
5
|
static
const
struct
ixgbe_info *ixgbe_info_tbl[] = {
[board_82598] = &ixgbe_82598_info,
[board_82599] = &ixgbe_82599_info,
[board_X540] = &ixgbe_X540_info,
};
|
ixgbe_probe函数很长,我们这里就不详细分析了,因为这部分就是对网卡进行初始化。不过我们关注下面几个代码片段。
首先是根据硬件的参数来取得对应的驱动值:
1
|
const
struct
ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
|
然后就是如何将不同的网卡驱动挂载到对应的回调中,这里做的很简单,就是通过对应的netdev的结构取得adapter,然后所有的核心操作都是保存在adapter中的,最后将ii的所有回调拷贝给adapter就可以了。我们来看代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
struct
net_device *netdev;
struct
ixgbe_adapter *adapter = NULL;
|