dpdk 18 ixgbe驱动初始化分析

本文详细介绍了DPDK中PCI设备驱动的注册、初始化过程,包括RTE_PMD_REGISTER_PCI宏的使用,rte_pci_register函数如何将驱动添加到PCI总线,以及rte_pci_scan如何扫描系统设备。在设备和驱动匹配后,通过调用probe函数完成设备初始化。整个流程涉及dpdk的总线注册、设备扫描、驱动匹配和初始化等关键步骤。
摘要由CSDN通过智能技术生成

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到list
    TAILQ_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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值