From 1f30417ec104ad067a59f93628f565437525b9d5 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Wed, 24 Aug 2022 23:42:32 +0800 Subject: [PATCH] =?UTF-8?q?new:=20xhci=E4=B8=AD=E6=96=AD=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/driver/usb/xhci/xhci.c | 168 ++++++++++++++++++++++++---------- kernel/driver/usb/xhci/xhci.h | 86 +++++++++++++++++ 2 files changed, 207 insertions(+), 47 deletions(-) diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index 30a81656..8319dd24 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -83,6 +83,11 @@ hardware_intr_controller xhci_hc_intr_controller = #define xhci_read_mem32(vaddr) (*(uint32_t *)(vaddr)) #define xhci_read_mem64(vaddr) (*(uint64_t *)(vaddr)) +// 读取xhci中断寄存器组的值 +#define xhci_read_intr_reg32(id, set_id, offset) (*(uint32_t *)(xhci_hc[id].vbase + xhci_hc[id].rts_offset + 0x20 * (set_id + 1) + offset)) +// 向xhci中断寄存器组写入值 +#define xhci_write_intr_reg32(id, set_id, offset, value) (*(uint32_t *)(xhci_hc[id].vbase + xhci_hc[id].rts_offset + 0x20 * (set_id + 1) + offset) = value) + /** * @brief 计算中断寄存器组虚拟地址 * @param id 主机控制器id @@ -129,47 +134,6 @@ hardware_intr_controller xhci_hc_intr_controller = ptr->cycle = 1; \ } while (0) -// Common TRB types -enum -{ - TRB_TYPE_NORMAL = 1, - TRB_TYPE_SETUP_STAGE, - TRB_TYPE_DATA_STAGE, - TRB_TYPE_STATUS_STAGE, - TRB_TYPE_ISOCH, - TRB_TYPE_LINK, - TRB_TYPE_EVENT_DATA, - TRB_TYPE_NO_OP, - TRB_TYPE_ENABLE_SLOT, - TRB_TYPE_DISABLE_SLOT = 10, - - TRB_TYPE_ADDRESS_DEVICE = 11, - TRB_TYPE_CONFIG_EP, - TRB_TYPE_EVALUATE_CONTEXT, - TRB_TYPE_RESET_EP, - TRB_TYPE_STOP_EP = 15, - TRB_TYPE_SET_TR_DEQUEUE, - TRB_TYPE_RESET_DEVICE, - TRB_TYPE_FORCE_EVENT, - TRB_TYPE_DEG_BANDWIDTH, - TRB_TYPE_SET_LAT_TOLERANCE = 20, - - TRB_TYPE_GET_PORT_BAND = 21, - TRB_TYPE_FORCE_HEADER, - TRB_TYPE_NO_OP_CMD, // 24 - 31 = reserved - - TRB_TYPE_TRANS_EVENT = 32, - TRB_TYPE_COMMAND_COMPLETION, - TRB_TYPE_PORT_STATUS_CHANGE, - TRB_TYPE_BANDWIDTH_REQUEST, - TRB_TYPE_DOORBELL_EVENT, - TRB_TYPE_HOST_CONTROLLER_EVENT = 37, - TRB_TYPE_DEVICE_NOTIFICATION, - TRB_TYPE_MFINDEX_WRAP, - // 40 - 47 = reserved - // 48 - 63 = Vendor Defined -}; - /** * @brief 在controller数组之中寻找可用插槽 * @@ -189,6 +153,32 @@ static int xhci_hc_find_available_id() return -1; } +/** + * @brief 从指定地址读取trb + * + * @param trb 要存储到的trb的地址 + * @param address 待读取trb的地址 + */ +static __always_inline void xhci_get_trb(struct xhci_TRB_t *trb, const uint32_t address) +{ + trb->param = xhci_read_mem64(address); + trb->status = xhci_read_mem32(address + 8); + trb->command = xhci_read_mem32(address + 12); +} + +/** + * @brief 将给定的trb写入指定的地址 + * + * @param trb 源trb + * @param address 拷贝的目标地址 + */ +static __always_inline void xhci_set_trb(struct xhci_TRB_t *trb, const uint32_t address) +{ + xhci_write_mem64(address, trb->param); + xhci_write_mem32(address + 8, trb->status); + xhci_write_mem32(address + 12, trb->command); +} + /** * @brief 停止xhci主机控制器 * @@ -594,7 +584,6 @@ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg) 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); kdebug("pci retval = %d", retval); @@ -624,8 +613,94 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) { // todo: handle irq kdebug("USB irq received."); -} + /* + 写入usb status寄存器,以表明当前收到了中断,清除usb status寄存器中的EINT位 + 需要先清除这个位,再清除interrupter中的pending bit) + */ + xhci_write_op_reg32(cid, XHCI_OPS_USBSTS, xhci_read_op_reg32(cid, XHCI_OPS_USBSTS)); + + // 读取第0个usb interrupter的intr management寄存器 + const uint32_t iman0 = xhci_read_intr_reg32(cid, 0, XHCI_IR_MAN); + kdebug("iman0=%d", iman0); + if ((iman0 & 3) == 3) // 中断被启用,且pending不为0 + { + // 写入1以清除该interrupter的pending bit + xhci_write_intr_reg32(cid, 0, XHCI_IR_MAN, iman0 | 3); + + struct xhci_TRB_t event_trb, origin_trb; // event ring trb以及其对应的command trb + uint64_t origin_vaddr; + // 暂存当前trb的起始地址 + uint64_t last_event_ring_vaddr = xhci_hc[cid].current_event_ring_vaddr; + + xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr); + + while ((event_trb.command & 1) == xhci_hc[cid].current_event_ring_cycle) // 循环处理处于当前周期的所有event ring + { + struct xhci_TRB_cmd_complete_t *event_trb_ptr = (struct xhci_TRB_cmd_complete_t *)&event_trb; + if ((event_trb.command & (1 << 2)) == 0) // 当前event trb不是由于short packet产生的 + { + switch (event_trb_ptr->code) // 判断它的完成码 + { + case TRB_COMP_TRB_SUCCESS: // trb执行成功,则将结果返回到对应的command ring的trb里面 + + switch (event_trb_ptr->TRB_type) // 根据event trb类型的不同,采取不同的措施 + { + case TRB_TYPE_COMMAND_COMPLETION: // 命令已经完成 + origin_vaddr = event_trb.param; + // 获取对应的command trb + xhci_get_trb(&origin_trb, origin_vaddr); + + switch (((struct xhci_TRB_normal_t *)&origin_trb)->TRB_type) + { + case TRB_TYPE_ENABLE_SLOT: // 源命令为enable slot + // 将slot id返回到命令TRB的command字段中 + origin_trb.command &= 0x00ffffff; + origin_trb.command |= (event_trb.command & 0xff000000); + origin_trb.status = event_trb.status; + break; + default: + origin_trb.status = event_trb.status; + break; + } + + // 标记该命令已经执行完成 + origin_trb.status |= XHCI_IRQ_DONE; + // 将command trb写入到表中 + xhci_set_trb(&origin_trb, origin_vaddr); + break; + } + break; + + default: + break; + } + } + else // 当前TRB是由short packet产生的 + { + switch (event_trb_ptr->TRB_type) + { + case TRB_TYPE_TRANS_EVENT: // 当前 event trb是 transfer event TRB + // If SPD was encountered in this TD, comp_code will be SPD, else it should be SUCCESS (specs 4.10.1.1) + xhci_write_mem32(event_trb.param, (event_trb.status | XHCI_IRQ_DONE)); // return code + bytes *not* transferred + break; + + default: + break; + } + } + + // 获取下一个event ring TRB + last_event_ring_vaddr = xhci_hc[cid].current_event_ring_vaddr; + xhci_hc[cid].current_event_ring_vaddr += sizeof(struct xhci_TRB_t); + xhci_get_trb(&event_trb, xhci_hc[cid].current_event_ring_vaddr); + } + + // 当前event ring cycle的TRB处理结束 + // 更新dequeue指针, 并清除event handler busy标志位 + xhci_write_intr_reg64(cid, 0, XHCI_IR_DEQUEUE, last_event_ring_vaddr | (1 << 3)); + } +} /** * @brief 重置端口 * @@ -795,6 +870,7 @@ static int xhci_hc_init_intr(int id) if (unlikely((int64_t)(retval) == -ENOMEM)) return -ENOMEM; xhci_hc[id].event_ring_table_vaddr = retval; + xhci_hc[id].current_event_ring_vaddr = xhci_hc[id].event_ring_vaddr; // 设置驱动程序要读取的下一个event ring trb的地址 retval = 0; xhci_hc[id].current_event_ring_cycle = 1; @@ -1005,9 +1081,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // ========== 设置USB host controller ========= // 获取页面大小 - kdebug("ops pgsize=%#010lx", xhci_read_op_reg32(cid, XHCI_OPS_PAGESIZE)); xhci_hc[cid].page_size = (xhci_read_op_reg32(cid, XHCI_OPS_PAGESIZE) & 0xffff) << 12; - kdebug("page size=%d", xhci_hc[cid].page_size); io_mfence(); // 获取设备上下文空间 xhci_hc[cid].dcbaap_vaddr = (uint64_t)kmalloc(2048, 0); // 分配2KB的设备上下文地址数组空间 @@ -1058,8 +1132,8 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // 发送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; + nop_trb.TRB_type = TRB_TYPE_ENABLE_SLOT; + nop_trb.ioc = 1; kdebug("to send nop TRB"); xhci_send_command(cid, &nop_trb, true); xhci_send_command(cid, &nop_trb, true); diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index 7ec3e635..deca79de 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -7,6 +7,8 @@ #define XHCI_MAX_ROOT_HUB_PORTS 128 // 本驱动程序最大支持127个root hub 端口(第0个保留) // ========== irq BEGIN =========== + +#define XHCI_IRQ_DONE (1<<31) // 当command trb 的status的第31位被驱动程序置位时,表明该trb已经执行完成(这是由于xhci规定,第31位可以由驱动程序自行决定用途) /** * @brief 每个xhci控制器的中断向量号 * @@ -393,11 +395,95 @@ struct xhci_host_controller_t uint64_t cmd_trb_vaddr; // 下一个要写入的trb的虚拟地址 uint64_t event_ring_vaddr; // event ring的虚拟地址 uint64_t event_ring_table_vaddr; // event ring table的虚拟地址 + uint64_t current_event_ring_vaddr; // 下一个要读取的event TRB的虚拟地址 uint8_t cmd_trb_cycle; // 当前command ring cycle uint8_t current_event_ring_cycle; // 当前event ring cycle struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空) }; +// Common TRB types +enum +{ + TRB_TYPE_NORMAL = 1, + TRB_TYPE_SETUP_STAGE, + TRB_TYPE_DATA_STAGE, + TRB_TYPE_STATUS_STAGE, + TRB_TYPE_ISOCH, + TRB_TYPE_LINK, + TRB_TYPE_EVENT_DATA, + TRB_TYPE_NO_OP, + TRB_TYPE_ENABLE_SLOT, + TRB_TYPE_DISABLE_SLOT = 10, + + TRB_TYPE_ADDRESS_DEVICE = 11, + TRB_TYPE_CONFIG_EP, + TRB_TYPE_EVALUATE_CONTEXT, + TRB_TYPE_RESET_EP, + TRB_TYPE_STOP_EP = 15, + TRB_TYPE_SET_TR_DEQUEUE, + TRB_TYPE_RESET_DEVICE, + TRB_TYPE_FORCE_EVENT, + TRB_TYPE_DEG_BANDWIDTH, + TRB_TYPE_SET_LAT_TOLERANCE = 20, + + TRB_TYPE_GET_PORT_BAND = 21, + TRB_TYPE_FORCE_HEADER, + TRB_TYPE_NO_OP_CMD, // 24 - 31 = reserved + + TRB_TYPE_TRANS_EVENT = 32, + TRB_TYPE_COMMAND_COMPLETION, + TRB_TYPE_PORT_STATUS_CHANGE, + TRB_TYPE_BANDWIDTH_REQUEST, + TRB_TYPE_DOORBELL_EVENT, + TRB_TYPE_HOST_CONTROLLER_EVENT = 37, + TRB_TYPE_DEVICE_NOTIFICATION, + TRB_TYPE_MFINDEX_WRAP, + // 40 - 47 = reserved + // 48 - 63 = Vendor Defined +}; + +// event ring trb的完成码 +enum +{ + TRB_COMP_TRB_SUCCESS = 1, + TRB_COMP_DATA_BUFFER_ERROR, + TRB_COMP_BABBLE_DETECTION, + TRB_COMP_TRANSACTION_ERROR, + TRB_COMP_TRB_ERROR, + TRB_COMP_STALL_ERROR, + TRB_COMP_RESOURCE_ERROR = 7, + TRB_COMP_BANDWIDTH_ERROR, + TRB_COMP_NO_SLOTS_ERROR, + TRB_COMP_INVALID_STREAM_TYPE, + TRB_COMP_SLOT_NOT_ENABLED, + TRB_COMP_EP_NOT_ENABLED, + TRB_COMP_SHORT_PACKET = 13, + TRB_COMP_RING_UNDERRUN, + TRB_COMP_RUNG_OVERRUN, + TRB_COMP_VF_EVENT_RING_FULL, + TRB_COMP_PARAMETER_ERROR, + TRB_COMP_BANDWITDH_OVERRUN, + TRB_COMP_CONTEXT_STATE_ERROR = 19, + TRB_COMP_NO_PING_RESPONSE, + TRB_COMP_EVENT_RING_FULL, + TRB_COMP_INCOMPATIBLE_DEVICE, + TRB_COMP_MISSED_SERVICE, + TRB_COMP_COMMAND_RING_STOPPED = 24, + TRB_COMP_COMMAND_ABORTED, + TRB_COMP_STOPPED, + TRB_COMP_STOPPER_LENGTH_ERROR, + TRB_COMP_RESERVED, + TRB_COMP_ISOCH_BUFFER_OVERRUN, + TRB_COMP_EVERN_LOST = 32, + TRB_COMP_UNDEFINED, + TRB_COMP_INVALID_STREAM_ID, + TRB_COMP_SECONDARY_BANDWIDTH, + TRB_COMP_SPLIT_TRANSACTION + /* 37 - 191 reserved */ + /* 192 - 223 vender defined errors */ + /* 224 - 225 vendor defined info */ +}; + /** * @brief 初始化xhci控制器 *