nvme

created : 2020-06-15T11:13:59+00:00
modified : 2020-06-27T06:11:20+00:00
linux nvme ssd

시작

Linux NVMe 공부

nvme 자료구조

의문점

PCI driver structure (실제로 module 의 interface)

static struct pci_driver nvme_driver = {
	.name		= "nvme",
	.id_table	= nvme_id_table,
	.probe		= nvme_probe,
	.remove		= nvme_remove,
	.shutdown	= nvme_shutdown,
#ifdef CONFIG_PM_SLEEP
	.driver		= {
		.pm	= &nvme_dev_pm_ops,
	},
#endif
	.sriov_configure = pci_sriov_configure_simple,
	.err_handler	= &nvme_err_handler,
};
static const struct pci_device_id nvme_id_table[] = {
	{ PCI_VDEVICE(INTEL, 0x0953),
		.driver_data = NVME_QUIRK_STRIPE_SIZE |
				NVME_QUIRK_DEALLOCATE_ZEROES, },
	{ PCI_VDEVICE(INTEL, 0x0a53),
		.driver_data = NVME_QUIRK_STRIPE_SIZE |
				NVME_QUIRK_DEALLOCATE_ZEROES, },
	{ PCI_VDEVICE(INTEL, 0x0a54),
		.driver_data = NVME_QUIRK_STRIPE_SIZE |
				NVME_QUIRK_DEALLOCATE_ZEROES, },
	{ PCI_VDEVICE(INTEL, 0x0a55),
		.driver_data = NVME_QUIRK_STRIPE_SIZE |
				NVME_QUIRK_DEALLOCATE_ZEROES, },
	{ PCI_VDEVICE(INTEL, 0xf1a5),	/* Intel 600P/P3100 */
		.driver_data = NVME_QUIRK_NO_DEEPEST_PS |
				NVME_QUIRK_MEDIUM_PRIO_SQ |
				NVME_QUIRK_NO_TEMP_THRESH_CHANGE },
  /* 이하 생략 */
};

nvme_probe 함수 (nvme_driverprobe 부분)

하는일
  1. NUMA NODE 설정 1-2. dev_to_node 를 통해서 [[NUMA]] NODE 를 가져온다. (단, CONFIG_NUMA 가 선언되어 있지 않으면 아무것도 하지 않는다.) 1-3. device 에 numa 노드가 설정되지 않았다면, first_memory_node 를 가져온다.
  2. struct nvme_dev 크기에 맞추어 dev 변수를 kernel memory 를 할당한다.
  3. queue 들을 설정 한다. (각 device는 적어도 2개, admin command 와 i/o command 를 담당하는 큐를 가지게 된다.) 3-1. write_queues,poll_queues 값을 설정한다. (흠.. 이 값을 어디서 세팅해놓는지는 못찾았다. 아마도 config 변수 값일듯) 3-2. 사용가능한 cpu 개수 + write_queues + poll_queues 값에 맞추어 queue를 할당한다.
  4. device를 가져온다. 4-1. 2~3 과정에서 설정한 dev 변수를 private_driver_data 로 지정한다. (pci_set_drvdata)
  5. pci를 메모리에 매핑시킨다. 5-1. pci를 “nvme” 앞으로 예약한다. 5-2. I/O 물리 메모리를 Virtual Memory 에 매핑시킨다.
  6. reset_work, remove_work (workqueue) 를 초기화 시킨다.
  7. [[prp]] list용 page, 256(4K~128K) 에 최적화된 prp list를 dma_pool_create 를 통해 각각 만든다.
  8. 하드웨어 별로 특이사항이 있는지 확인한다. (quirks 에다가 OR 연산으로 넣어놓는다.)
  9. iod용 memory pool 을 할당한다. (iod는 i/o description 의 약자)
  10. NVMe Controller 를 init 10-1. spin_lock, mutex, list, rwsem(read write semaphore), ops, quirks, workqueues 들을 초기화(이외에도 많은 controller 관련 변수들을 초기화) 10-2. 이때 nvme_pci_ctrl_ops 를 넘겨준다. 이를 기반으로 core.c 에 선언 되어 있는 nvme_init_ctrl 이 호출된다.
  11. NVMe Controller reset 11-1. pci에 nvme 를 켜주는 등의 작업. 11-2. admin queue 설정

  12. 오래걸리는 작업 (controller 의 reset_work, scan_work 초기화, 4 에서 가져온 device release (정확히 함수는 put_device 호출)) 을 async 하게 동작하도록 예약
그림