nvme_setup_io_queues(struct nvme_dev * dev) from nvme_reset_work
->struct nvme_queue * adminq = dev->queues[0];
->struct pci_dev * pdev = to_pci_dev(dev->dev);
->nr_io_queues = num_present_cpus();
->result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues)
->pci_free_irq(pdev, 0, adminq);
->pci_free_irq_vectors(pdev);
->pci_disable_msix(dev);
->pci_disable_msi(dev);
->dev->max_qid = nr_io_queues;
->queue_request_irq(adminq);
->pci_request_irq(...);
->nvme_create_io_queues(dev);
->for (dev->ctrl.queue_count to dev->max_qid)
->nvme_alloc_queue(...);
->dma_zalloc_coherent(...);
->...__dma_alloc_coherent(...);
->*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
->nvme_alloc_sq_cmds(...);
->dev->ctrl.queue_count++;
->if fail, break;
->max = min(dev->max_qid, dev->ctrl.queue_count - 1);
->for (dev->online_queues to max)
->nvme_create_queue(dev->queues[i], i);
->nvmeq->cq_vector = qid - 1;
->adapter_alloc_cq(dev, qid, nvmeq);
->nvme_sumbit_sync_cmd(dev->ctrl.admin_q, ...);
->adapter_alloc_sq(dev, qid, nvmeq);
->nvme_sumbit_sync_cmd(dev->ctrl.admin_q, ...);
->queue_request_irq(nvmeq);
->nvme_init_queue(nvmeq, qid);
->dev->online_queues++;
->if fail, break;
->return ret > = 0 ? 0 : ret;
1. 먼저 io 큐를 위한 개수를 설정한다. 이 동안 관리자 큐의 인터럽트를 해제한다.
2. io를 위한 큐 개수가 6개이면 관리자 큐를 포함해 0 부터 6, 총 7개의 인덱스가 필요하다.
그래서 max_qid를 nr_io_queues로 설정한다.
3. nvme_create_io_queues에서 첫번째 for문에서 queue_count 값은 1이다. 관리자 큐만 존재하기 때문이다.
이 후, 앞서 설정한 max_qid 까지 인덱스를 증가시키면서 nvme_queue를 위한 메모리 공간을 할당하고,
SQ와 CQ를 위한 dma 주소를 할당한다. 그래서 이 함수가 성공적으로 할당한 경우 컨트롤러의 큐 개수를 하나 증가시킨다. fail 하는 경우는 이를 위한 메모리 공간이 부족한 경우라고 생각하고 있다.
cf, 혹은 cpu개수 보다 초과한 경우?
4. max_qid와 (queue_count - 1) 중 최소값을 선택하는데, 이는 메모리가 정상적으로 할당된 nvme_queue의 개수를 보는 것이다. queue_count - 1은 관리자 큐를 제외하기 위함이다.
5. 이제 두번째 for문에서 현재 online_queues는 1이다. 관리자 큐만 있기 때문이다.
6. SQ, CQ 생성을 위해 nvme ssd에 command를 보낸다. 할당이 실패한 경우 음수 값이 반환되어 이를 리턴한다.
반환 값이 0인 경우 성공, 음수인 경우는 리눅스 에러 코드를 나타내며, 양수인 경우 NVMe 상태코드를 나타낸다.
cf, nvme command는 nvme spec에 맞추어 보내게된다.
7. 즉, nvme_setup_io_queues의 반환 값이 nvme_reset_work로 전달되는데, 0인 경우 nvme_reset_work는 이어서 코드를 진행해나가고, 음수인 경우는 nvme 초기화를 마저 하지 못하고 실패하게 된다.
'리눅스 커널 > 블록 멀티 큐' 카테고리의 다른 글
nvme command 관련 추가 내용 (0) | 2021.10.26 |
---|---|
nvme command (0) | 2021.10.26 |
nvme_reset_work 흐름 (0) | 2021.10.26 |
nvme 자료구조 관계 (0) | 2021.10.26 |
NVMe 디바이스 드라이버 초기화 흐름 (0) | 2021.10.26 |