diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index 22000c4d..efea0cf2 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,8 @@ static struct xhci_host_controller_t xhci_hc[XHCI_MAX_HOST_CONTROLLERS] = {0}; #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_is_aligned64(addr) ((addr & 0x3f) == 0) // 是否64bytes对齐 + /** * @brief 判断端口信息 * @param cid 主机控制器id @@ -58,6 +61,21 @@ static struct xhci_host_controller_t xhci_hc[XHCI_MAX_HOST_CONTROLLERS] = {0}; #define XHCI_PORT_HAS_PAIR(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_HAS_PAIR) == XHCI_PROTOCOL_HAS_PAIR) #define XHCI_PORT_IS_ACTIVE(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_ACTIVE) == XHCI_PROTOCOL_ACTIVE) +/** + * @brief 设置link TRB的命令(dword3) + * + */ +#define xhci_TRB_set_link_cmd(trb_vaddr) \ + do \ + { \ + struct xhci_TRB_normal_t *ptr = (struct xhci_TRB_normal_t *)trb_vaddr; \ + ptr->TRB_type = TRB_TYPE_LINK; \ + ptr->ioc = 0; \ + ptr->chain = 0; \ + ptr->ent = 0; \ + ptr->cycle = 1; \ + } while (0) + #define FAIL_ON(value, to) \ do \ { \ @@ -65,6 +83,47 @@ static struct xhci_host_controller_t xhci_hc[XHCI_MAX_HOST_CONTROLLERS] = {0}; goto to; \ } 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数组之中寻找可用插槽 * @@ -239,15 +298,9 @@ static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int */ static int xhci_hc_pair_ports(int id) { - struct xhci_caps_HCCPARAMS1_reg_t hcc1; - struct xhci_caps_HCCPARAMS2_reg_t hcc2; struct xhci_caps_HCSPARAMS1_reg_t hcs1; - struct xhci_caps_HCSPARAMS2_reg_t hcs2; - memcpy(&hcc1, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCCPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); - memcpy(&hcc2, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCCPARAMS2), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); memcpy(&hcs1, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); - memcpy(&hcs2, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS2), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); // 从hcs1获取端口数量 xhci_hc[id].port_num = hcs1.max_ports; @@ -350,6 +403,24 @@ static int xhci_hc_pair_ports(int id) return 0; } +/** + * @brief 创建ring,并将最后一个trb指向头一个trb + * + * @param trbs 要创建的trb数量 + * @return uint64_t + */ +static uint64_t xhci_create_ring(int trbs) +{ + int total_size = trbs * sizeof(struct xhci_TRB_t); + const uint64_t vaddr = (uint64_t)kmalloc(total_size, 0); + memset(vaddr, 0, total_size); + + // 设置最后一个trb为link trb + xhci_TRB_set_link_cmd(vaddr + total_size - sizeof(sizeof(struct xhci_TRB_t))); + + return vaddr; +} + /** * @brief 初始化xhci控制器 * @@ -386,16 +457,26 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // 读取xhci控制寄存器 uint16_t iversion = *(uint16_t *)(xhci_hc[cid].vbase + XHCI_CAPS_HCIVERSION); - uint32_t hcc1 = xhci_read_cap_reg32(cid, XHCI_CAPS_HCCPARAMS1); + struct xhci_caps_HCCPARAMS1_reg_t hcc1; + struct xhci_caps_HCCPARAMS2_reg_t hcc2; + + struct xhci_caps_HCSPARAMS1_reg_t hcs1; + struct xhci_caps_HCSPARAMS2_reg_t hcs2; + memcpy(&hcc1, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCCPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); + memcpy(&hcc2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCCPARAMS2), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); + memcpy(&hcs1, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); + memcpy(&hcs2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS2), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); + + // 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].db_offset = xhci_read_cap_reg32(cid, XHCI_CAPS_DBOFF) & (~0x3); // bits [1:0] reserved xhci_hc[cid].rts_offset = xhci_read_cap_reg32(cid, XHCI_CAPS_RTSOFF) & (~0x1f); // bits [4:0] reserved. - xhci_hc[cid].ext_caps_off = ((hcc1 & 0xffff0000) >> 16) * 4; - xhci_hc[cid].context_size = (hcc1 & (1 << 2)) ? 64 : 32; + xhci_hc[cid].ext_caps_off = (hcc1.xECP) * 4; + xhci_hc[cid].context_size = (hcc1.csz) ? 64 : 32; if (iversion < 0x95) { @@ -414,18 +495,43 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // 重置xhci控制器 FAIL_ON(xhci_hc_reset(cid), failed); + // 关闭legacy支持 FAIL_ON(xhci_hc_stop_legacy(cid), failed); + // 端口配对 FAIL_ON(xhci_hc_pair_ports(cid), failed); + // 获取页面大小 + xhci_hc[cid].page_size = (xhci_read_op_reg32(cid, XHCI_OPS_PAGESIZE) & 0xffff) << 12; + kdebug("pg size=%d", xhci_hc[cid].page_size); + + // 获取设备上下文空间 + xhci_hc[cid].dcbaap_vaddr = (uint64_t)kmalloc(2048, 0); // 分配2KB的设备上下文地址数组空间 + memset(xhci_hc[cid].dcbaap_vaddr, 0, 2048); + + kdebug("dcbaap_vaddr=%#018lx", xhci_hc[cid].dcbaap_vaddr); + if (unlikely(!xhci_is_aligned64(xhci_hc[cid].dcbaap_vaddr))) // 地址不是按照64byte对齐 + { + kerror("dcbaap isn't 64 byte aligned."); + goto failed_free_dyn; + } + // 写入dcbaap + xhci_write_cap_reg64(cid, XHCI_OPS_DCBAAP, virt_2_phys(xhci_hc[cid].dcbaap_vaddr)); + xhci_hc[cid].cmd_ring_vaddr = xhci_create_ring(XHCI_CMND_RING_TRBS); ++xhci_ctrl_count; spin_unlock(&xhci_controller_init_lock); return; + +failed_free_dyn:; // 释放动态申请的内存 + if (xhci_hc[cid].dcbaap_vaddr) + kfree(xhci_hc[cid].dcbaap_vaddr); + failed:; // 取消地址映射 mm_unmap(xhci_hc[cid].vbase, 65536); // 清空数组 memset((void *)&xhci_hc[cid], 0, sizeof(struct xhci_host_controller_t)); + failed_exceed_max:; kerror("Failed to initialize controller: bus=%d, dev=%d, func=%d", dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func); spin_unlock(&xhci_controller_init_lock); diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index f9e09dfb..fa472952 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -2,7 +2,7 @@ #include #include -#define XHCI_MAX_HOST_CONTROLLERS 4 // 本驱动程序最大支持4个xhci root hub controller +#define XHCI_MAX_HOST_CONTROLLERS 4 // 本驱动程序最大支持4个xhci root hub controller #define XHCI_MAX_ROOT_HUB_PORTS 128 // 本驱动程序最大支持127个root hub 端口(第0个保留) // xhci Capability Registers offset @@ -157,10 +157,134 @@ struct xhci_ops_config_reg_t // 端口信息标志位 #define XHCI_PROTOCOL_USB2 0 #define XHCI_PROTOCOL_USB3 1 -#define XHCI_PROTOCOL_INFO (1<<0) // 1->usb3, 0->usb2 -#define XHCI_PROTOCOL_HSO (1<<1) // 1-> usb2 high speed only -#define XHCI_PROTOCOL_HAS_PAIR (1<<2) // 当前位被置位,意味着当前端口具有一个与之配对的端口 -#define XHCI_PROTOCOL_ACTIVE (1<<3) // 当前端口是这个配对中,被激活的端口 +#define XHCI_PROTOCOL_INFO (1 << 0) // 1->usb3, 0->usb2 +#define XHCI_PROTOCOL_HSO (1 << 1) // 1-> usb2 high speed only +#define XHCI_PROTOCOL_HAS_PAIR (1 << 2) // 当前位被置位,意味着当前端口具有一个与之配对的端口 +#define XHCI_PROTOCOL_ACTIVE (1 << 3) // 当前端口是这个配对中,被激活的端口 + +// TRB的Transfer Type可用值定义 +#define XHCI_TRB_TRT_NO_DATA 0 +#define XHCI_TRB_TRT_RESERVED 1 +#define XHCI_TRB_TRT_OUT_DATA 2 +#define XHCI_TRB_TRT_IN_DATA 3 + +#define XHCI_CMND_RING_TRBS 128 // TRB num of command ring, not more than 4096 + +#define XHCI_TRBS_PER_RING 256 + +/** + * @brief xhci通用TRB结构 + * + */ +struct xhci_TRB_t +{ + uint64_t param; // 参数 + uint32_t status; + uint32_t command; +} __attribute__((packed)); +struct xhci_TRB_normal_t +{ + uint64_t buf_paddr; // 数据缓冲区物理地址 + + unsigned transfer_length : 17; // 传输数据长度 + unsigned TD_size : 5; // 传输描述符中剩余的数据包的数量 + unsigned intr_target : 10; // 中断目标 [0:MaxIntrs-1] + + unsigned cycle : 1; // used to mark the enqueue pointer of transfer ring + unsigned ent : 1; // evaluate next TRB before updating the endpoint's state + unsigned isp : 1; // Interrupt on short packet bit + unsigned ns : 1; // No snoop + unsigned chain : 1; // The chain bit is used to tell the controller that this + // TRB is associated with the next TRB in the TD + unsigned ioc : 1; // 完成时发起中断 + unsigned idt : 1; // Immediate Data + unsigned resv : 2; // Reserved and zero'd + unsigned bei : 1; // Block event interrupt + unsigned TRB_type : 6; // TRB类型 + uint16_t Reserved; // 保留且置为0 +} __attribute__((packed)); + +struct xhci_TRB_setup_state_t +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + + uint16_t wIndex; + uint16_t wLength; + + unsigned transfer_legth : 17; + unsigned resv1 : 5; // Reserved and zero'd + unsigned intr_target : 10; + + unsigned cycle : 1; + unsigned resv2 : 4; // Reserved and zero'd + unsigned ioc : 1; + unsigned idt : 1; + unsigned resv3 : 3; // Reserved and zero'd + unsigned TRB_type : 6; + unsigned trt : 2; // Transfer type + unsigned resv4 : 14; // Reserved and zero'd + +} __attribute__((packed)); + +struct xhci_TRB_data_stage_t +{ + uint64_t buf_paddr; // 数据缓冲区物理地址 + + unsigned transfer_length : 17; // 传输数据长度 + unsigned TD_size : 5; // 传输描述符中剩余的数据包的数量 + unsigned intr_target : 10; // 中断目标 [0:MaxIntrs-1] + + unsigned cycle : 1; // used to mark the enqueue pointer of transfer ring + unsigned ent : 1; // evaluate next TRB before updating the endpoint's state + unsigned isp : 1; // Interrupt on short packet bit + unsigned ns : 1; // No snoop + unsigned chain : 1; // The chain bit is used to tell the controller that this + // TRB is associated with the next TRB in the TD + unsigned ioc : 1; // 完成时发起中断 + unsigned idt : 1; // Immediate Data + unsigned resv : 3; // Reserved and zero'd + unsigned TRB_type : 6; // TRB类型 + unsigned dir : 1; // 0 -> out packet + // 1 -> in packet + unsigned Reserved : 15; // 保留且置为0 +} __attribute__((packed)); + +struct xhci_TRB_status_stage_t +{ + uint64_t resv1; // Reserved and zero'd + + unsigned resv2 : 22; // Reserved and zero'd + unsigned intr_target : 10; // 中断目标 [0:MaxIntrs-1] + + unsigned cycle : 1; // used to mark the enqueue pointer of transfer ring + unsigned ent : 1; // evaluate next TRB before updating the endpoint's state + unsigned resv3 : 2; // Reserved and zero'd + unsigned chain : 1; // The chain bit is used to tell the controller that this + // TRB is associated with the next TRB in the TD + unsigned ioc : 1; // 完成时发起中断 + unsigned resv4 : 4; // Reserved and zero'd + unsigned TRB_type : 6; // TRB类型 + unsigned dir : 1; // 0 -> out packet + // 1 -> in packet + unsigned Reserved : 15; // 保留且置为0 +} __attribute__((packed)); + +struct xhci_TRB_cmd_complete_t +{ + uint64_t cmd_trb_pointer_paddr; // 指向生成当前Event TRB的TRB的物理地址(16bytes对齐) + + unsigned resv1 : 24; // Reserved and zero'd + uint8_t code; // Completion code + + unsigned cycle : 1; // cycle bit + unsigned resv2 : 9; // Reserved and zero'd + unsigned TRB_type : 6; // TRB类型 + uint8_t VF_ID; + uint8_t slot_id; // the id of the slot associated with the + // command that generated the event +} __attribute__((packed)); /** * @brief xhci端口信息 @@ -187,6 +311,9 @@ struct xhci_host_controller_t uint16_t port_num; // 总的端口数量 uint8_t port_num_u2; // usb 2.0端口数量 uint8_t port_num_u3; // usb 3端口数量 + uint8_t page_size; // page size + uint64_t dcbaap_vaddr; // Device Context Base Address Array Pointer的虚拟地址 + uint64_t cmd_ring_vaddr; // command ring的虚拟地址 struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空) };