Browse Source

:new: xhci:匹配usb2、usb3端口

fslongjin 2 years ago
parent
commit
8e5f769a0e
4 changed files with 167 additions and 8 deletions
  1. 1 1
      kernel/common/kprint.h
  2. 153 2
      kernel/driver/usb/xhci/xhci.c
  3. 12 4
      kernel/driver/usb/xhci/xhci.h
  4. 1 1
      run.sh

+ 1 - 1
kernel/common/kprint.h

@@ -35,7 +35,7 @@
         printk("[ DEBUG ] (%s:%d)\t", __FILE__, __LINE__); \
         printk(__VA_ARGS__);                               \
         printk("\n");                                      \
-    } while (0);
+    } while (0)
 
 #define kwarn(...)                                 \
     do                                             \

+ 153 - 2
kernel/driver/usb/xhci/xhci.c

@@ -46,6 +46,18 @@ 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)
 
+/**
+ * @brief 判断端口信息
+ * @param cid 主机控制器id
+ * @param pid 端口id
+ */
+#define XHCI_PORT_IS_USB2(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_INFO) == XHCI_PROTOCOL_USB2)
+#define XHCI_PORT_IS_USB3(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_INFO) == XHCI_PROTOCOL_USB3)
+
+#define XHCI_PORT_IS_USB2_HSO(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_HSO) == XHCI_PROTOCOL_HSO)
+#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)
+
 #define FAIL_ON(value, to)        \
     do                            \
     {                             \
@@ -172,6 +184,53 @@ static int xhci_hc_stop_legacy(int id)
     return 0;
 }
 
+/**
+ * @brief
+ *
+ * @return uint32_t
+ */
+
+/**
+ * @brief 在Ex capability list中寻找符合指定的协议号的寄存器offset、count、flag信息
+ *
+ * @param id 主机控制器id
+ * @param list_off 列表项位置距离控制器虚拟基地址的偏移量
+ * @param version 要寻找的端口版本号(2或3)
+ * @param offset 返回的 Compatible Port Offset
+ * @param count 返回的 Compatible Port Count
+ * @param protocol_flag 返回的与协议相关的flag
+ * @return uint32_t 下一个列表项的偏移量
+ */
+static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset, uint32_t *count, uint16_t *protocol_flag)
+{
+    if (count)
+        *count = 0;
+
+    do
+    {
+        uint32_t dw0 = xhci_read_cap_reg32(id, list_off);
+        uint32_t next_list_off = (dw0 >> 8) & 0xff;
+        next_list_off = next_list_off ? (list_off + (next_list_off << 2)) : 0;
+
+        if ((dw0 & 0xff) == XHCI_XECP_ID_PROTOCOL && ((dw0 & 0xff000000) >> 24) == version)
+        {
+            uint32_t dw2 = xhci_read_cap_reg32(id, list_off + 8);
+
+            if (offset != NULL)
+                *offset = (uint32_t)(dw2 & 0xff);
+            if (count != NULL)
+                *count = (uint32_t)((dw2 & 0xff00) >> 8);
+            if (protocol_flag != NULL)
+                *protocol_flag = (uint16_t)((dw2 >> 16) & 0xffff);
+
+            return next_list_off;
+        }
+
+        list_off = next_list_off;
+    } while (list_off);
+
+    return 0;
+}
 /**
  * @brief 配对xhci主机控制器的usb2、usb3端口
  *
@@ -192,10 +251,102 @@ static int xhci_hc_pair_ports(int id)
 
     // 从hcs1获取端口数量
     xhci_hc[id].port_num = hcs1.max_ports;
-    kinfo("Found %d ports on xhci root hub.", hcs1.max_ports);
 
     // 找到所有的端口并标记其端口信息
 
+    xhci_hc[id].port_num_u2 = 0;
+    xhci_hc[id].port_num_u3 = 0;
+
+    uint32_t next_off = xhci_hc[id].ext_caps_off;
+    uint32_t offset, cnt;
+    uint16_t protocol_flags;
+
+    // 寻找所有的usb2端口
+    while (next_off)
+    {
+        next_off = xhci_hc_get_protocol_offset(id, next_off, 2, &offset, &cnt, &protocol_flags);
+
+        if (cnt)
+        {
+            for (int i = 0; i < cnt; ++i)
+            {
+                xhci_hc[id].ports[offset + i].offset = ++xhci_hc[id].port_num_u2;
+                xhci_hc[id].ports[offset + i].flags = XHCI_PROTOCOL_USB2;
+
+                // usb2 high speed only
+                if (protocol_flags & 2)
+                    xhci_hc[id].ports[offset + i].flags |= XHCI_PROTOCOL_HSO;
+            }
+        }
+    }
+
+    // 寻找所有的usb3端口
+    next_off = xhci_hc[id].ext_caps_off;
+    while (next_off)
+    {
+        next_off = xhci_hc_get_protocol_offset(id, next_off, 3, &offset, &cnt, &protocol_flags);
+
+        if (cnt)
+        {
+            for (int i = 0; i < cnt; ++i)
+            {
+                xhci_hc[id].ports[offset + i].offset = ++xhci_hc[id].port_num_u3;
+                xhci_hc[id].ports[offset + i].flags = XHCI_PROTOCOL_USB3;
+            }
+        }
+    }
+
+    // 将对应的USB2端口和USB3端口进行配对
+    for (int i = 1; i <= xhci_hc[id].port_num; ++i)
+    {
+        for (int j = i; j <= xhci_hc[id].port_num; ++j)
+        {
+            if (unlikely(i == j))
+                continue;
+
+            if ((xhci_hc[id].ports[i].offset == xhci_hc[id].ports[j].offset) &&
+                ((xhci_hc[id].ports[i].flags & XHCI_PROTOCOL_INFO) != (xhci_hc[id].ports[j].flags & XHCI_PROTOCOL_INFO)))
+            {
+                xhci_hc[id].ports[i].paired_port_num = j;
+                xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_HAS_PAIR;
+
+                xhci_hc[id].ports[j].paired_port_num = i;
+                xhci_hc[id].ports[j].flags |= XHCI_PROTOCOL_HAS_PAIR;
+            }
+        }
+    }
+
+    // 标记所有的usb3端口为激活状态
+    for (int i = 1; i <= xhci_hc[id].port_num; ++i)
+    {
+        if (XHCI_PORT_IS_USB3(id, i) ||
+            (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))))
+            xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_ACTIVE;
+    }
+    kinfo("Found %d ports on root hub, usb2 ports:%d, usb3 ports:%d", xhci_hc[id].port_num, xhci_hc[id].port_num_u2, xhci_hc[id].port_num_u3);
+
+    /*
+    // 打印配对结果
+    for (int i = 1; i <= xhci_hc[id].port_num; ++i)
+    {
+        if (XHCI_PORT_IS_USB3(id, i))
+        {
+            kdebug("USB3 port %d, offset=%d, pair with usb2 port %d, current port is %s", i, xhci_hc[id].ports[i].offset,
+                   xhci_hc[id].ports[i].paired_port_num, XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive");
+        }
+        else if (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))) // 单独的2.0接口
+        {
+            kdebug("Stand alone USB2 port %d, offset=%d, current port is %s", i, xhci_hc[id].ports[i].offset,
+                   XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive");
+        }
+        else if (XHCI_PORT_IS_USB2(id, i))
+        {
+             kdebug("USB2 port %d, offset=%d, current port is %s, has pair=%s", i, xhci_hc[id].ports[i].offset,
+                   XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive", XHCI_PORT_HAS_PAIR(id, i)?"true":"false");
+        }
+    }
+    */
+
     return 0;
 }
 
@@ -230,7 +381,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
 
     // 为当前控制器映射寄存器地址空间
     xhci_hc[cid].vbase = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + XHCI_MAPPING_OFFSET + 65536 * xhci_hc[cid].controller_id;
-    kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf));
+    // kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf));
     mm_map_phys_addr(xhci_hc[cid].vbase, dev_hdr->BAR0 & (~0xf), 65536, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, true);
 
     // 读取xhci控制寄存器

+ 12 - 4
kernel/driver/usb/xhci/xhci.h

@@ -2,8 +2,8 @@
 #include <driver/usb/usb.h>
 #include <driver/pci/pci.h>
 
-#define XHCI_MAX_HOST_CONTROLLERS 8
-#define XHCI_MAX_ROOT_HUB_PORTS 128
+#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
 #define XHCI_CAPS_CAPLENGTH 0x00 // Cap 寄存器组的长度
@@ -141,7 +141,7 @@ struct xhci_ops_config_reg_t
 // ID 部分的含义定义
 #define XHCI_XECP_ID_RESERVED 0
 #define XHCI_XECP_ID_LEGACY 1    // USB Legacy Support
-#define XHCI_XECP_ID_PROTOCAL 2  // Supported protocal
+#define XHCI_XECP_ID_PROTOCOL 2  // Supported protocol
 #define XHCI_XECP_ID_POWER 3     // Extended power management
 #define XHCI_XECP_ID_IOVIRT 4    // I/0 virtualization
 #define XHCI_XECP_ID_MSG 5       // Message interrupt
@@ -154,6 +154,14 @@ struct xhci_ops_config_reg_t
 #define XHCI_XECP_LEGACY_OS_OWNED (1 << 24)   // 当系统控制着该hc时,该位被置位
 #define XHCI_XECP_LEGACY_OWNING_MASK (XHCI_XECP_LEGACY_BIOS_OWNED | XHCI_XECP_LEGACY_OS_OWNED)
 
+// 端口信息标志位
+#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) // 当前端口是这个配对中,被激活的端口
+
 /**
  * @brief xhci端口信息
  *
@@ -179,7 +187,7 @@ struct xhci_host_controller_t
     uint16_t port_num;                                         // 总的端口数量
     uint8_t port_num_u2;                                       // usb 2.0端口数量
     uint8_t port_num_u3;                                       // usb 3端口数量
-    struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS];    // 指向端口信息数组的指针
+    struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS];    // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空)
 };
 
 /**

+ 1 - 1
run.sh

@@ -112,7 +112,7 @@ if [ $flag_can_run -eq 1 ]; then
         -device ahci,id=ahci \
         -device ide-hd,drive=disk,bus=ahci.0    \
         -usb    \
-        -device qemu-xhci,id=xhci 
+        -device qemu-xhci,id=xhci,p2=8,p3=4
 
     fi
 else