您的位置:首页 > 编程语言

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接口,这个接口需要用户自己定义和实现
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: