msi.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #include "msi.h"
  2. #include "pci.h"
  3. #include <common/errno.h>
  4. /**
  5. * @brief 生成msi消息
  6. *
  7. * @param msi_desc msi描述符
  8. * @return struct msi_msg_t* msi消息指针(在描述符内)
  9. */
  10. extern struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);
  11. /**
  12. * @brief 启用 Message Signaled Interrupts
  13. *
  14. * @param header 设备header
  15. * @param vector 中断向量号
  16. * @param processor 要投递到的处理器
  17. * @param edge_trigger 是否边缘触发
  18. * @param assert 是否高电平触发
  19. *
  20. * @return 返回码
  21. */
  22. int pci_enable_msi(struct msi_desc_t *msi_desc)
  23. {
  24. struct pci_device_structure_header_t *ptr = msi_desc->pci_dev;
  25. uint32_t cap_ptr;
  26. uint32_t tmp;
  27. uint16_t message_control;
  28. uint64_t message_addr;
  29. // 先尝试获取msi-x,若不存在,则获取msi capability
  30. if (msi_desc->pci.msi_attribute.is_msix)
  31. {
  32. cap_ptr = pci_enumerate_capability_list(ptr, 0x11);
  33. if (((int32_t)cap_ptr) < 0)
  34. {
  35. cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
  36. if (((int32_t)cap_ptr) < 0)
  37. return -ENOSYS;
  38. msi_desc->pci.msi_attribute.is_msix = 0;
  39. }
  40. }
  41. else
  42. {
  43. cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
  44. if (((int32_t)cap_ptr) < 0)
  45. return -ENOSYS;
  46. msi_desc->pci.msi_attribute.is_msix = 0;
  47. }
  48. // 获取msi消息
  49. msi_arch_get_msg(msi_desc);
  50. if (msi_desc->pci.msi_attribute.is_msix)
  51. {
  52. }
  53. else
  54. {
  55. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  56. message_control = (tmp >> 16) & 0xffff;
  57. // 写入message address
  58. message_addr = ((((uint64_t)msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo); // 获取message address
  59. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
  60. if (message_control & (1 << 7)) // 64位
  61. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, (uint32_t)((message_addr >> 32) & 0xffffffff));
  62. // 写入message data
  63. tmp = msi_desc->msg.data;
  64. if (message_control & (1 << 7)) // 64位
  65. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
  66. else
  67. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
  68. // 使能msi
  69. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  70. tmp |= (1 << 16);
  71. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  72. }
  73. return 0;
  74. }
  75. /**
  76. * @brief 在已配置好msi寄存器的设备上,使能msi
  77. *
  78. * @param header 设备头部
  79. * @return int 返回码
  80. */
  81. int pci_start_msi(void *header)
  82. {
  83. struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
  84. uint32_t cap_ptr;
  85. uint32_t tmp;
  86. switch (ptr->HeaderType)
  87. {
  88. case 0x00: // general device
  89. if (!(ptr->Status & 0x10))
  90. return -ENOSYS;
  91. cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
  92. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  93. if (tmp & 0xff != 0x5)
  94. return -ENOSYS;
  95. // 使能msi
  96. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  97. tmp |= (1 << 16);
  98. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  99. break;
  100. case 0x01: // pci to pci bridge
  101. if (!(ptr->Status & 0x10))
  102. return -ENOSYS;
  103. cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
  104. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  105. if (tmp & 0xff != 0x5)
  106. return -ENOSYS;
  107. //使能msi
  108. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  109. tmp |= (1 << 16);
  110. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  111. break;
  112. case 0x02: // pci to card bus bridge
  113. return -ENOSYS;
  114. break;
  115. default: // 不应该到达这里
  116. return -EINVAL;
  117. break;
  118. }
  119. return 0;
  120. }
  121. /**
  122. * @brief 禁用指定设备的msi
  123. *
  124. * @param header pci header
  125. * @return int
  126. */
  127. int pci_disable_msi(void *header)
  128. {
  129. struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
  130. uint32_t cap_ptr;
  131. uint32_t tmp;
  132. switch (ptr->HeaderType)
  133. {
  134. case 0x00: // general device
  135. if (!(ptr->Status & 0x10))
  136. return -ENOSYS;
  137. cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
  138. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  139. if (tmp & 0xff != 0x5)
  140. return -ENOSYS;
  141. // 禁用msi
  142. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  143. tmp &= (~(1 << 16));
  144. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  145. break;
  146. case 0x01: // pci to pci bridge
  147. if (!(ptr->Status & 0x10))
  148. return -ENOSYS;
  149. cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
  150. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  151. if (tmp & 0xff != 0x5)
  152. return -ENOSYS;
  153. //禁用msi
  154. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  155. tmp &= (~(1 << 16));
  156. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  157. break;
  158. case 0x02: // pci to card bus bridge
  159. return -ENOSYS;
  160. break;
  161. default: // 不应该到达这里
  162. return -EINVAL;
  163. break;
  164. }
  165. return 0;
  166. }