🆕 xhci:匹配usb2、usb3端口

This commit is contained in:
fslongjin 2022-07-20 14:29:22 +08:00
parent 10537cd1bc
commit 8e5f769a0e
4 changed files with 167 additions and 8 deletions

View File

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

View File

@ -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中寻找符合指定的协议号的寄存器offsetcountflag信息
*
* @param id id
* @param list_off
* @param version 23
* @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主机控制器的usb2usb3端口
*
@ -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控制寄存器

View File

@ -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项为空)
};
/**

2
run.sh
View File

@ -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