xhci 数据结构
xhci 数据结构
xhci 数据结构主要在手册上有详细的定义,本文根据手册进行归纳总结:
重点关注的包括:
- device context
- trb ring
- trb
device context设备上下文
设备上下文数据结构由xHC管理,用于向系统软件报告设备配置和状态信息。设备上下文数据结构由32个数据结构的数组组成。第一个上下文数据结构(索引=“0”)是Slot Context数据结构。其余上下文数据结构是“端点上下文”数据结构
在枚举USB设备的过程中,系统软件会在主机内存中为该设备分配设备上下文数据结构,并将其初始化为“0”。然后,使用地址设备命令将数据结构的所有权传递给xHC。xHC保留对设备上下文的所有权,直到使用“禁用插槽命令”禁用了设备插槽为止。设备上下文数据结构由xHC拥有时,应被系统软件视为只读
其中主要分为slot 上下文 , 和 endpoint 上下文,在host xhci 中有定义
616 struct xhci_slot_ctx {617 __le32 dev_info;618 __le32 dev_info2;619 __le32 tt_info;620 __le32 dev_state;621 /* offset 0x10 to 0x1f reserved for HC internal use */622 __le32 reserved[4];623 };
700 struct xhci_ep_ctx {701 __le32 ep_info;702 __le32 ep_info2;703 __le64 deq;704 __le32 tx_info;705 /* offset 0x14 - 0x1f reserved for HC internal use */706 __le32 reserved[3];707 };
slot 上下文
Slot主要是有关 包含与整个设备有关的信息,或影响USB设备的所有端点的信息。Slot Context提供的信息包括: 控制,状态,寻址和电源管理。
作为设备上下文成员,xHC使用插槽上下文数据结构将设备参数的当前值报告给系统软件。
xHC报告的插槽状态标识设备的当前状态,并与USB规范中描述的USB设备状态紧密对应。
设备上下文的Slot Context数据结构也称为“Output Slot Context”。 作为输入上下文成员,系统软件使用Slot
Context数据结构将命令参数传递给主机控制器。 输入上下文的Slot Context数据结构也称为“Input Slot Context”。
如果针对设备插槽的命令成功执行,则xHC将在生成Command Completion Event 之前更新输出插槽上下文,以反映其正在主动使用的参数值来管理设备。
插槽上下文的xHCI保留区域可用作xHC实现定义的暂存器。
插槽上下文中的所有保留字段仅供xHC使用,除非插槽处于“禁用”状态,否则不得由系统软件修改。
endpoint 上下文
重点参数:
针对iso通信:
在xhci.c 中进行了初始化:
1418 /* Set up an endpoint with one ring segment. Do not allocate stream rings.
1419 * Drivers will have to call usb_alloc_streams() to do that.
1420 */
1421 int xhci_endpoint_init(struct xhci_hcd *xhci,
1422 struct xhci_virt_device *virt_dev,
1423 struct usb_device *udev,
1424 struct usb_host_endpoint *ep,
1425 gfp_t mem_flags)
1426 {
...1494 /* Set up the endpoint ring */
1495 virt_dev->eps[ep_index].new_ring =
1496 xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
1497 if (!virt_dev->eps[ep_index].new_ring)
1498 return -ENOMEM;
...
1503 /* Fill the endpoint context */
1504 ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
1505 EP_INTERVAL(interval) |
1506 EP_MULT(mult));
1507 ep_ctx->ep_info2 = cpu_to_le32(EP_TYPE(endpoint_type) |
1508 MAX_PACKET(max_packet) |
1509 MAX_BURST(max_burst) |
1510 ERROR_COUNT(err_count));
1511 ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma |
1512 ep_ring->cycle_state);
1513
1514 ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
1515 EP_AVG_TRB_LENGTH(avg_trb_len));...
ring
Ring是一个循环队列,xHC使用三种类型的Ring:
- Command Ring:(每个XHC一个)软件使用Command Ring将命令发送给xHC。使系统软件能够发出命令以枚举USB设备,配置xHC以支持这些设备以及协调虚拟化功能。
- Event Ring:(每个中断一个)每个中断器的一种循环队列,为xHC提供了一种向系统软件报告的方式:数据传输和命令完成状态,根集线器端口状态更改以及其他与xHC相关的事件。或者说:xHC使用事件环返回状态和命令结果,并将其传输到系统软件。
- Transfer Ring:(每个Endpoint或Stream一个)Transfer Ring被用来在内存和设备Endpoint之间传输数据。
备注:每个设备,插入的过程中,会根据设备反馈的设备描述符,注册相应的多个endpoint,后面我单独写一篇,usb设备插入注册,解析设备描述符的过程。
1589 struct xhci_ring {
1590 struct xhci_segment *first_seg;
1591 struct xhci_segment *last_seg;
1592 union xhci_trb *enqueue;
1593 struct xhci_segment *enq_seg;
1594 union xhci_trb *dequeue;
1595 struct xhci_segment *deq_seg;
1596 struct list_head td_list;
1597 /*
1598 * Write the cycle state into the TRB cycle field to give ownership of
1599 * the TRB to the host controller (if we are the producer), or to check
1600 * if we own the TRB (if we are the consumer). See section 4.9.1.
1601 */
1602 u32 cycle_state;
1603 unsigned int stream_id;
1604 unsigned int num_segs;
1605 unsigned int num_trbs_free;
1606 unsigned int num_trbs_free_temp;
1607 unsigned int bounce_buf_len;
1608 enum xhci_ring_type type;
1609 bool last_td_was_short;
1610 struct radix_tree_root *trb_address_map;
1611 };
Transfer Ring
重点介绍每个endpoint 上的Transfer Ring
将需要硬件完成的USB传输,通过TRB的形式,将信息提交给硬件,放入RING当中,放入的位置为当前ENQUEUE PTR的位置,每放一个,ENQUEUE PTR向前跨一步,遇到LINK TRB,则跳转到LINK TRB指向的位置
而硬件则按DEQUEUE PTR指向的位置,取出TRB到CACHE当中,执行该TRB,同样,每执行一个,则ADVANCE 该 DEQUEUE PTR,遇LINK TRB,跳转。
TD表示一个USB TRANSFER(不同于USB TRANSACTION)
在TRB当中,有一个CH BIT,如果一处TD由多个TRB构成,则软件需要将除最后一个TRB的所有CH BIT置位。
trb 的结构:
xhci 发送数据分析:
概述:
从xhci_urb_enqueue 开始看:
1433 static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
1434 {
···
1519 case USB_ENDPOINT_XFER_CONTROL:
1520 ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
1521 slot_id, ep_index);
···
3211 int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
3212 struct urb *urb, int slot_id, unsigned int ep_index)
3213 {
···
246 ret = prepare_transfer(xhci, xhci->devs[slot_id],
3247 ep_index, urb->stream_id,
3248 num_trbs, urb, 0, mem_flags);
····3323 queue_trb(xhci, ring, more_trbs_coming | need_zero_pkt,
3324 lower_32_bits(send_addr),
3325 upper_32_bits(send_addr),
3326 length_field,
3327 field);
···
2828 static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
2829 bool more_trbs_coming,
2830 u32 field1, u32 field2, u32 field3, u32 field4)
2831 {
2832 struct xhci_generic_trb *trb;
2833
2834 trb = &ring->enqueue->generic;
2835 trb->field[0] = cpu_to_le32(field1);
2836 trb->field[1] = cpu_to_le32(field2);
2837 trb->field[2] = cpu_to_le32(field3);
2838 /* make sure TRB is fully written before giving it to the controller */
2839 wmb();
2840 trb->field[3] = cpu_to_le32(field4);
2841
2842 trace_xhci_queue_trb(ring, trb);
2843
2844 inc_enq(xhci, ring, more_trbs_coming);
2845 }
2846
通过inc_enq 向xhci ring 中写数据,更新指针enqueue。
204 static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,205 bool more_trbs_coming)206 {207 u32 chain;208 union xhci_trb *next;209 210 chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;211 /* If this is not event ring, there is one less usable TRB */212 if (!trb_is_link(ring->enqueue))213 ring->num_trbs_free--;214 next = ++(ring->enqueue);
xhci 接收数据分析:
xhci 的中断处理函数xhci_irq 调用函数 xhci_handle_event
2625 static int xhci_handle_event(struct xhci_hcd *xhci)
2626 {
2651 switch (le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) {
2652 case TRB_TYPE(TRB_COMPLETION):
2653 handle_cmd_completion(xhci, &event->event_cmd);
2654 break;
2655 case TRB_TYPE(TRB_PORT_STATUS):
2656 handle_port_status(xhci, event);
2657 update_ptrs = 0;
2658 break;
2659 case TRB_TYPE(TRB_TRANSFER):
2660 ret = handle_tx_event(xhci, &event->trans_event);
2661 if (ret >= 0)
2662 update_ptrs = 0;
2663 break;
2664 case TRB_TYPE(TRB_DEV_NOTE):
2665 handle_device_notification(xhci, event);
2666 break;
2667 default:
2668 if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
2669 TRB_TYPE(48))
2670 handle_vendor_event(xhci, event);
2671 else
2672 xhci_warn(xhci, "ERROR unknown event type %d\n",
2673 TRB_FIELD_TO_TYPE(
2674 le32_to_cpu(event->event_cmd.flags)));
2675 }
其中判断,trb 的类型:
#define TRB_TYPE(p) ((p) << 10)
如果类型是#define TRB_COMPLETION 33, 则表示传输完成,调用handle_cmd_completion,
则会调用函数handle_cmd_completion -> xhci_handle_cmd_set_deq -> update_ring_for_set_deq_completion
在函数update_ring_for_set_deq_completion中更新指针dequeue
975 static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,976 struct xhci_virt_device *dev,977 struct xhci_ring *ep_ring,978 unsigned int ep_index)979 {980 union xhci_trb *dequeue_temp;981 int num_trbs_free_temp;982 bool revert = false;983 984 num_trbs_free_temp = ep_ring->num_trbs_free;985 dequeue_temp = ep_ring->dequeue;986 987 /* If we get two back-to-back stalls, and the first stalled transfer988 * ends just before a link TRB, the dequeue pointer will be left on989 * the link TRB by the code in the while loop. So we have to update990 * the dequeue pointer one segment further, or we'll jump off991 * the segment into la-la-land.992 */993 if (trb_is_link(ep_ring->dequeue)) {994 ep_ring->deq_seg = ep_ring->deq_seg->next;995 ep_ring->dequeue = ep_ring->deq_seg->trbs;996 }997 998 while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {999 /* We have more usable TRBs */
1000 ep_ring->num_trbs_free++;
1001 ep_ring->dequeue++;
1002 if (trb_is_link(ep_ring->dequeue)) {
1003 if (ep_ring->dequeue ==
1004 dev->eps[ep_index].queued_deq_ptr)
1005 break;
1006 ep_ring->deq_seg = ep_ring->deq_seg->next;
1007 ep_ring->dequeue = ep_ring->deq_seg->trbs;
1008 }
1009 if (ep_ring->dequeue == dequeue_temp) {
1010 revert = true;
1011 break;
1012 }
1013 }
1014
1015 if (revert) {
1016 xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
1017 ep_ring->num_trbs_free = num_trbs_free_temp;
1018 }
1019 }
相关文章:

xhci 数据结构
xhci 数据结构 xhci 数据结构主要在手册上有详细的定义,本文根据手册进行归纳总结: 重点关注的包括: device contexttrb ringtrb device context设备上下文 设备上下文数据结构由xHC管理,用于向系统软件报告设备配置和状态信息。…...

Go——Goroutine介绍
一. 并发介绍 进程和线程 进程是程序在操作系统中一次执行过程,系统进程资源分配和调度的一个独立单位。线程是进程执行的实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程可以创建和撤销多个线程,…...
Centos7,部署etcd集群,基于二进制包,https安全通讯
由于etcd集群https通讯,所以需要自建CA数字证书,学习使用https部署etcd集群前,可以先完成一下,基于http通信的etcd集群: 关于CA原理以及工作可以阅读,以下两篇文章: CA工作原理 对称加密与非对…...
设置MariaDB,创建新库,新用户并授权其可以从任何主机登录
OS:CENTOS 7 1、从系统进入MariaDB # mysql -u root -p 这里的root是指MariaDB的管理员用户,和系统的root不搭边,只是同名而已。 2、看下有哪些库、用户 MariaDB [(none)]> show databases; MariaDB [(none)]>select user,host from mysql.us…...

每日一VUE——组件的生命周期
文章目录 VUE组件的生命周期生命周期钩子函数实例创建Teleport VUE组件的生命周期 组件生命周期 组件从创建到挂载、更新、到销毁的一系列过程被称为组件的生命周期。 生命周期函数 在组件的各个生命周期节点执行的函数,为生命周期钩子函数。 生命周期钩子函数…...

Redis中的BigKey
Redis中的BigKey 文章目录 Redis中的BigKey什么是BigKey?BigKey的危害找到Bigkey删除BigKey优化BigKeyBigKey对持久化的影响对AOF日志的影响对AOF重写和RDB的影响 什么是BigKey? 大 key 并不是指 key 的值很大,而是 key 对应的 value 很大。…...

MySQL中的存储过程详解(上篇)
使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法,看完代码自己敲一遍,十分有用 拖动表名到查询文件中就可以直接把名字拉进来中括号,就代表可写可不写 目录 1.认识存储过程 1.1 存储过程的作用 1.2 存储过程简介…...

面试官:说一说CyclicBarrier的妙用!我:这个没用过...
写在开头 面试官:同学,AQS的原理知道吗? 我:学过一点,抽象队列同步器,Java中很多同步工具都是基于它的… 面试官:好的,那其中CyclicBarrier学过吗?讲一讲它的妙用吧 我&…...

MySQL高可用搭建方案MHA
MHA架构介绍 MHA是Master High Availability的缩写,它是目前MySQL高可用方面的一个相对成熟的解决方案,其核心是使用perl语言编写的一组脚本,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中&am…...

【vue】用vite创建vue项目
前置要求 要有Node.js 1. 用vite创建vue项目 在cmd中,进入一个文件夹 在文件资源管理器上面的文件目录中,输入cmd,回车在cmd中通过cd命令进入对应文件夹 创建项目 npm create vitelatest # 创建项目创建项目过程中的一些选项 Ok to pro…...

内网渗透-内网环境下的横向移动总结
内网环境下的横向移动总结 文章目录 内网环境下的横向移动总结前言横向移动威胁 威胁密码安全 威胁主机安全 威胁信息安全横向移动威胁的特点 利用psexec 利用psexec.exe工具msf中的psexec 利用windows服务 sc命令 1.与靶机建立ipc连接2.拷贝exe到主机系统上3.在靶机上创建一个…...
Linux命令学习—linux 的常用命令
1.1、改变目录 cd 目录的表达方法: /根目录 .当前目录 .. 上一级目录 ~家目录 #cd / 进入到系统根目录 #cd . 进入当前目录 #cd .. 进入当前目录的父目录,返回上层目录 #cd /tmp 进入指定目录/tmp #cd ~ 进入当前用户的家目录 #cd …...

【Git教程】(十)版本库之间的依赖 —— 项目与子模块之间的依赖、与子树之间的依赖 ~
Git教程 版本库之间的依赖 1️⃣ 与子模块之间的依赖2️⃣ 与子树之间的依赖🌾 总结 在 Git 中,版本库是发行单位,代表的是一个版本,而分支或标签则只能被创建在版本库这个整体中。如果一个项目中包含了若干个子项目,…...

最新版IntelliJ IDEA 2024.1安装和配置教程 详细图文解说版安装教程
IntelliJ IDEA 2024.1 最新版如何快速入门体验?IntelliJ IDEA 2024.1 安装和配置教程 图文解说版 文章目录 IntelliJ IDEA 2024.1 最新版如何快速入门体验?IntelliJ IDEA 2024.1 安装和配置教程 图文解说版前言 第一步: IntelliJ IDEA 2024.1安装教程第 0 步&…...

JVM常用参数一
jvm启动参数 JVM(Java虚拟机)的启动参数是在启动JVM时可以设置的一些命令行参数。这些参数用于指定JVM的运行环境、内存分配、垃圾回收器以及其他选项。以下是一些常见的JVM启动参数: -Xms:设置JVM的初始堆大小。 -Xmx࿱…...

分布式锁-redission可重入锁原理
5.3 分布式锁-redission可重入锁原理 在Lock锁中,他是借助于底层的一个voaltile的一个state变量来记录重入的状态的,比如当前没有人持有这把锁,那么state0,假如有人持有这把锁,那么state1,如果持有这把锁的…...
Android Gradle开发与应用 (八) :Kotlin DSL
1. 前言 本文介绍了Gradle Kotlin DSL相关的一些知识点 2. DSL是什么 DSL是为特定领域设计的专门的语言,也就是设计了一门语言,然后解决某个特定的领域的特定问题。 2.1 举例说明 以下的这些都可以称之为DSL 正则表达式 :用于文本处理的特定语言SQ…...
phpstorm 快捷键
PHPstorm最常用的快捷键,提高开发效率 - 知乎 (zhihu.com) 四年精华PHP技术文章整理合集——PHP框架篇 (qq.com) 四年精华PHP技术文合集——微服务架构篇 (qq.com) Vue3 打印票据 预览的库:vue3打印解决方案:Vue-Plugin-HiPrint - 掘金 (j…...

浦大喜奔APP8.0智能升级,发力数字金融深化五大金融篇章服务
1. 浦大喜奔立足科技赋能持续迭代升级,筑牢用户体验护城河 浦发信用卡中心坚持数字科技与客户体验双轮驱动,以科技赋能发展,优化整体系统性能,全方位支撑浦大喜奔 APP提高线上客户服务能力与体验,积极服务民生消费&a…...

自然语言处理、大语言模型相关名词整理
自然语言处理相关名词整理 零样本学习(zero-shot learning)词嵌入(Embedding)为什么 Embedding 搜索比基于词频搜索效果好? Word2VecTransformer检索增强生成(RAG)幻觉采样温度Top-kTop-p奖励模…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...

高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...