bugfix: 修复了无法收到xhci控制器中断的bug

This commit is contained in:
fslongjin 2022-08-24 14:30:23 +08:00
parent ff94280f77
commit e22fe35bb1
5 changed files with 134 additions and 26 deletions

View File

@ -14,7 +14,7 @@
/**
* @brief msi消息
*
*
* @param msi_desc msi描述符
* @return struct msi_msg_t* msi消息指针
*/
@ -23,5 +23,6 @@ struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc)
msi_desc->msg.address_hi = 0;
msi_desc->msg.address_lo = ia64_pci_get_arch_msi_message_address(msi_desc->processor);
msi_desc->msg.data = ia64_pci_get_arch_msi_message_data(msi_desc->irq_num, msi_desc->processor, msi_desc->edge_trigger, msi_desc->assert);
msi_desc->msg.vector_control = 0;
return &(msi_desc->msg);
}

View File

@ -23,6 +23,7 @@ static __always_inline struct pci_msix_cap_t __msi_read_msix_cap_list(struct msi
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;
@ -82,7 +83,7 @@ static __always_inline int __msix_map_table(struct pci_device_structure_header_t
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);
// 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);
@ -98,16 +99,19 @@ static __always_inline int __msix_map_table(struct pci_device_structure_header_t
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 = ((uint64_t)(msi_desc->msg.address_hi) << 32) | (msi_desc->msg.address_lo);
io_mfence();
++ptr;
*ptr = (msi_desc->msg.vector_control << 32) | (msi_desc->msg.data);
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
* @param msi_index
*/
static __always_inline void __msix_clear_entry(struct pci_device_structure_header_t *pci_dev, uint16_t msi_index)
{
@ -164,13 +168,15 @@ int pci_enable_msi(struct msi_desc_t *msi_desc)
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();
// 使能msi
// todo: disable intx
// 使能msi-x
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
tmp |= (1 << 16);
tmp |= (1 << 31);
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
}
else

View File

@ -70,6 +70,7 @@ uint pci_write_config(uchar bus, uchar slot, uchar func, uchar offset, uint32_t
// 构造pci配置空间地址
uint address = (uint)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint)0x80000000));
io_out32(PORT_PCI_CONFIG_ADDRESS, address);
// 写入数据
io_out32(PORT_PCI_CONFIG_DATA, data);

View File

@ -37,6 +37,8 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs);
static int xhci_hc_init_intr(int id);
static int xhci_hc_start_ports(int id);
static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring);
hardware_intr_controller xhci_hc_intr_controller =
{
.enable = xhci_hc_irq_enable,
@ -55,9 +57,6 @@ hardware_intr_controller xhci_hc_intr_controller =
32bit的寄存器中的偏移量8的位置开始读取1个字节
32bit的寄存器的0地址处开始读取32bit
*/
#define xhci_read_cap_reg8(id, offset) (*(uint8_t *)(xhci_hc[id].vbase + offset))
#define xhci_get_ptr_cap_reg8(id, offset) ((uint8_t *)(xhci_hc[id].vbase + offset))
#define xhci_write_cap_reg8(id, offset, value) (*(uint8_t *)(xhci_hc[id].vbase + offset) = (uint8_t)value)
#define xhci_read_cap_reg32(id, offset) (*(uint32_t *)(xhci_hc[id].vbase + offset))
#define xhci_get_ptr_cap_reg32(id, offset) ((uint32_t *)(xhci_hc[id].vbase + offset))
@ -79,6 +78,11 @@ hardware_intr_controller xhci_hc_intr_controller =
#define xhci_get_ptr_op_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase_op + offset))
#define xhci_write_op_reg64(id, offset, value) (*(uint64_t *)(xhci_hc[id].vbase_op + offset) = (uint64_t)value)
#define xhci_write_mem32(vaddr, value) (*(uint32_t *)(vaddr) = value)
#define xhci_write_mem64(vaddr, value) (*(uint64_t *)(vaddr) = value)
#define xhci_read_mem32(vaddr) (*(uint32_t *)(vaddr))
#define xhci_read_mem64(vaddr) (*(uint64_t *)(vaddr))
/**
* @brief
* @param id id
@ -267,7 +271,7 @@ static int xhci_hc_stop_legacy(int id)
do
{
// 判断当前entry是否为legacy support entry
if (xhci_read_cap_reg8(id, current_offset) == XHCI_XECP_ID_LEGACY)
if ((xhci_read_cap_reg32(id, current_offset) & 0xff) == XHCI_XECP_ID_LEGACY)
{
io_mfence();
// 接管控制权
@ -309,7 +313,7 @@ static int xhci_hc_stop_legacy(int id)
static int xhci_hc_start_sched(int id)
{
io_mfence();
xhci_write_op_reg32(id, XHCI_OPS_USBCMD, (1 << 0) | (1 >> 2) | (1 << 3));
xhci_write_op_reg32(id, XHCI_OPS_USBCMD, (1 << 0) | (1 << 2) | (1 << 3));
io_mfence();
usleep(100 * 1000);
}
@ -327,12 +331,6 @@ static int xhci_hc_stop_sched(int id)
io_mfence();
}
/**
* @brief
*
* @return uint32_t
*/
/**
* @brief Ex capability list中寻找符合指定的协议号的寄存器offsetcountflag信息
*
@ -588,17 +586,20 @@ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg)
struct msi_desc_t msi_desc;
memset(&msi_desc, 0, sizeof(struct msi_desc_t));
io_mfence();
msi_desc.irq_num = irq_num;
msi_desc.msi_index = 0;
msi_desc.pci_dev = (struct pci_device_structure_header_t *)xhci_hc[cid].pci_dev_hdr;
msi_desc.assert = info->assert;
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;
msi_desc.pci.msi_attribute.is_msix = 1;
// todo: QEMU是使用msix的因此要先在pci中实现msix
io_mfence();
int retval = pci_enable_msi(&msi_desc);
kdebug("pci retval = %d", retval);
kdebug("xhci irq %d installed.", irq_num);
return 0;
}
@ -764,6 +765,7 @@ static int xhci_hc_start_ports(int id)
}
}
kinfo("xHCI controller %d: Started %d ports.", id, cnt);
return 0;
}
/**
@ -833,6 +835,79 @@ static int xhci_hc_init_intr(int id)
return 0;
}
/**
* @brief doorbell寄存器
*
* @param id id
* @param slot_id usb控制器插槽id0
* @param value
*/
static __always_inline void __xhci_write_doorbell(const int id, const uint16_t slot_id, const uint32_t value)
{
// 确保写入门铃寄存器之前,所有的写操作均已完成
io_sfence();
xhci_write_cap_reg32(id, xhci_hc[id].db_offset + slot_id * sizeof(uint32_t), value);
io_sfence();
}
/**
* @brief xhci控制器发送命令
*
* @param id xhci控制器号
* @param trb
* @param do_ring doorbell register
* @return int
*/
static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring)
{
uint64_t origin_trb_vaddr = xhci_hc[id].cmd_trb_vaddr;
// 必须先写入参数和状态数据最后写入command
xhci_write_mem64(xhci_hc[id].cmd_trb_vaddr, trb->param); // 参数
xhci_write_mem32(xhci_hc[id].cmd_trb_vaddr + 8, trb->status); // 状态
xhci_write_mem32(xhci_hc[id].cmd_trb_vaddr + 12, trb->command); // 命令
xhci_hc[id].cmd_trb_vaddr += sizeof(struct xhci_TRB_t); // 跳转到下一个trb
{
// 如果下一个trb是link trb,则将下一个要操作的地址是设置为第一个trb
struct xhci_TRB_normal_t *ptr = (struct xhci_TRB_normal_t *)xhci_hc[id].cmd_trb_vaddr;
if (ptr->TRB_type == TRB_TYPE_LINK)
{
ptr->cycle = xhci_hc[id].cmd_trb_cycle;
xhci_hc[id].cmd_trb_vaddr = xhci_hc[id].cmd_ring_vaddr;
xhci_hc[id].cmd_trb_cycle ^= 1;
}
}
if (do_ring) // 按响命令门铃
{
kdebug("to ring..");
__xhci_write_doorbell(id, 0, 0);
kdebug("ring..");
// 等待中断产生
int timer = 20;
// Now wait for the interrupt to happen
// We use bit 31 of the command dword since it is reserved
while (timer && ((xhci_read_mem32(origin_trb_vaddr + 12) & (1 << 31)) == 0))
{
usleep(1000);
--timer;
}
uint32_t x = xhci_read_cap_reg32(id, xhci_hc[id].rts_offset + 0x20);
kdebug("ip=%#010lx", x);
if (timer == 0)
kwarn("USB xHCI Command Interrupt wait timed out.");
else
{
kdebug("interrupt done");
}
}
return 0;
}
/**
* @brief xhci控制器
*
@ -861,7 +936,12 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
xhci_hc[cid].controller_id = cid;
xhci_hc[cid].pci_dev_hdr = dev_hdr;
io_mfence();
pci_write_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0x4, 0x0006); // mem I/O access enable and bus master enable
{
uint32_t tmp = pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0x4);
tmp |= 0x6;
// mem I/O access enable and bus master enable
pci_write_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0x4, tmp);
}
io_mfence();
// 为当前控制器映射寄存器地址空间
xhci_hc[cid].vbase = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + XHCI_MAPPING_OFFSET + 65536 * xhci_hc[cid].controller_id;
@ -883,7 +963,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
// kdebug("hcc1.xECP=%#010lx", hcc1.xECP);
// 计算operational registers的地址
xhci_hc[cid].vbase_op = xhci_hc[cid].vbase + xhci_read_cap_reg8(cid, XHCI_CAPS_CAPLENGTH);
xhci_hc[cid].vbase_op = xhci_hc[cid].vbase + (xhci_read_cap_reg32(cid, XHCI_CAPS_CAPLENGTH) & 0xff);
io_mfence();
xhci_hc[cid].db_offset = xhci_read_cap_reg32(cid, XHCI_CAPS_DBOFF) & (~0x3); // bits [1:0] reserved
io_mfence();
@ -894,13 +974,18 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
xhci_hc[cid].context_size = (hcc1.csz) ? 64 : 32;
if (iversion < 0x95)
{
kwarn("Unsupported/Unknowned xHCI controller version: %#06x. This may cause unexpected behavior.", iversion);
}
{
// Write to the FLADJ register incase the BIOS didn't
uint32_t tmp = pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0x60);
tmp |= (0x20 << 8);
pci_write_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0x60, tmp);
}
// if it is a Panther Point device, make sure sockets are xHCI controlled.
if (((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0) & 0xffff) == 0x8086) &&
((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 2) & 0xffff) == 0x1E31) &&
(((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0) >> 16) & 0xffff) == 0x1E31) &&
((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 8) & 0xff) == 4))
{
kdebug("Is a Panther Point device");
@ -939,6 +1024,8 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
io_mfence();
// 创建command ring
xhci_hc[cid].cmd_ring_vaddr = xhci_create_ring(XHCI_CMND_RING_TRBS);
xhci_hc[cid].cmd_trb_vaddr = xhci_hc[cid].cmd_ring_vaddr;
if (unlikely(!xhci_is_aligned64(xhci_hc[cid].cmd_ring_vaddr))) // 地址不是按照64byte对齐
{
kerror("cmd ring isn't 64 byte aligned.");
@ -962,10 +1049,22 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
FAIL_ON_TO(xhci_hc_init_intr(cid), failed_free_dyn);
io_mfence();
++xhci_ctrl_count;
io_mfence();
spin_unlock(&xhci_controller_init_lock);
io_mfence();
// 发送nop
struct xhci_TRB_normal_t nop_trb = {0};
nop_trb.cycle = xhci_hc[cid].cmd_trb_cycle;
nop_trb.TRB_type = TRB_TYPE_NO_OP;
// nop_trb.ioc = 1;
kdebug("to send nop TRB");
xhci_send_command(cid, &nop_trb, true);
xhci_send_command(cid, &nop_trb, true);
kdebug("nop TRB send OK");
return;
failed_free_dyn:; // 释放动态申请的内存

View File

@ -390,6 +390,7 @@ struct xhci_host_controller_t
uint32_t page_size; // page size
uint64_t dcbaap_vaddr; // Device Context Base Address Array Pointer的虚拟地址
uint64_t cmd_ring_vaddr; // command ring的虚拟地址
uint64_t cmd_trb_vaddr; // 下一个要写入的trb的虚拟地址
uint64_t event_ring_vaddr; // event ring的虚拟地址
uint64_t event_ring_table_vaddr; // event ring table的虚拟地址
uint8_t cmd_trb_cycle; // 当前command ring cycle