123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- #include "msi.h"
- #include "pci.h"
- #include <common/errno.h>
- #include <mm/mmio.h>
- /**
- * @brief 生成msi消息
- *
- * @param msi_desc msi描述符
- * @return struct msi_msg_t* msi消息指针(在描述符内)
- */
- 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);
- io_lfence();
- 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 = {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.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表 //MSIX表不再单独映射(To do)
- *
- * @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映射到页表
- rs_map_phys(pci_dev->msix_mmio_vaddr, bar, pci_dev->msix_mmio_size, PAGE_KERNEL_PAGE);
- 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 = ((uint64_t)(msi_desc->msg.address_hi) << 32) | (msi_desc->msg.address_lo);
- io_mfence();
- ++ptr;
- io_mfence();
- *ptr = ((uint64_t)(msi_desc->msg.vector_control) << 32) | (msi_desc->msg.data);
- io_mfence();
- }
- /**
- * @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
- *
- * @param header 设备header
- * @param vector 中断向量号
- * @param processor 要投递到的处理器
- * @param edge_trigger 是否边缘触发
- * @param assert 是否高电平触发
- *
- * @return 返回码
- */
- int pci_enable_msi(struct msi_desc_t *msi_desc)
- {
- struct pci_device_structure_header_t *ptr = msi_desc->pci_dev;
- uint32_t cap_ptr;
- uint32_t tmp;
- uint16_t message_control;
- uint64_t message_addr;
- // 先尝试获取msi-x,若不存在,则获取msi capability
- if (msi_desc->pci.msi_attribute.is_msix)
- {
- cap_ptr = pci_enumerate_capability_list(ptr, 0x11);
- if (((int32_t)cap_ptr) < 0)
- {
- cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
- if (((int32_t)cap_ptr) < 0)
- return -ENOSYS;
- msi_desc->pci.msi_attribute.is_msix = 0;
- }
- }
- else
- {
- cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
- if (((int32_t)cap_ptr) < 0)
- return -ENOSYS;
- msi_desc->pci.msi_attribute.is_msix = 0;
- }
- // 获取msi消息
- msi_arch_get_msg(msi_desc);
- if (msi_desc->pci.msi_attribute.is_msix) // MSI-X
- {
- kdebug("is msix");
- // 读取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);
- io_mfence();
- // 设置msix的中断
- __msix_set_entry(msi_desc);
- io_mfence();
- // todo: disable intx
- // 使能msi-x
- tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
- tmp |= (1U << 31);
- pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
- }
- else
- {
- kdebug("is msi");
- tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
- message_control = (tmp >> 16) & 0xffff;
- // 写入message address
- message_addr = ((((uint64_t)msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo); // 获取message address
- pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
- if (message_control & (1 << 7)) // 64位
- pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8,
- (uint32_t)((message_addr >> 32) & 0xffffffff));
- // 写入message data
- tmp = msi_desc->msg.data;
- if (message_control & (1 << 7)) // 64位
- pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
- else
- pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
- // 使能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);
- }
- return 0;
- }
- /**
- * @brief 在已配置好msi寄存器的设备上,使能msi
- *
- * @param header 设备头部
- * @return int 返回码
- */
- int pci_start_msi(void *header)
- {
- struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
- uint32_t cap_ptr;
- uint32_t tmp;
- switch (ptr->HeaderType)
- {
- case 0x00: // general device
- if (!(ptr->Status & 0x10))
- return -ENOSYS;
- cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
- tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
- if (tmp & 0xff != 0x5)
- return -ENOSYS;
- // 使能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);
- break;
- case 0x01: // pci to pci bridge
- if (!(ptr->Status & 0x10))
- return -ENOSYS;
- cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
- tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
- if (tmp & 0xff != 0x5)
- return -ENOSYS;
- // 使能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);
- break;
- case 0x02: // pci to card bus bridge
- return -ENOSYS;
- break;
- default: // 不应该到达这里
- return -EINVAL;
- break;
- }
- return 0;
- }
- /**
- * @brief 禁用指定设备的msi
- *
- * @param header pci header
- * @return int
- */
- int pci_disable_msi(void *header)
- {
- struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
- uint32_t cap_ptr;
- uint32_t tmp;
- switch (ptr->HeaderType)
- {
- case 0x00: // general device
- if (!(ptr->Status & 0x10))
- return -ENOSYS;
- cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
- tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
- if (tmp & 0xff != 0x5)
- return -ENOSYS;
- // 禁用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);
- break;
- case 0x01: // pci to pci bridge
- if (!(ptr->Status & 0x10))
- return -ENOSYS;
- cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
- tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
- if (tmp & 0xff != 0x5)
- return -ENOSYS;
- // 禁用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);
- break;
- case 0x02: // pci to card bus bridge
- return -ENOSYS;
- break;
- default: // 不应该到达这里
- return -EINVAL;
- break;
- }
- return 0;
- }
|