msi.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "msi.h"
  2. #include "pci.h"
  3. #include <common/errno.h>
  4. #include <mm/mmio.h>
  5. /**
  6. * @brief 生成msi消息
  7. *
  8. * @param msi_desc msi描述符
  9. * @return struct msi_msg_t* msi消息指针(在描述符内)
  10. */
  11. extern struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);
  12. /**
  13. * @brief 读取msix的capability list
  14. *
  15. * @param msi_desc msi描述符
  16. * @param cap_off capability list的offset
  17. * @return struct pci_msix_cap_t 对应的capability list
  18. */
  19. static __always_inline struct pci_msix_cap_t __msi_read_msix_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
  20. {
  21. struct pci_msix_cap_t cap_list = {0};
  22. uint32_t dw0;
  23. dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
  24. io_lfence();
  25. cap_list.cap_id = dw0 & 0xff;
  26. cap_list.next_off = (dw0 >> 8) & 0xff;
  27. cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
  28. cap_list.dword1 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
  29. cap_list.dword2 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
  30. return cap_list;
  31. }
  32. static __always_inline struct pci_msi_cap_t __msi_read_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
  33. {
  34. struct pci_msi_cap_t cap_list;
  35. uint32_t dw0;
  36. dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
  37. cap_list.cap_id = dw0 & 0xff;
  38. cap_list.next_off = (dw0 >> 8) & 0xff;
  39. cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
  40. cap_list.msg_addr_lo = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
  41. uint16_t msg_data_off = 0xc;
  42. if (cap_list.msg_ctrl & (1 << 7)) // 64位
  43. {
  44. cap_list.msg_addr_hi = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
  45. }
  46. else
  47. {
  48. cap_list.msg_addr_hi = 0;
  49. msg_data_off = 0x8;
  50. }
  51. cap_list.msg_data = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + msg_data_off) & 0xffff;
  52. cap_list.mask = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x10);
  53. cap_list.pending = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x14);
  54. return cap_list;
  55. }
  56. /**
  57. * @brief 映射设备的msix表
  58. *
  59. * @param pci_dev pci设备信息结构体
  60. * @param msix_cap msix capability list的结构体
  61. * @return int 错误码
  62. */
  63. static __always_inline int __msix_map_table(struct pci_device_structure_header_t *pci_dev, struct pci_msix_cap_t *msix_cap)
  64. {
  65. // 计算bar寄存器的offset
  66. uint32_t bar_off = 0x10 + 4 * (msix_cap->dword1 & 0x7);
  67. // msix table相对于bar寄存器中存储的地址的offset
  68. pci_dev->msix_offset = msix_cap->dword1 & (~0x7);
  69. pci_dev->msix_table_size = (msix_cap->msg_ctrl & 0x7ff) + 1;
  70. pci_dev->msix_mmio_size = pci_dev->msix_table_size * 16 + pci_dev->msix_offset;
  71. // 申请mmio空间
  72. mmio_create(pci_dev->msix_mmio_size, VM_IO | VM_DONTCOPY, &pci_dev->msix_mmio_vaddr, &pci_dev->msix_mmio_size);
  73. pci_dev->msix_mmio_vaddr &= (~0xf);
  74. uint32_t bar = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->func, bar_off);
  75. // kdebug("pci_dev->msix_mmio_vaddr=%#018lx, bar=%#010lx, table offset=%#010lx, table_size=%#010lx, mmio_size=%d", pci_dev->msix_mmio_vaddr, bar, pci_dev->msix_offset, pci_dev->msix_table_size, pci_dev->msix_mmio_size);
  76. // 将msix table映射到页表
  77. mm_map(&initial_mm, pci_dev->msix_mmio_vaddr, pci_dev->msix_mmio_size, bar);
  78. return 0;
  79. }
  80. /**
  81. * @brief 将msi_desc中的数据填写到msix表的指定表项处
  82. *
  83. * @param pci_dev pci设备结构体
  84. * @param msi_desc msi描述符
  85. */
  86. static __always_inline void __msix_set_entry(struct msi_desc_t *msi_desc)
  87. {
  88. uint64_t *ptr = (uint64_t *)(msi_desc->pci_dev->msix_mmio_vaddr + msi_desc->pci_dev->msix_offset + msi_desc->msi_index * 16);
  89. *ptr = ((uint64_t)(msi_desc->msg.address_hi) << 32) | (msi_desc->msg.address_lo);
  90. io_mfence();
  91. ++ptr;
  92. io_mfence();
  93. *ptr = ((uint64_t)(msi_desc->msg.vector_control) << 32) | (msi_desc->msg.data);
  94. io_mfence();
  95. }
  96. /**
  97. * @brief 清空设备的msix table的指定表项
  98. *
  99. * @param pci_dev pci设备
  100. * @param msi_index 表项号
  101. */
  102. static __always_inline void __msix_clear_entry(struct pci_device_structure_header_t *pci_dev, uint16_t msi_index)
  103. {
  104. uint64_t *ptr = (uint64_t *)(pci_dev->msix_mmio_vaddr + pci_dev->msix_offset + msi_index * 16);
  105. *ptr = 0;
  106. ++ptr;
  107. *ptr = 0;
  108. }
  109. /**
  110. * @brief 启用 Message Signaled Interrupts
  111. *
  112. * @param header 设备header
  113. * @param vector 中断向量号
  114. * @param processor 要投递到的处理器
  115. * @param edge_trigger 是否边缘触发
  116. * @param assert 是否高电平触发
  117. *
  118. * @return 返回码
  119. */
  120. int pci_enable_msi(struct msi_desc_t *msi_desc)
  121. {
  122. struct pci_device_structure_header_t *ptr = msi_desc->pci_dev;
  123. uint32_t cap_ptr;
  124. uint32_t tmp;
  125. uint16_t message_control;
  126. uint64_t message_addr;
  127. // 先尝试获取msi-x,若不存在,则获取msi capability
  128. if (msi_desc->pci.msi_attribute.is_msix)
  129. {
  130. cap_ptr = pci_enumerate_capability_list(ptr, 0x11);
  131. if (((int32_t)cap_ptr) < 0)
  132. {
  133. cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
  134. if (((int32_t)cap_ptr) < 0)
  135. return -ENOSYS;
  136. msi_desc->pci.msi_attribute.is_msix = 0;
  137. }
  138. }
  139. else
  140. {
  141. cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
  142. if (((int32_t)cap_ptr) < 0)
  143. return -ENOSYS;
  144. msi_desc->pci.msi_attribute.is_msix = 0;
  145. }
  146. // 获取msi消息
  147. msi_arch_get_msg(msi_desc);
  148. if (msi_desc->pci.msi_attribute.is_msix) // MSI-X
  149. {
  150. // 读取msix的信息
  151. struct pci_msix_cap_t cap = __msi_read_msix_cap_list(msi_desc, cap_ptr);
  152. // 映射msix table
  153. __msix_map_table(msi_desc->pci_dev, &cap);
  154. io_mfence();
  155. // 设置msix的中断
  156. __msix_set_entry(msi_desc);
  157. io_mfence();
  158. // todo: disable intx
  159. // 使能msi-x
  160. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  161. tmp |= (1 << 31);
  162. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  163. }
  164. else
  165. {
  166. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  167. message_control = (tmp >> 16) & 0xffff;
  168. // 写入message address
  169. message_addr = ((((uint64_t)msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo); // 获取message address
  170. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
  171. if (message_control & (1 << 7)) // 64位
  172. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, (uint32_t)((message_addr >> 32) & 0xffffffff));
  173. // 写入message data
  174. tmp = msi_desc->msg.data;
  175. if (message_control & (1 << 7)) // 64位
  176. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
  177. else
  178. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
  179. // 使能msi
  180. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  181. tmp |= (1 << 16);
  182. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  183. }
  184. return 0;
  185. }
  186. /**
  187. * @brief 在已配置好msi寄存器的设备上,使能msi
  188. *
  189. * @param header 设备头部
  190. * @return int 返回码
  191. */
  192. int pci_start_msi(void *header)
  193. {
  194. struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
  195. uint32_t cap_ptr;
  196. uint32_t tmp;
  197. switch (ptr->HeaderType)
  198. {
  199. case 0x00: // general device
  200. if (!(ptr->Status & 0x10))
  201. return -ENOSYS;
  202. cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
  203. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  204. if (tmp & 0xff != 0x5)
  205. return -ENOSYS;
  206. // 使能msi
  207. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  208. tmp |= (1 << 16);
  209. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  210. break;
  211. case 0x01: // pci to pci bridge
  212. if (!(ptr->Status & 0x10))
  213. return -ENOSYS;
  214. cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
  215. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  216. if (tmp & 0xff != 0x5)
  217. return -ENOSYS;
  218. // 使能msi
  219. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  220. tmp |= (1 << 16);
  221. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  222. break;
  223. case 0x02: // pci to card bus bridge
  224. return -ENOSYS;
  225. break;
  226. default: // 不应该到达这里
  227. return -EINVAL;
  228. break;
  229. }
  230. return 0;
  231. }
  232. /**
  233. * @brief 禁用指定设备的msi
  234. *
  235. * @param header pci header
  236. * @return int
  237. */
  238. int pci_disable_msi(void *header)
  239. {
  240. struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
  241. uint32_t cap_ptr;
  242. uint32_t tmp;
  243. switch (ptr->HeaderType)
  244. {
  245. case 0x00: // general device
  246. if (!(ptr->Status & 0x10))
  247. return -ENOSYS;
  248. cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
  249. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  250. if (tmp & 0xff != 0x5)
  251. return -ENOSYS;
  252. // 禁用msi
  253. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  254. tmp &= (~(1 << 16));
  255. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  256. break;
  257. case 0x01: // pci to pci bridge
  258. if (!(ptr->Status & 0x10))
  259. return -ENOSYS;
  260. cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
  261. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  262. if (tmp & 0xff != 0x5)
  263. return -ENOSYS;
  264. // 禁用msi
  265. tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
  266. tmp &= (~(1 << 16));
  267. pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
  268. break;
  269. case 0x02: // pci to card bus bridge
  270. return -ENOSYS;
  271. break;
  272. default: // 不应该到达这里
  273. return -EINVAL;
  274. break;
  275. }
  276. return 0;
  277. }