본 아티클에서는 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
*/