DPDK学习记录5 - eth dev初始化1之before main

在main函数运行之前,通过gcc的构造函数,完成总线到链表中的注册,且完成各种pmd驱动到某类总线的注册,完成几类全局变量的数据关系。本文以pci总线和em pmd驱动为例。

1 gcc的构造函数 - constructor属性

gcc的constructor函数属性,可以让该函数在main函数之前运行,且可以指定函数运行的优先级,优先级>100,且值越小优先级越高。

ether dev初始化用到的是RTE_PRIORITY_BUS这个level的优先级。

另一个used的意思是,即使函数未被使用也不会被优化掉。

/**
 * 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)

#define RTE_PRIORITY_LOG 101
#define RTE_PRIORITY_BUS 110
#define RTE_PRIORITY_CLASS 120
#define RTE_PRIORITY_LAST 65535

#define RTE_PRIO(prio) \
	RTE_PRIORITY_ ## prio        //##为连接符号

2 rte_bus_register

以PCI总线为例,把pci总线的全局变量rte_pci_bus,加入总线链表全局变量rte_bus_list的一个过程。

2.1 businitfn_pci 构造函数声明

#define RTE_REGISTER_BUS(nm, bus) \
RTE_INIT_PRIO(businitfn_ ##nm, BUS) \
{\
	(bus).name = RTE_STR(nm);\
	rte_bus_register(&bus); \
}  

RTE_REGISTER_BUS(pci, rte_pci_bus.bus);   ==> 等同于声明一个gcc的构造函数 businitfn_pci
static void __attribute__((constructor(110), used)) businitfn_pci(void)
{
	rte_pci_bus.bus.name = RTE_STR(pci);
	rte_bus_register(&rte_pci_bus.bus); 
}

//全局变量 rte_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),
};

2.2 rte_bus_register函数

2.2.1 struct rte_bus_list 链表结构体的定义

dpdk中对bus总线链表结构体的定义:TAILQ_HEAD(rte_bus_list, rte_bus); 其中rte_bus_list为新定义的链表结构体的名字,rte_bus为链表中元素的类型。

TAILQ的使用,需要包含linux系统头文件:#include <sys/queue.h>

在sys/queue.h中

#define TAILQ_HEAD(name, type)                \
struct name {                                 \
    struct type *tqh_first;       \
    struct type **tqh_last;       \  
}

2.2.2 定义全局变量rte_bus_list

用上面定义的链表结构体,定义一个同名的全局变量

static struct rte_bus_list rte_bus_list =
	TAILQ_HEAD_INITIALIZER(rte_bus_list);

2.2.3 businitfn_pci 构造函数中完成链表insert

运行rte_bus_register(&rte_pci_bus.bus); 则是把rte_pci_bus.bus加入到链表全局变量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);
}

3. PMD driver注册到rte_pci_bus的driver list中

目标是要在rte_pci_bus.driver_list 链表中加入PMD driver,以net_e1000_em驱动为例。

3.1 声明gcc的构造函数 pciinitfn_net_e1000_em — 优先级最低

#define RTE_INIT(func) \
	RTE_INIT_PRIO(func, LAST)

#define RTE_INIT_PRIO(func, prio) \
static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)

#define RTE_PRIORITY_LAST 65535

#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_PMD_EXPORT_NAME(nm, __COUNTER__)

RTE_PMD_REGISTER_PCI(net_e1000_em, rte_em_pmd);
//=====> 等同于声明一个函数如下:
static void __attribute__((constructor(65535), used)) pciinitfn_net_e1000_em (void)
{
	rte_em_pmd.driver.name = RTE_STR(net_e1000_em);
	rte_pci_register(&rte_em_pmd);
}

3.2 rte_pci_register(&rte_em_pmd)

把pci pmd的全局变量rte_em_pmd挂到另一个全局变量rte_pci_bus.driver_list上。

//定义em pmd全局变量
static struct rte_pci_driver rte_em_pmd = {
	.id_table = pci_id_em_map,
	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
		     RTE_PCI_DRV_IOVA_AS_VA,
	.probe = eth_em_pci_probe,
	.remove = eth_em_pci_remove,
};

struct rte_pci_driver {
	TAILQ_ENTRY(rte_pci_driver) next;  /**< Next in list. */
	struct rte_driver driver;          /**< Inherit core driver. */ //从哪里继承?
	struct rte_pci_bus *bus;           /**< PCI bus reference. */  //反向指回总线变量
	pci_probe_t *probe;                /**< Device Probe function. */
	pci_remove_t *remove;              /**< Device Remove function. */
	const struct rte_pci_id *id_table; /**< ID table, NULL terminated. */
	uint32_t drv_flags;                /**< Flags RTE_PCI_DRV_*. */
};

/* register driver */
void rte_pci_register(struct rte_pci_driver *rte_em_pmd)
{
	TAILQ_INSERT_TAIL(&rte_pci_bus.driver_list, rte_em_pmd, next);
	rte_em_pmd->bus = &rte_pci_bus;
}

4. gdb调试结果

4.1 run之前打了4个断点,分别如下。run之后businitfn_pci函数被断住
在这里插入图片描述

4.2
接着断在rte_bus_register,rte_bus_list变量在insert前后发生变化。
在这里插入图片描述

4.3
continue之后,除了pci总线,还是其他如dpaa/vmbus/ifpga等总线也相继断住且挂到rte_bus_list链上。
在这里插入图片描述

4.4
接着continue之后,断在rte_pci_register函数,处理各种pmd驱动挂到rte_pci_bus.driver_list链中的过程。
在这里插入图片描述
可以看到Breakpoint 3也断住了,正是注册em PMD驱动到rte_pci_bus.driver_list链中的过程。
在这里插入图片描述

5. 示意图

至此,在main函数运行之前,已经把rte_bus_list/ rte_pci_bus/ rte_pci_bus.driver_list / rte_em_pmd 等pmd,这些全局变量串联起来,同时这些全局变量上的函数指针也都挂上了。

5.1 rte_bus_list和rte_pci_bus的数据关系
在这里插入图片描述

5.2 rte_pci_bus.driver_list 和rte_em_pmd的数据关系
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值