irq.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-10-24 GuEe-GUI first version
  9. */
  10. #include <drivers/pci_msi.h>
  11. #define DBG_TAG "pci.msi.irq"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. static RT_DEFINE_SPINLOCK(msi_irq_map_lock);
  15. static RT_BITMAP_DECLARE(msi_irq_map, MAX_HANDLERS) = {};
  16. rt_err_t rt_pci_msi_setup_irqs(struct rt_pci_device *pdev, int nvec, int type)
  17. {
  18. int irq, index = 0, irq_nr = 0;
  19. rt_err_t err = RT_EOK;
  20. struct rt_pic_irq *pirq;
  21. struct rt_pic *msi_pic;
  22. struct rt_pci_msi_desc *desc;
  23. if (!pdev)
  24. {
  25. return -RT_EINVAL;
  26. }
  27. msi_pic = pdev->msi_pic;
  28. if (type == PCIY_MSI)
  29. {
  30. int last_irq = -1, irq_idx;
  31. rt_size_t irq_nr;
  32. desc = rt_pci_msi_first_desc(pdev);
  33. irq_nr = 1 << desc->msi.cap.multi_msg_use;
  34. rt_hw_spin_lock(&msi_irq_map_lock.lock);
  35. _retry:
  36. for (int i = 0; i < irq_nr; ++i)
  37. {
  38. if ((irq = msi_pic->ops->irq_alloc_msi(msi_pic, desc)) < 0)
  39. {
  40. err = irq;
  41. LOG_E("Setup %s[%d] IRQ error = %s", "MSI", i, rt_strerror(err));
  42. break;
  43. }
  44. if (last_irq >= 0 && last_irq + 1 != irq)
  45. {
  46. for (int idx = 0; idx < i; ++i, --last_irq)
  47. {
  48. rt_bitmap_set_bit(msi_irq_map, last_irq);
  49. }
  50. last_irq = irq;
  51. goto _retry;
  52. }
  53. last_irq = irq;
  54. }
  55. if (!err)
  56. {
  57. /* Get the first irq */
  58. desc->irq = irq - (irq_nr - 1);
  59. }
  60. rt_bitmap_for_each_set_bit(msi_irq_map, irq_idx, MAX_HANDLERS)
  61. {
  62. msi_pic->ops->irq_free_msi(msi_pic, irq_idx);
  63. /* Free bit so the next user doesn't need to bzero */
  64. rt_bitmap_clear_bit(msi_irq_map, irq_idx);
  65. }
  66. rt_hw_spin_unlock(&msi_irq_map_lock.lock);
  67. if (!err)
  68. {
  69. for (int idx = 0; idx < nvec; ++idx)
  70. {
  71. pirq = rt_pic_find_pirq(msi_pic, irq + idx);
  72. pirq->msi_desc = desc;
  73. msi_pic->ops->irq_compose_msi_msg(pirq, &desc->msg);
  74. rt_pci_msi_write_msg(desc, &desc->msg);
  75. }
  76. }
  77. }
  78. else if (type == PCIY_MSIX)
  79. {
  80. rt_pci_msi_for_each_desc(pdev, desc)
  81. {
  82. if ((irq = msi_pic->ops->irq_alloc_msi(msi_pic, desc)) < 0)
  83. {
  84. err = irq;
  85. LOG_E("Setup %s[%d] IRQ error = %s", "MSI-X",
  86. desc->msix.index, rt_strerror(err));
  87. break;
  88. }
  89. desc->irq = irq;
  90. pirq = rt_pic_find_pirq(msi_pic, irq);
  91. pirq->msi_desc = desc;
  92. msi_pic->ops->irq_compose_msi_msg(pirq, &desc->msg);
  93. rt_pci_msi_write_msg(desc, &desc->msg);
  94. ++irq_nr;
  95. }
  96. if (err)
  97. {
  98. rt_pci_msi_for_each_desc(pdev, desc)
  99. {
  100. if (index >= irq_nr)
  101. {
  102. break;
  103. }
  104. msi_pic->ops->irq_free_msi(msi_pic, desc->irq);
  105. ++index;
  106. }
  107. }
  108. }
  109. else
  110. {
  111. err = -RT_EINVAL;
  112. }
  113. return err;
  114. }