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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《CSS 知识点》仅在文本有省略号时添加 tip 信息

html <div ref"btns" class"btns"><div class"btn" >这是一段很短的文本.</div><div class"btn" >这是一段很短的文本.</div><div class"btn" >这是一段很长的文本.有省略号和tip.<…

MongoDB副本集部署(windows)

环境准备 本教程演示mongodb4.4 副本集部署&#xff08;一主两从&#xff0c;伪分布式&#xff09; 节点配置主节点localhost:27017从节点1localhost:27018从节点2localhost:27019 每一个节点&#xff08;实例&#xff09;都创建对应的数据文件&#xff08;data&#xff09;…

MySQL中的存储过程详解(上篇)

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

OpenHarmony轻量系统开发【13】鸿蒙小车开发

13.1 小车介绍 基于鸿蒙系统 Hi3861 的WiFi小车 首先&#xff0c;我们得有一套WiFi小车套件&#xff0c;其实也是Hi3861 加上电机、循迹模块、超声波等模块。 小车安装完大概是这样&#xff1a; 13.2 电机驱动 我们这里先只做最简单的&#xff0c;驱动小车的电机&#xff…

ModuleNotFoundError: No module named ‘llama_index.readers“解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

怎样将PDF转成PPT,有免费的工具吗?

PDF转换为PPT的需求在现代办公和学习中越来越常见。很多人可能遇到过需要将PDF文件中的内容转移到PPT中以方便编辑和展示的情况。幸运的是&#xff0c;现在市面上有许多工具可以帮助我们实现这一目标&#xff0c;而且其中不乏一些免费的选项。本文将详细介绍如何使用这些免费工…

自然语言处理、大语言模型相关名词整理

自然语言处理相关名词整理 零样本学习&#xff08;zero-shot learning&#xff09;词嵌入&#xff08;Embedding&#xff09;为什么 Embedding 搜索比基于词频搜索效果好&#xff1f; Word2VecTransformer检索增强生成&#xff08;RAG&#xff09;幻觉采样温度Top-kTop-p奖励模…

Python | Leetcode Python题解之第24题两两交换链表中的节点

题目&#xff1a; 题解&#xff1a; class Solution:def swapPairs(self, head: ListNode) -> ListNode:dummyHead ListNode(0)dummyHead.next headtemp dummyHeadwhile temp.next and temp.next.next:node1 temp.nextnode2 temp.next.nexttemp.next node2node1.next…

Hello算法11:排序

https://www.hello-algo.com/chapter_sorting/ 选择排序 初始未排序的区间是[0,n-1]在[0,n-1]中查找最小元素&#xff0c;和索引0交换&#xff0c;此时未排序的区间是[1,n-1]在[1,n-1]中查找最小元素&#xff0c;和索引1交换&#xff0c;此时未排序区间是[2,n-1]以此类推&…

基于springboot+vue+Mysql的藏区特产销售平台

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

TC387实现SPI自通讯

TC387实现SPI自通讯 预期效果&#xff1a; TC387上定义两个SPI通讯接口&#xff0c;一个用于发数据一个用于收数据。准确无误的收到一次数据就对核心板led灯的状态进行一次翻转。 由于实验设备有限&#xff0c;只能想办法通过现有设备进行实验。 实现过程&#xff1a; 最开…

linux 设置定时任务---学习

1、设置定时任务 crontab -e 设置格式参考&#xff1a;【Linux】Linux crontab 命令定时任务设置_crontab 设置每天10:30执行-CSDN博客 测试过程&#xff1a; */1 * * * * /root/cronjob.sh 脚本内容: echo "hell0 cronjob" >> /root/test/hello.txt 实现…

extends继承

目录 什么时候用继承? 继承的格式? 继承的特点 子类可以继承父类的哪些呢&#xff1f; 是否可以继承父类的构造方法呢&#xff1f; 是否可以继承成员变量&#xff1f; 是否可以继承成员方法&#xff1f; 在Java中&#xff0c;extends关键字用于实现继承关系。通过使用…

24年重庆三支一扶报名照不通过怎么处理?

24年重庆三支一扶报名照不通过怎么处理&#xff1f;

Laravel 11入门:使用ServBay打造高效开发环境

Laravel 11发布&#xff0c;改进了不少功能。 它引入了更加流畅的应用结构、每秒限速、健康路由等特性。 此外&#xff0c;Laravel还推出了第一方可扩展的WebSocket服务器Laravel Reverb&#xff0c;为你的应用提供强大的实时功能。 在今天的指南中&#xff0c;我将设置一个…

ASP.NET基于BS课件发布系统

摘 要&#xff1a;本文在分析建立动态网站的技术细节和课件发布工作流程的基础上&#xff0c;阐述了网站的结构与功能设计。本网站采用的是B/S结构&#xff0c;网站使用 Microsoft Visual Studio .NET2003作为主要开发工具&#xff0c;采用Dreamweaver 作为辅助开发工具实现网…

ELK日志分析系统之Zookeeper

一、Zookeeper简介 ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务&#xff0c;它提供了一项基本服务&#xff1a;分布式锁服务。分布式应用可以基于它实现更高级的服务&#xff0c;实现诸如同步服务、配置维护和集群管理或者命名的服务。 Zookeepe…

3_3.Apache的管理及优化web

### 一.Apache的作用 ### 在web被访问时通常使用http://的方式 http:// ##超文本传输协议 http:// 超文本传输协议提供软件&#xff1a; Apache nginx stgw jfe Tengine ### 二.Apache的安装 ### dnf install httpd.x86_64 -y ### 三.Apache的启用 ### systemctl enable --…

C语言 03 VSCode开发

安装好 C 语言的开发环境后&#xff0c;就需要创建项目进行开发了。 使用 IDE&#xff08;集成开发环境&#xff09;进行开发了。 C 语言的开发工具很多&#xff0c;现在主流的有 Clion、Visual Studio、VSCode。 这里以 VSCode 作为演示。 创建项目 安装 VSCode。 推荐直接在…