dpdk学习(1)----程序代码创建流程
2018-01-16 16:58
351 查看
关于dpdk的初始化rte_eal_init()有关pcie部分的关系
static struct rte_driver rte_opal_card_driver={
.type=PMD_PDEV,
.init=rte_opal_card_init,
};
PMD_REGISTER_DRIVER(rte_opal_card_driver);
#define PMD_REGISTER_DRIVER(d)\
void devinitfn_ ##d(void);\
void __attribute__((constructor,used)) devinitfn_ ##d(void) \
{\
rte_eal_driver_register(&d);\
}
使用attribute的constructor属性,在MAIN函数执行前,就执行rte_eal_driver_register()函数,将rte_opal_card_driver驱动挂到驱动dev_driver_list(rte_driver_list)链表上。
其中rte_opal_card_init接口是需要用户自己定义的稍后会提起。
rte_eal_init
1、-----rte_eal_dev_init(void)
----TAILQ_FOREACH(driver,&dev_driver_list,next){
if(driver->type!=PMD_PDEV)
continue;
/* PDEV drivers don't get passed any parameters */
driver->init(NULL, NULL);
}
init函数调用的就是rte_opal_card_init(const char *name __rte_unused, const char *params __rte_unused)
{
PMD_DEBUG_TRACE("rte_opal_pmd_init");
rte_eth_driver_register(&rte_opal_pmd);
return (0);
}
rte_opal_pmd结构体定义如下:
static struct eth_driver rte_opal_pmd={
{
.name = "rte_opal_pmd",
.id_table = pci_id_opal_map,
.drv_flags = RTE_PCI_DRV_NEED_MAPPING,//rte_eal_pci_probe(void)中会涉及校验
}
.eth_dev_init = eth_opal_dev_init,
.dev_private_size = sizeof(struct opal_hw),
}
void rte_eth_driver_register(struct eth_driver *eth_drv)
{
eth_drv->pci_drv.devinit = rte_eth_dev_init;
eth_drv->pci_drv.devuninit = rte_eth_dev_uninit;
rte_eal_pci_register(ð_drv->pci_drv);
}
/* register a driver */
void
rte_eal_pci_register(struct rte_pci_driver *driver)
{
TAILQ_INSERT_TAIL(&pci_driver_list, driver, next);
}
追踪至此明白了是将eth_driver驱动 (rte_opal_pmd)注册到pci_driver_list链表中。
2、 ---------int rte_eal_pci_probe(void)
TAILQ_FOREACH(dev,&pci_device_list,next){
pci_probe_all_drivers(dev);
}
在这里将没必要的代码做了删减.
/*
if vendor/device ID match ,call the devinit() function of all registered driver for the given divice.
return -1 if initialization failed ,return 1 if no driver is found for the device
*/
static int pci_probe_all_drivers(struct rte_pci_device *dev )
{
struct rte_pci_driver * dr=NULL;
int rc=0;
if(dev=NULL) return -1;
TAILQ_FOREACH(dr,&pci_driver_list,next){
rc=rte_eal_pci_probe_one_driver(dr,dev);
if(rc<0)
return -1;
if(rc>0)
continue;
return 0;
}
return 1;
}
int rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr,struct rte_pci_device *dev)
{
struct rte_pci_id * id_table;
int ret;
for(id_table=dr->id_table;id_table->vendor_id != 0; id_table++){
if(id_table->vendor_id!=dev->id.vendor_id&&
id_table->vendor_id!=PCI_ANY_ID)
continue;
if(id_table->device_id!=dev->id.device_id&&
id_table->device_id!=PCI_ANY_ID)
continue;
if(id_table->subsystem_vendor_id!=dev->id.subsystem_vendor_id &&
id_table->subsystem_vendor_id!=PCI_ANY_ID)
continue;
if(id_table->subsystem_vendor_id!=dev->id.subsystem_vendor_id &&
id_table->subsystem_vendor_id!=PCI_ANY_ID)
continue;
struct rte_pci_addr * loc=&dev->addr;
if(dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING){
ret=pci_uio_map_resource(dev);
if(ret!=0)
teturn ret;
}else if(dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
rte_eal_process_type()==RTE_PROC_PRIMARY){
if(pci_unbind_kernel_driver(dev)<0)
return -1;
}
dev->driver=dr;
return dr->devinit(dr,dev);
}
return 1;
}
在这里最后会调用dr->devinit(dr,dev);调用static int rte_eth_dev_init(struct rte_pci_driver *pci_drv,
struct rte_pci_device *pci_dev)
到这个位置可以总结一下。注册一个网卡驱动(poll mode)函数被一个以太网驱动程序的初始化函数调用同时注册本身作为PCI驱动程序和一个以太网调查模式驱动程序
调用rte_eal_pci_register()函数注册pci_drv结构体被嵌入到eth_drv结构中。rte_eth_dev_init()函数的地址被挂载在pci_drv的devinit域中
在PCI probe过程中,rte_eth_dev_init()函数被每个匹配的嵌入式PCI驱动程序提供的标识符调用
static int rte_eth_dev_init(struct rte_pci_driver *pci_drv,struct rte_pci_device *pci_dev)
{
struct eth_driver *eth_drv;
struct rte_eth_dev *eth_dev;
char ethdev_name[RTE_ETH_NAME_MAX_LEN];
int diag;
eth_drv = (struct eth_driver *)pci_drv;
/* Create unique Ethernet device name using PCI address */
rte_eth_dev_create_unique_device_name(ethdev_name,
sizeof(ethdev_name), pci_dev);
eth_dev = rte_eth_dev_allocate(ethdev_name, RTE_ETH_DEV_PCI);
if (eth_dev == NULL)
return -ENOMEM;
if (rte_eal_process_type() == RTE_PROC_PRIMARY){
eth_dev->data->dev_private = rte_zmalloc("ethdev private structure",
eth_drv->dev_private_size,
RTE_CACHE_LINE_SIZE);
if (eth_dev->data->dev_private == NULL)
rte_panic("Cannot allocate memzone for private port data\n");
}
eth_dev->pci_dev = pci_dev;
eth_dev->driver = eth_drv;
eth_dev->data->rx_mbuf_alloc_failed = 0;
/* init user callbacks */
TAILQ_INIT(&(eth_dev->link_intr_cbs));
/*
* Set the default MTU.
*/
eth_dev->data->mtu = ETHER_MTU;
/* Invoke PMD device initialization function */
diag = (*eth_drv->eth_dev_init)(eth_dev);
if (diag == 0)
return (0);
PMD_DEBUG_TRACE("driver %s: eth_dev_init(vendor_id=0x%u device_id=0x%x)"
" failed\n", pci_drv->name,
(unsigned) pci_dev->id.vendor_id,
(unsigned) pci_dev->id.device_id);
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
rte_free(eth_dev->data->dev_private);
eth_dev->attached = DEV_DETACHED;
nb_ports--;
return diag;
}
到达这个位置就会调用diag = (*eth_drv->eth_dev_init)(eth_dev);即eth_opal_dev_init接口,这个接口需要用户自己定义和实现
static struct rte_driver rte_opal_card_driver={
.type=PMD_PDEV,
.init=rte_opal_card_init,
};
PMD_REGISTER_DRIVER(rte_opal_card_driver);
#define PMD_REGISTER_DRIVER(d)\
void devinitfn_ ##d(void);\
void __attribute__((constructor,used)) devinitfn_ ##d(void) \
{\
rte_eal_driver_register(&d);\
}
使用attribute的constructor属性,在MAIN函数执行前,就执行rte_eal_driver_register()函数,将rte_opal_card_driver驱动挂到驱动dev_driver_list(rte_driver_list)链表上。
其中rte_opal_card_init接口是需要用户自己定义的稍后会提起。
rte_eal_init
1、-----rte_eal_dev_init(void)
----TAILQ_FOREACH(driver,&dev_driver_list,next){
if(driver->type!=PMD_PDEV)
continue;
/* PDEV drivers don't get passed any parameters */
driver->init(NULL, NULL);
}
init函数调用的就是rte_opal_card_init(const char *name __rte_unused, const char *params __rte_unused)
{
PMD_DEBUG_TRACE("rte_opal_pmd_init");
rte_eth_driver_register(&rte_opal_pmd);
return (0);
}
rte_opal_pmd结构体定义如下:
static struct eth_driver rte_opal_pmd={
{
.name = "rte_opal_pmd",
.id_table = pci_id_opal_map,
.drv_flags = RTE_PCI_DRV_NEED_MAPPING,//rte_eal_pci_probe(void)中会涉及校验
}
.eth_dev_init = eth_opal_dev_init,
.dev_private_size = sizeof(struct opal_hw),
}
void rte_eth_driver_register(struct eth_driver *eth_drv)
{
eth_drv->pci_drv.devinit = rte_eth_dev_init;
eth_drv->pci_drv.devuninit = rte_eth_dev_uninit;
rte_eal_pci_register(ð_drv->pci_drv);
}
/* register a driver */
void
rte_eal_pci_register(struct rte_pci_driver *driver)
{
TAILQ_INSERT_TAIL(&pci_driver_list, driver, next);
}
追踪至此明白了是将eth_driver驱动 (rte_opal_pmd)注册到pci_driver_list链表中。
2、 ---------int rte_eal_pci_probe(void)
TAILQ_FOREACH(dev,&pci_device_list,next){
pci_probe_all_drivers(dev);
}
在这里将没必要的代码做了删减.
/*
if vendor/device ID match ,call the devinit() function of all registered driver for the given divice.
return -1 if initialization failed ,return 1 if no driver is found for the device
*/
static int pci_probe_all_drivers(struct rte_pci_device *dev )
{
struct rte_pci_driver * dr=NULL;
int rc=0;
if(dev=NULL) return -1;
TAILQ_FOREACH(dr,&pci_driver_list,next){
rc=rte_eal_pci_probe_one_driver(dr,dev);
if(rc<0)
return -1;
if(rc>0)
continue;
return 0;
}
return 1;
}
int rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr,struct rte_pci_device *dev)
{
struct rte_pci_id * id_table;
int ret;
for(id_table=dr->id_table;id_table->vendor_id != 0; id_table++){
if(id_table->vendor_id!=dev->id.vendor_id&&
id_table->vendor_id!=PCI_ANY_ID)
continue;
if(id_table->device_id!=dev->id.device_id&&
id_table->device_id!=PCI_ANY_ID)
continue;
if(id_table->subsystem_vendor_id!=dev->id.subsystem_vendor_id &&
id_table->subsystem_vendor_id!=PCI_ANY_ID)
continue;
if(id_table->subsystem_vendor_id!=dev->id.subsystem_vendor_id &&
id_table->subsystem_vendor_id!=PCI_ANY_ID)
continue;
struct rte_pci_addr * loc=&dev->addr;
if(dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING){
ret=pci_uio_map_resource(dev);
if(ret!=0)
teturn ret;
}else if(dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
rte_eal_process_type()==RTE_PROC_PRIMARY){
if(pci_unbind_kernel_driver(dev)<0)
return -1;
}
dev->driver=dr;
return dr->devinit(dr,dev);
}
return 1;
}
在这里最后会调用dr->devinit(dr,dev);调用static int rte_eth_dev_init(struct rte_pci_driver *pci_drv,
struct rte_pci_device *pci_dev)
到这个位置可以总结一下。注册一个网卡驱动(poll mode)函数被一个以太网驱动程序的初始化函数调用同时注册本身作为PCI驱动程序和一个以太网调查模式驱动程序
调用rte_eal_pci_register()函数注册pci_drv结构体被嵌入到eth_drv结构中。rte_eth_dev_init()函数的地址被挂载在pci_drv的devinit域中
在PCI probe过程中,rte_eth_dev_init()函数被每个匹配的嵌入式PCI驱动程序提供的标识符调用
static int rte_eth_dev_init(struct rte_pci_driver *pci_drv,struct rte_pci_device *pci_dev)
{
struct eth_driver *eth_drv;
struct rte_eth_dev *eth_dev;
char ethdev_name[RTE_ETH_NAME_MAX_LEN];
int diag;
eth_drv = (struct eth_driver *)pci_drv;
/* Create unique Ethernet device name using PCI address */
rte_eth_dev_create_unique_device_name(ethdev_name,
sizeof(ethdev_name), pci_dev);
eth_dev = rte_eth_dev_allocate(ethdev_name, RTE_ETH_DEV_PCI);
if (eth_dev == NULL)
return -ENOMEM;
if (rte_eal_process_type() == RTE_PROC_PRIMARY){
eth_dev->data->dev_private = rte_zmalloc("ethdev private structure",
eth_drv->dev_private_size,
RTE_CACHE_LINE_SIZE);
if (eth_dev->data->dev_private == NULL)
rte_panic("Cannot allocate memzone for private port data\n");
}
eth_dev->pci_dev = pci_dev;
eth_dev->driver = eth_drv;
eth_dev->data->rx_mbuf_alloc_failed = 0;
/* init user callbacks */
TAILQ_INIT(&(eth_dev->link_intr_cbs));
/*
* Set the default MTU.
*/
eth_dev->data->mtu = ETHER_MTU;
/* Invoke PMD device initialization function */
diag = (*eth_drv->eth_dev_init)(eth_dev);
if (diag == 0)
return (0);
PMD_DEBUG_TRACE("driver %s: eth_dev_init(vendor_id=0x%u device_id=0x%x)"
" failed\n", pci_drv->name,
(unsigned) pci_dev->id.vendor_id,
(unsigned) pci_dev->id.device_id);
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
rte_free(eth_dev->data->dev_private);
eth_dev->attached = DEV_DETACHED;
nb_ports--;
return diag;
}
到达这个位置就会调用diag = (*eth_drv->eth_dev_init)(eth_dev);即eth_opal_dev_init接口,这个接口需要用户自己定义和实现
相关文章推荐
- 高级应用Magento-订单创建流程及程序代码
- 程序流程代码练习
- nova组件、架构、代码目录以及创建虚拟机流程
- 让在vc6创建的程序中,控件可以随xp风格的改变而变化,不用再程序中添加代码来自己实现~
- MFC中SDI程序创建流程的回顾
- 2013 Mac Air 装Win7双系统问题-安装程序无法创建新的分区,也无法定位系统 & Windows无法安装所需的文件,错误代码0x80070570
- [转]C# 2.0:使用匿名方法、迭代程序和局部类来创建优雅的代码
- ceph的pool创建流程--代码分析
- windows程序窗体创建流程模型A--利用基本数据类型
- 通过heat创建stack的代码流程分析heat stack-create
- Linux下时间范围判断的程序流程及其C代码实现
- Linux下合并前缀相同的文件的程序流程及其C代码实现
- c#通过纯代码创建桌面快捷方式、创建程序菜单项、将网页添加到收藏夹
- 程序执行流程 + 控制器/控制器View创建流程
- socket创建流程及代码示例
- 《机器学习实战》程序清单3-4 创建树的函数代码
- 微信小程序中的微信支付js代码和流程详解
- MFC中SDI程序创建流程的回顾
- openssl主要流程程序代码
- OpenGL 一般程序创建流程