NVMe Device Driver init flow, kernel version 4.13.10
from drivers/nvme/host/pci.c
static struct pci_driver nvme_driver = {
.name = "nvme",
.id_table = nvme_id_table,
.probe = nvme_probe,
.remove = nvme_remove,
.shutdown = nvme_shutdown,
.driver = {
.pm = &nvme_dev_pm_ops,
},
.sriov_configure = nvme_pci_sriov_configure,
.err_handler = &nvme_err_handler,
};
static int __init nvme_init(void)
{
return pci_register_driver(&nvme_driver);
}
static void __exit nvme_exit(void)
{
pci_unregister_driver(&nvme_driver);
_nvme_check_size();
}
MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");
module_init(nvme_init);
module_exit(nvme_exit);
모듈 형식으로 되어 있다.
이 후 흐름을 정리하면 아래와 같다.
insmod
->nvme_init()
->pci_register_driver()
->__pci_register_driver()
->driver_register()
->drvier_find()
->bus_add_driver()
->drvier_add_groups()
->kobject_uevent()
...
이 후 어디선가 nvme_probe() 가 호출되어야 하는데, 정확한 흐름은 찾지 못했다.
다음은 nvme_probe() 의 흐름이다.
nvme_probe()
//
->dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node);
->dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(void *), GFP_KERNEL, node)
->nvme_dev_map(dev)
//
->nvme_remap_bar(dev, NVME_REG_DBS + 4096)
//
->dev->bar = ioremap(pci_resource_start(pdev, 0), size);
->dev->bar_mapped_size = size;
->dev->dbs = dev->bar + NVME_REG_DBS;
->INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work);
->queue_work(nvme_wq, &dev->ctrl.resetwork);
->return 0;
전체 코드는 drivers/nvme/host/pci.c 에서 확인 할 수 있고, 여기서는 필자가 이해한 바를 토대로 그 흐름을 적었다.
1. nvme_dev 를 위한 메모리를 할당한다.
2. nvme_queue 관리를 위한 포인터 배열을 위한 메모리를 할당한다. 그 길이는, 코어 개수 + 1 로
각 코어에 할당을 위한 io 큐와 관리자 큐의 전체 개수를 의미한다.
3. pci 장치에 물리메모리에 매핑되는 가상메모리 주소를 ioremap을 통하여 얻는다.
이 부분은 NVMe spec과 같이 보아야 할 부분이다. //나중에 한 차례 정리 해보겠다.
4. nvme_reset_work() 가 호출된다.
'리눅스 커널 > 블록 멀티 큐' 카테고리의 다른 글
nvme command 관련 추가 내용 (0) | 2021.10.26 |
---|---|
nvme command (0) | 2021.10.26 |
nvme_setup_io_queues 흐름 (0) | 2021.10.26 |
nvme_reset_work 흐름 (0) | 2021.10.26 |
nvme 자료구조 관계 (0) | 2021.10.26 |