Linux PCIe EPF 디바이스 생성 과정 분석

본 아티클에서는 kernel 5.15 버전을 기반으로 PCI endpoint function 디바이스의 생성 과정에 대해 설명한다. pci-epf-test 예제를 통해 주요 함수들의 동작 원리를 살펴본다.

먼저 pci_ep_cfs_init 함수부터 분석한다. 690-699 행에서 Configfs文件系统에 pci_ep 서브시스템을 생성한다. 701-718 행에서는 해당 서브시스템 아래에 functions와 controllers 두 개의 config_group을 각각 생성한다.

static struct configfs_subsystem pci_ep_cfs_subsys = {
    .su_group = {
        .cg_item = {
            .ci_namebuf = "pci_ep",
            .ci_type = &pci_ep_type,
        },
    },
    .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex),
};

static int __init pci_ep_cfs_init(void)
{
    int ret;
    struct config_group *root = &pci_ep_cfs_subsys.su_group;

    config_group_init(root);

    ret = configfs_register_subsystem(&pci_ep_cfs_subsys);
    if (ret) {
        pr_err("Registration failed %d for subsystem %s\n",
               ret, root->cg_item.ci_namebuf);
        goto error_out;
    }

    functions_group = configfs_register_default_group(root, "functions",
                               &pci_functions_type);
    if (IS_ERR(functions_group)) {
        ret = PTR_ERR(functions_group);
        pr_err("Functions group registration error %d\n",
               ret);
        goto err_functions;
    }

    controllers_group =
        configfs_register_default_group(root, "controllers",
                        &pci_controllers_type);
    if (IS_ERR(controllers_group)) {
        ret = PTR_ERR(controllers_group);
        pr_err("Controllers group registration error %d\n",
               ret);
        goto err_controllers;
    }

    return 0;

err_controllers:
    configfs_unregister_default_group(functions_group);

err_functions:
    configfs_unregister_subsystem(&pci_ep_cfs_subsys);

error_out:
    return ret;
}
module_init(pci_ep_cfs_init);

이전 아티클에서 설명한 바와 같이, endpoint 컨트롤러 드라이버 등록 시 devm_pci_epc_create 함수가 호출되며, 이 함수 내부에서 pci_ep_cfs_add_epc_group을 통해 controllers 아래에 컨트롤러 해당하는 config_group이 생성된다. 예컨대 51000000.pcie_ep와 같은 형태로 등록된다.

struct config_group *pci_ep_cfs_add_epc_group(const char *epc_name)
{
    int ret;
    struct pci_epc *epc;
    struct config_group *group;
    struct pci_epc_group *epc_group_ptr;

    epc_group_ptr = kzalloc(sizeof(*epc_group_ptr), GFP_KERNEL);
    if (!epc_group_ptr) {
        ret = -ENOMEM;
        goto alloc_failed;
    }

    group = &epc_group_ptr->group;

    config_group_init_type_name(group, epc_name, &pci_epc_type);
    ret = configfs_register_group(controllers_group, group);
    if (ret) {
        pr_err("Configfs group registration failed for %s\n", epc_name);
        goto reg_failed;
    }

    epc = pci_epc_get(epc_name);
    if (IS_ERR(epc)) {
        ret = PTR_ERR(epc);
        goto get_failed;
    }

    epc_group_ptr->epc = epc;

    return group;

get_failed:
    configfs_unregister_group(group);

reg_failed:
    kfree(epc_group_ptr);

alloc_failed:
    return ERR_PTR(ret);
}

다음으로 pci_epf_driver의 등록 함수인 pci_epf_register_driver를 살펴본다. 410행에서는 디바이스 드라이버를 등록하고, 414행에서는 드라이버에 해당하는 config_group을 추가한다. 이 과정은 결국 pci_ep_cfs_add_epf_group 함수를 호출하여 config_group을 생성한다.

#define pci_epf_register_driver(driver)    \
__pci_epf_register_driver((driver), THIS_MODULE)

/**
* __pci_epf_register_driver() - register a new PCI EPF driver
* @driver: structure representing PCI EPF driver
* @owner: owner module reference
*/

태그: linux Kernel pci-express PCIe endpoint

6월 20일 22:29에 게시됨