From e22fe35bb1b3125e508a70b793c6ad7098f43e62 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Wed, 24 Aug 2022 14:30:23 +0800 Subject: [PATCH] =?UTF-8?q?bugfix:=20=E4=BF=AE=E5=A4=8D=E4=BA=86=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=94=B6=E5=88=B0xhci=E6=8E=A7=E5=88=B6=E5=99=A8?= =?UTF-8?q?=E4=B8=AD=E6=96=AD=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/arch/x86_64/ia64_msi.c | 3 +- kernel/driver/pci/msi.c | 22 ++++-- kernel/driver/pci/pci.c | 1 + kernel/driver/usb/xhci/xhci.c | 133 +++++++++++++++++++++++++++++----- kernel/driver/usb/xhci/xhci.h | 1 + 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/kernel/arch/x86_64/ia64_msi.c b/kernel/arch/x86_64/ia64_msi.c index 647ee4bb..d7236f57 100644 --- a/kernel/arch/x86_64/ia64_msi.c +++ b/kernel/arch/x86_64/ia64_msi.c @@ -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); } \ No newline at end of file diff --git a/kernel/driver/pci/msi.c b/kernel/driver/pci/msi.c index 9b2cb180..e18b1fc2 100644 --- a/kernel/driver/pci/msi.c +++ b/kernel/driver/pci/msi.c @@ -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 diff --git a/kernel/driver/pci/pci.c b/kernel/driver/pci/pci.c index 2fecadca..e2ca3644 100644 --- a/kernel/driver/pci/pci.c +++ b/kernel/driver/pci/pci.c @@ -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); diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index dcfaa3e6..30a81656 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -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中寻找符合指定的协议号的寄存器offset、count、flag信息 * @@ -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控制器插槽id(0用作命令门铃,其他的用于具体的设备的门铃) + * @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:; // 释放动态申请的内存 diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index 14c960f7..7ec3e635 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -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