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 }