rte_log_set_global_level
rte_log_set_global_level(uint32_t level)
pci bus注册
TE_REGISTER_BUS(pci, rte_pci_bus.bus); drivers/bus/pci/pci_common.c ,注册静态的设置rte_pci_bus,在rte_pci_bus中设置了pci bus的各个回调函数
struct rte_pci_bus rte_pci_bus = {.bus = {.scan = rte_pci_scan,.probe = rte_pci_probe, .find_device = pci_find_device,.plug = pci_plug,.unplug = pci_unplug,.parse = pci_parse,.get_iommu_class = rte_pci_get_iommu_class,.dev_iterate = rte_pci_dev_iterate,.hot_unplug_handler = pci_hot_unplug_handler,.sigbus_handler = pci_sigbus_handler,},.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
}; RTE_REGISTER_BUS(pci, rte_pci_bus.bus);
TE_REGISTER_BUS的定义如下:
//
/*** Helper for Bus registration.* The constructor has higher priority than PMD constructors.*/
#define RTE_REGISTER_BUS(nm, bus) \
RTE_INIT_PRIO(businitfn_ ##nm, BUS) \
{\(bus).name = RTE_STR(nm);\rte_bus_register(&bus); \
}
设置了bus name并调用rte_bus_register注册总线
RTE_INIT_PRIO、TE_INIT的定义为:
//rte_common.h:::
/*** Run function before main() with high priority.** @param func* Constructor function.* @param prio* Priority number must be above 100.* Lowest number is the first to run.*/
#define RTE_INIT_PRIO(func, prio) \
static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)/*** Run function before main() with low priority.** The constructor will be run after prioritized constructors.** @param func* Constructor function.*/
#define RTE_INIT(func) \RTE_INIT_PRIO(func, LAST)
设置了constructor属性,这些函数会在main函数之前执行,prio为优先级,优先级高的constructor函数会被先执行,以下是dpdk优先级的一些定义
//dpdk-stable/lib/librte_eal/common/include/rte_common.h
#define RTE_PRIORITY_LOG 101
#define RTE_PRIORITY_BUS 110
#define RTE_PRIORITY_CLASS 120
#define RTE_PRIORITY_LAST 65535
可以看出dpdk log的相关初始化最先被执行
对于rte_bus_register,会检测被注册的总线必要的回调函数是否存在,然后将buf添加到rte_bus_list
void
rte_bus_register(struct rte_bus *bus)
{RTE_VERIFY(bus);RTE_VERIFY(bus->name && strlen(bus->name));/* A bus should mandatorily have the scan implemented */RTE_VERIFY(bus->scan);RTE_VERIFY(bus->probe);RTE_VERIFY(bus->find_device);/* Buses supporting driver plug also require unplug. */RTE_VERIFY(!bus->plug || bus->unplug);TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);RTE_LOG(DEBUG, EAL, "Registered [%s] bus.\n", bus->name);
}
驱动注册
RTE_PMD_REGISTER_PCI(net_ixgbe, rte_ixgbe_pmd);
net_ixgbe 为驱动名字,rte_ixgbe_pmd结构体是对被注册driver的描述
/** Helper for PCI device registration from driver (eth, crypto) instance */#define RTE_PMD_REGISTER_PCI(nm, pci_drv) \RTE_INIT(pciinitfn_ ##nm) \
{\(pci_drv).driver.name = RTE_STR(nm);\rte_pci_register(&pci_drv); \
} \
对于rte_pci_register,
void
rte_pci_register(struct rte_pci_driver *driver)
{//添加driver到listTAILQ_INSERT_TAIL(&rte_pci_bus.driver_list, driver, next);//rte_pci_bus为全局变量driver->bus = &rte_pci_bus;
}
将驱动添加到对应的总线的driver_list。我们在看看rte_ixgbe_pmd 结构体
static struct rte_pci_driver rte_ixgbe_pmd = {.id_table = pci_id_ixgbe_map,.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,.probe = eth_ixgbe_pci_probe,.remove = eth_ixgbe_pci_remove,
};
结构体中,pci_id_ixgbe_map描述了driver支持的设备,并设置了probe、remove回调函数,在后续会扫描PCI总线上的device,并对调用rte_pci_match(dr, dev)检测device、driver匹配,匹配则进一步调用driver的probe函数。
device扫描
#0 rte_pci_scan () at dpdk-stable/drivers/bus/pci/linux/pci.c:464
#1 rte_bus_scan () at dpdk-stable/lib/librte_eal/common/eal_common_bus.c:78
#2 rte_eal_init (argc=argc@entry=10, argv=argv@entry=0xffffff31a8) at dpdk-stable/lib/librte_eal/linuxapp/eal/eal.c:1028
#3 main (argc=<optimized out>, argv=0xffffff31a8) at dpdk-stable/app/test-pmd/testpmd.c:3124
在rte_bus_scan函数中会遍历rte_bus_list,并调用每个bus注册的scan回调函数,对于本文例子就是rte_pci_scan()函数。rte_pci_scan 会遍历系统中的device设,备,并将device信息填充到rte_pci_device,最后调用pci_scan_one–>rte_pci_add_device 将device添加到rte_pci_bus.device_list
driver初始化
#0 eth_ixgbe_pci_probe () at dpdk-stable/drivers/net/ixgbe/ixgbe_ethdev.c:1799
#1 rte_pci_probe_one_driver () at dpdk-stable/drivers/bus/pci/pci_common.c:199
#2 pci_probe_all_drivers () at dpdk-stable/drivers/bus/pci/pci_common.c:273
#3 rte_pci_probe () at dpdk-stable/drivers/bus/pci/pci_common.c:308
#4 rte_bus_probe () at dpdk-stable/lib/librte_eal/common/eal_common_bus.c:100
#5 rte_eal_init () at dpdk-stable/lib/librte_eal/linuxapp/eal/eal.c:1213
在device和driver都安放好后就要开始初始化,对于PCI总线上的设备,会在rte_pci_probe遍历rte_pci_bus.device_list,对每个device调用 pci_probe_all_drivers()函数,并在函数中遍历rte_pci_bus.driver_list,使用rte_pci_match(dr, dev) 判断device和driver是否匹配,匹配则调用driver的probe。
以下是对这个过程的简化代码
FOREACH_DEVICE_ON_PCIBUS(dev){FOREACH_DRIVER_ON_PCIBUS(dr)if (!rte_pci_match(dr, dev))return 1;probe_driver();
}
by:junchao_zhao@yeah.net