xhci 数据结构

xhci 数据结构

xhci 数据结构主要在手册上有详细的定义,本文根据手册进行归纳总结:
重点关注的包括:

  1. device context
  2. trb ring
  3. 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 transfer
 988      * ends just before a link TRB, the dequeue pointer will be left on
 989      * the link TRB by the code in the while loop.  So we have to update
 990      * the dequeue pointer one segment further, or we'll jump off
 991      * 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 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/546150.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【个人博客搭建】(2)项目分层结构

1、在解决方案这右击&#xff0c; 2、填写项目名称。&#xff08;位置使用默认即可&#xff09; 3、选择框架版本。&#xff08;最好同创建webapi一个版本吧&#xff09; 4、创建后进入该界面。会生成默认的一个Class类。&#xff08;后修改名称或删除都可&#xff09; 5、然后…

【C/C++】什么是内存泄漏?如何检测内存泄漏?

一、内存泄漏概述 1.1 什么是内存泄漏 内存泄漏是在没有自动 gc 的编程语言里面&#xff0c;经常发生的一个问题。 自动垃圾回收&#xff08;Automatic Garbage Collection&#xff0c;简称 GC&#xff09;是一种内存管理技术&#xff0c;在程序运行时自动检测和回收不再使用…

MySQL进阶-----limit、count、update优化

目录 前言 一、limit优化 1. 未优化案例 2.优化后案例 二、count优化 count用法 三、update优化 1.锁行情况&#xff08;有索引&#xff09; 2.锁表情况&#xff08;无索引&#xff09; 前言 上一期我们学习了order by优化和group by优化&#xff0c;本期我们就继续学习…

不需要GPU就可以玩转模型,同时支持本地化部署

简单一款不需要GPU就可以在Win 机器跑的模型&#xff1a;Ollama&#xff1b;用于本地运行和部署大型语言模型&#xff08;LLMs&#xff09;的开源工具 关于Ollama的简要介绍 平台兼容性&#xff1a;Ollama支持多种操作系统&#xff0c;包括macOS、Linux和Windows&#xff0c;…

Spectre漏洞 v2 版本再现,影响英特尔 CPU + Linux 组合设备

近日&#xff0c;网络安全研究人员披露了针对英特尔系统上 Linux 内核的首个原生 Spectre v2 漏洞&#xff0c;该漏洞是2018 年曝出的严重处理器“幽灵”&#xff08;Spectre&#xff09;漏洞 v2 衍生版本&#xff0c;利用该漏洞可以从内存中读取敏感数据&#xff0c;主要影响英…

一维非线性扩展卡尔曼滤波|matlab的EKF程序|一维例程源代码

为了满足不同条件下的用途,编了一个简单的一维状态量下的EKF,后面准备出UKF和CKF的版本。 使用的系统是非线性的,以体现算法对于非线性系统的性能。(状态方程和观测方程均设计成非线性的) 程序运行截图 程序都在一个m文件里面,粘贴到matlab的编辑器就能运行,如果中文注…

vivado 写入 ILA 探针信息、读取 ILA 探针信息

写入 ILA 探针信息 “调试探针 (Debug Probes) ”窗口中的“ ILA 核 (ILA Cores) ”选项卡视图包含有关您在自己的设计中使用 ILA 核探测的 信号线的信息。此 ILA 探针信息提取自您的设计 &#xff0c; 并存储在数据文件内 &#xff0c; 此数据文件通常带有 .ltx 文件扩…

React 集成三方登录按钮样式的插件库

按钮不提供任何社交逻辑。 效果如下&#xff1a; 原地址&#xff1a;https://www.npmjs.com/package/react-social-login-buttons 时小记&#xff0c;终有成。

基于注解以及配置类使用SpringIoc

四 基于注解方式使用SpringIoc 和 XML 配置文件一样&#xff0c;注解本身并不能执行&#xff0c;注解本身仅仅只是做一个标记&#xff0c;具体的功能是框架检测到注解标记的位置&#xff0c;然后针对这个位置按照注解标记的功能来执行具体操作。 本质上&#xff1a;所有一切的…

UML简单小结

文章目录 一、UML概述二、UML建模工具三、类图1、概念2、组成 四、类与类之间的关系1、继承2、实现3、依赖4、关联5、聚合6、组合 五、常见UML图1、用例图1&#xff09; 概念2&#xff09;组成3&#xff09;用例图所包含的的关系关联(Association)泛化(Inheritance)包含(Includ…

web笔记再整理

前四天笔记在此连接: web前端笔记表单练习题五彩导航栏练习题-CSDN博客https://blog.csdn.net/simply_happy/article/details/136917265?spm1001.2014.3001.5502 # 1.边框弧度​ div {​ width: 300px;​ height: 50px;​ background-color: aqua;​ …

sql注入之时间注入

一、时间注入 时间注入又名延时注入&#xff0c;属于盲注入的一种&#xff0c;通常是某个注入点无法通过布尔型注入获取数据&#xff0c;而采用一种突破注入的技巧。 在 mysql 里 函数 sleep() 是延时的意思&#xff0c;sleep(10)就是数据库延时 10 秒返回内容。判断注入可以使…

G2D图像处理硬件调用和测试-基于米尔-全志T113-i开发板

本篇测评由电子工程世界的优秀测评者“jf_99374259”提供。 本文将介绍基于米尔电子MYD-YT113i开发板的G2D图像处理硬件调用和测试。 MYC-YT113i核心板及开发板 真正的国产核心板&#xff0c;100%国产物料认证 国产T113-i处理器配备2*Cortex-A71.2GHz &#xff0c;RISC-V 外置…

Selenium自动化测试网页加载太慢如何解决?

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 遇到网页加载慢&#xff0c;selenium运行效率降低&#xff0c;可以通过修改页面加载策略提升自动…

docker-compose yaml指定具体容器网桥ip网段subnet;docker创建即指定subnet;docker取消自启动

1、docker-compose yaml指定具体容器网桥ip网段subnet docker-compose 启动yaml有时可能的容器网段与宿主机的ip冲突导致宿主机上不了网&#xff0c;这时候可以更改yaml指定subnet 宿主机内网一般是192**&#xff0c;这时候容器可以指定172* version: 3.9 services:coredns:…

Django之rest_framework(四)

扩展的视图类介绍 rest_framework提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这几种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量 官网:3 - Class based views - Django REST framework rest_framework.mixi…

比特币突然暴跌

作者&#xff1a;秦晋 周末愉快。 今天给大家分享两则比特币新闻&#xff0c;也是两个数据。一则是因为中东地缘政治升温&#xff0c;传统资本市场的风险情绪蔓延至加密市场&#xff0c;引发加密市场暴跌。比特币跌至66000美元下方。杠杆清算金额高达8.5亿美元。 二则是&#x…

【Node.js】Express学习笔记(黑马)

目录 初识 ExpressExpress 简介Express 的基本使用托管静态资源nodemon Express 路由路由的概念路由的使用 Express 中间件中间件的概念Express 中间件的初体验中间件的分类 初识 Express Express 简介 什么是 Express&#xff1f; 官方给出的概念&#xff1a;Express 是基于…

书生·浦语大模型全链路开源体系-第3课

书生浦语大模型全链路开源体系-第3课 书生浦语大模型全链路开源体系-第3课相关资源RAG 概述在 InternLM Studio 上部署茴香豆技术助手环境配置配置基础环境下载基础文件下载安装茴香豆 使用茴香豆搭建 RAG 助手修改配置文件 创建知识库运行茴香豆知识助手 在茴香豆 Web 版中创建…

Windows 10明年退役

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Windows 10 生命周期终止&#xff0c;收费预警二、收费标准&#xff1a;基于云的方式&#xff0c;使用 Windows 10 的 PC 也能接收 ESU高定价背后还是主推 …