2022-08-30 20:34:52 +08:00

328 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
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 = ((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 |= (1 << 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;
}