Explorar o código

new: msix中断

fslongjin %!s(int64=2) %!d(string=hai) anos
pai
achega
ff94280f77

+ 122 - 3
kernel/driver/pci/msi.c

@@ -1,6 +1,7 @@
 #include "msi.h"
 #include "pci.h"
 #include <common/errno.h>
+#include <mm/mmio.h>
 
 /**
  * @brief 生成msi消息
@@ -10,6 +11,112 @@
  */
 extern struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);
 
+/**
+ * @brief 读取msix的capability list
+ *
+ * @param msi_desc msi描述符
+ * @param cap_off capability list的offset
+ * @return struct pci_msix_cap_t 对应的capability list
+ */
+static __always_inline struct pci_msix_cap_t __msi_read_msix_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
+{
+    struct pci_msix_cap_t cap_list = {0};
+    uint32_t dw0;
+    dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
+    cap_list.cap_id = dw0 & 0xff;
+    cap_list.next_off = (dw0 >> 8) & 0xff;
+    cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
+
+    cap_list.dword1 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
+    cap_list.dword2 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
+    return cap_list;
+}
+
+static __always_inline struct pci_msi_cap_t __msi_read_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
+{
+    struct pci_msi_cap_t cap_list;
+    uint32_t dw0;
+    dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
+    cap_list.cap_id = dw0 & 0xff;
+    cap_list.next_off = (dw0 >> 8) & 0xff;
+    cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
+
+    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);
+    uint16_t msg_data_off = 0xc;
+    if (cap_list.msg_ctrl & (1 << 7)) // 64位
+    {
+        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);
+    }
+    else
+    {
+        cap_list.msg_addr_hi = 0;
+        msg_data_off = 0x8;
+    }
+
+    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;
+
+    cap_list.mask = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x10);
+    cap_list.pending = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x14);
+
+    return cap_list;
+}
+
+/**
+ * @brief 映射设备的msix表
+ *
+ * @param pci_dev pci设备信息结构体
+ * @param msix_cap msix capability list的结构体
+ * @return int 错误码
+ */
+static __always_inline int __msix_map_table(struct pci_device_structure_header_t *pci_dev, struct pci_msix_cap_t *msix_cap)
+{
+    // 计算bar寄存器的offset
+    uint32_t bar_off = 0x10 + 4 * (msix_cap->dword1 & 0x7);
+
+    // msix table相对于bar寄存器中存储的地址的offset
+    pci_dev->msix_offset = msix_cap->dword1 & (~0x7);
+    pci_dev->msix_table_size = (msix_cap->msg_ctrl & 0x7ff) + 1;
+    pci_dev->msix_mmio_size = pci_dev->msix_table_size * 16 + pci_dev->msix_offset;
+
+    // 申请mmio空间
+    mmio_create(pci_dev->msix_mmio_size, VM_IO | VM_DONTCOPY, &pci_dev->msix_mmio_vaddr, &pci_dev->msix_mmio_size);
+    pci_dev->msix_mmio_vaddr &= (~0xf);
+    uint32_t bar = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->func, bar_off);
+    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);
+
+    // 将msix table映射到页表
+    mm_map(&initial_mm, pci_dev->msix_mmio_vaddr, pci_dev->msix_mmio_size, bar);
+    return 0;
+}
+
+/**
+ * @brief 将msi_desc中的数据填写到msix表的指定表项处
+ *
+ * @param pci_dev pci设备结构体
+ * @param msi_desc msi描述符
+ */
+static __always_inline void __msix_set_entry(struct msi_desc_t *msi_desc)
+{
+    uint64_t *ptr = (uint64_t *)(msi_desc->pci_dev->msix_mmio_vaddr + msi_desc->pci_dev->msix_offset + msi_desc->msi_index * 16);
+    *ptr = (msi_desc->msg.address_hi << 32) | (msi_desc->msg.address_lo);
+    ++ptr;
+    *ptr = (msi_desc->msg.vector_control << 32) | (msi_desc->msg.data);
+}
+
+/**
+ * @brief 清空设备的msix table的指定表项
+ * 
+ * @param pci_dev pci设备
+ * @param msi_index 表项号 
+ */
+static __always_inline void __msix_clear_entry(struct pci_device_structure_header_t *pci_dev, uint16_t msi_index)
+{
+    uint64_t *ptr = (uint64_t *)(pci_dev->msix_mmio_vaddr + pci_dev->msix_offset + msi_index * 16);
+    *ptr = 0;
+    ++ptr;
+    *ptr = 0;
+}
+
 /**
  * @brief 启用 Message Signaled Interrupts
  *
@@ -51,8 +158,20 @@ int pci_enable_msi(struct msi_desc_t *msi_desc)
     // 获取msi消息
     msi_arch_get_msg(msi_desc);
 
-    if (msi_desc->pci.msi_attribute.is_msix)
+    if (msi_desc->pci.msi_attribute.is_msix) // MSI-X
     {
+        // 读取msix的信息
+        struct pci_msix_cap_t cap = __msi_read_msix_cap_list(msi_desc, cap_ptr);
+        // 映射msix table
+        __msix_map_table(msi_desc->pci_dev, &cap);
+
+        // 设置msix的中断
+        __msix_set_entry(msi_desc);
+
+        // 使能msi
+        tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
+        tmp |= (1 << 16);
+        pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
     }
     else
     {
@@ -124,7 +243,7 @@ int pci_start_msi(void *header)
         if (tmp & 0xff != 0x5)
             return -ENOSYS;
 
-        //使能msi
+        // 使能msi
         tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
         tmp |= (1 << 16);
         pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
@@ -182,7 +301,7 @@ int pci_disable_msi(void *header)
         if (tmp & 0xff != 0x5)
             return -ENOSYS;
 
-        //禁用msi
+        // 禁用msi
         tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
         tmp &= (~(1 << 16));
         pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);

+ 39 - 2
kernel/driver/pci/msi.h

@@ -10,6 +10,7 @@ struct msi_msg_t
     uint32_t address_lo;
     uint32_t address_hi;
     uint32_t data;
+    uint32_t vector_control;
 };
 struct pci_msi_desc_t
 {
@@ -27,6 +28,42 @@ struct pci_msi_desc_t
     } msi_attribute;
 };
 
+/**
+ * @brief msi capability list的结构
+ *
+ */
+struct pci_msi_cap_t
+{
+    uint8_t cap_id;
+    uint8_t next_off;
+    uint16_t msg_ctrl;
+
+    uint32_t msg_addr_lo;
+    uint32_t msg_addr_hi;
+
+    uint16_t msg_data;
+    uint16_t Rsvd;
+
+    uint32_t mask;
+    uint32_t pending;
+};
+
+/**
+ * @brief MSI-X的capability list结构体
+ * 
+ */
+struct pci_msix_cap_t
+{
+    uint8_t cap_id;
+    uint8_t next_off;
+    uint16_t msg_ctrl;
+
+    uint32_t dword1; // 该DWORD的组成为:[Table Offset][BIR2:0].
+                     // 由于Table Offset是8字节对齐的,因此mask掉该dword的BIR部分,就是table offset的值
+    uint32_t dword2; // 该DWORD的组成为:[Pending Bit Offset][Pending Bit BIR2:0].
+                     // 由于Pending Bit Offset是8字节对齐的,因此mask掉该dword的BIR部分,就是Pending Bit Offset的值
+};
+
 /**
  * @brief msi描述符
  *
@@ -40,7 +77,7 @@ struct msi_desc_t
     struct pci_device_structure_header_t *pci_dev; // 对应的pci设备的结构体
     struct msi_msg_t msg;                          // msi消息
     uint16_t msi_index;                            // msi描述符的index
-    struct pci_msi_desc_t pci;                         // 与pci相关的msi描述符数据
+    struct pci_msi_desc_t pci;                     // 与pci相关的msi描述符数据
 };
 
 /**
@@ -54,7 +91,7 @@ struct msi_desc_t
  *
  * @return 返回码
  */
-int pci_enable_msi(struct msi_desc_t * msi_desc);
+int pci_enable_msi(struct msi_desc_t *msi_desc);
 
 /**
  * @brief 禁用指定设备的msi

+ 3 - 2
kernel/driver/pci/pci.c

@@ -503,7 +503,7 @@ void pci_get_device_structure(uint8_t class_code, uint8_t sub_class, struct pci_
  * @param cap_type c要寻找的capability类型
  * @return uint64_t cap list的偏移量
  */
-uint32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, int cap_type)
+int32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, uint32_t cap_type)
 {
     uint32_t cap_offset;
     switch (pci_dev->HeaderType)
@@ -524,7 +524,8 @@ uint32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci
     while (1)
     {
         tmp = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->func, cap_offset);
-        if (tmp & 0xff != cap_type)
+        kdebug("tmp & 0xff=%#010lx",tmp & 0xff);
+        if ((tmp & 0xff) != cap_type)
         {
             if ((tmp & 0xff00) >> 8)
             {

+ 9 - 2
kernel/driver/pci/pci.h

@@ -19,6 +19,13 @@ void pci_init();
 struct pci_device_structure_header_t
 {
     struct List list;
+
+    // 包含msix table地址的bar的mmio基地址
+    uint64_t msix_mmio_vaddr;
+    uint64_t msix_mmio_size;  // msix映射长度
+    uint32_t msix_offset;     // msix表的offset
+    uint16_t msix_table_size; // msix表的表项数量
+
     // ==== 以下三个变量表示该结构体所处的位置
     uint8_t bus;
     uint8_t device;
@@ -43,7 +50,7 @@ struct pci_device_structure_header_t
                            // |     bit7     |    bit6    | Bits 5-4 |     Bits 3-0    |
                            // | BIST Capable | Start BIST | Reserved | Completion Code |
                            // for more details, please visit https://wiki.osdev.org/PCI
-} __attribute__((packed));
+};
 
 /**
  * @brief 表头类型为0x0的pci设备结构
@@ -215,4 +222,4 @@ void pci_get_device_structure(uint8_t class_code, uint8_t sub_class, struct pci_
  * @param cap_type c要寻找的capability类型
  * @return uint64_t cap list的偏移量
  */
-uint32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, int cap_type);
+int32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, uint32_t cap_type);

+ 1 - 0
kernel/driver/usb/xhci/xhci.c

@@ -593,6 +593,7 @@ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg)
     msi_desc.edge_trigger = info->edge_trigger;
     msi_desc.processor = info->processor;
     msi_desc.pci.msi_attribute.is_64 = 1;
+    msi_desc.pci.msi_attribute.is_msix=1;
     // todo: QEMU是使用msix的,因此要先在pci中实现msix
     io_mfence();
     int retval = pci_enable_msi(&msi_desc);

+ 2 - 1
kernel/mm/mm.c

@@ -249,7 +249,8 @@ unsigned long page_init(struct Page *page, ul flags)
     {
         ++page->ref_counts;
         barrier();
-        ++page->zone->total_pages_link;
+        if (page->zone)
+            ++page->zone->total_pages_link;
     }
     page->anon_vma = NULL;
     spin_init(&(page->op_lock));