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