nvme-pci.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #define NVME_REG_BAR 0
  13. struct pci_nvme_quirk
  14. {
  15. const struct rt_nvme_ops *ops;
  16. };
  17. struct pci_nvme_controller
  18. {
  19. struct rt_nvme_controller parent;
  20. const struct pci_nvme_quirk *quirk;
  21. rt_bool_t is_msi;
  22. struct rt_pci_msix_entry msix_entries[RT_USING_NVME_QUEUE];
  23. };
  24. static const struct rt_nvme_ops pci_nvme_std_ops =
  25. {
  26. .name = "PCI",
  27. };
  28. static rt_err_t pci_nvme_probe(struct rt_pci_device *pdev)
  29. {
  30. rt_err_t err;
  31. rt_ssize_t msi_nr;
  32. struct rt_nvme_controller *nvme;
  33. struct pci_nvme_controller *pci_nvme = rt_calloc(1, sizeof(*pci_nvme));
  34. const struct pci_nvme_quirk *quirk = pdev->id->data;
  35. if (!pci_nvme)
  36. {
  37. return -RT_ENOMEM;
  38. }
  39. pci_nvme->quirk = quirk;
  40. nvme = &pci_nvme->parent;
  41. nvme->dev = &pdev->parent;
  42. nvme->regs = rt_pci_iomap(pdev, NVME_REG_BAR);
  43. if (!nvme->regs)
  44. {
  45. err = -RT_EIO;
  46. goto _fail;
  47. }
  48. nvme->ops = quirk && quirk->ops ? quirk->ops : &pci_nvme_std_ops;
  49. if ((msi_nr = rt_pci_msix_vector_count(pdev)) <= 0)
  50. {
  51. msi_nr = rt_pci_msi_vector_count(pdev);
  52. }
  53. if (msi_nr > 0)
  54. {
  55. nvme->irqs_nr = RT_ARRAY_SIZE(pci_nvme->msix_entries);
  56. nvme->irqs_nr = rt_min_t(rt_size_t, msi_nr, nvme->irqs_nr);
  57. }
  58. if (nvme->irqs_nr > 0)
  59. {
  60. rt_pci_msix_entry_index_linear(pci_nvme->msix_entries, nvme->irqs_nr);
  61. if (rt_pci_msix_enable(pdev, pci_nvme->msix_entries, nvme->irqs_nr) > 0)
  62. {
  63. pci_nvme->is_msi = RT_TRUE;
  64. for (int i = 0; i < nvme->irqs_nr; ++i)
  65. {
  66. nvme->irqs[i] = pci_nvme->msix_entries[i].irq;
  67. }
  68. }
  69. }
  70. if (!pci_nvme->is_msi)
  71. {
  72. nvme->irqs_nr = 1;
  73. nvme->irqs[0] = pdev->irq;
  74. rt_pci_irq_unmask(pdev);
  75. }
  76. rt_pci_set_master(pdev);
  77. if ((err = rt_nvme_controller_register(nvme)))
  78. {
  79. goto _disable;
  80. }
  81. pdev->parent.user_data = pci_nvme;
  82. return RT_EOK;
  83. _disable:
  84. if (pci_nvme->is_msi)
  85. {
  86. rt_pci_msix_disable(pdev);
  87. }
  88. else
  89. {
  90. rt_pci_irq_mask(pdev);
  91. }
  92. rt_pci_clear_master(pdev);
  93. rt_iounmap(nvme->regs);
  94. _fail:
  95. rt_free(pci_nvme);
  96. return err;
  97. }
  98. static rt_err_t pci_nvme_remove(struct rt_pci_device *pdev)
  99. {
  100. struct rt_nvme_controller *nvme;
  101. struct pci_nvme_controller *pci_nvme = pdev->parent.user_data;
  102. nvme = &pci_nvme->parent;
  103. rt_nvme_controller_unregister(nvme);
  104. if (pci_nvme->is_msi)
  105. {
  106. rt_pci_msix_disable(pdev);
  107. }
  108. else
  109. {
  110. /* INTx is shared, don't mask all */
  111. rt_hw_interrupt_umask(pdev->irq);
  112. rt_pci_irq_mask(pdev);
  113. }
  114. rt_pci_clear_master(pdev);
  115. rt_iounmap(nvme->regs);
  116. rt_free(pci_nvme);
  117. return RT_EOK;
  118. }
  119. static rt_err_t pci_nvme_shutdown(struct rt_pci_device *pdev)
  120. {
  121. return pci_nvme_remove(pdev);
  122. }
  123. static const struct rt_pci_device_id pci_nvme_ids[] =
  124. {
  125. { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0010) },
  126. { RT_PCI_DEVICE_CLASS(PCIS_STORAGE_EXPRESS, ~0) },
  127. { /* sentinel */ }
  128. };
  129. static struct rt_pci_driver pci_nvme_driver =
  130. {
  131. .name = "nvme-pci",
  132. .ids = pci_nvme_ids,
  133. .probe = pci_nvme_probe,
  134. .remove = pci_nvme_remove,
  135. .shutdown = pci_nvme_shutdown,
  136. };
  137. RT_PCI_DRIVER_EXPORT(pci_nvme_driver);