当前位置:   article > 正文

xHCI1.1-TRB Ring_xhci协议

xhci协议

4.9 TRB Ring

TRB(Transfer Request Block)  Ring是一个TRB数据结构的环状队列,TRB Ring用来在producer和consumer之间传送工作项(Work Item)。和其相关的有两个指针,出队指针(Dequeue)和入队指针(Enqueue)。一个工作项由一个或多个TRB数据结构组成。一个工作项定义了一个将要被执行的操作或是一个已经执行的操作的结果。

有三种基本TRB Rings:Transfer,Event和Command。每种Ring都有其专用的TRB数据结构。但他们都是使用底层的TRB Ring机制来组织工作项和基本TRB模版。

    

Transfer Rings提供来自或是到USB设备的数据传输。Transfer Rings和USB Pipes之间有个一对一的映射关系。这是通过设备上下文中的端口上下文数据结构(或者端口上下文指向的流上下文数组)定义的。

Event Rings为xHCI提供向系统软件报告的方式,报告的内容包括:数据传输和命令完成状态,root hub port状态改变,和其他xHCI相关的事件。一个Event Ring通过Runtime Registers中的Event Ring Segment Table Base Address,Segment Table Size和Dequeue Pointer Registers来定义。

Command Ring为系统软件提供发送命令来枚举USB设备,配置xHCI支持设备,以及协调虚拟化功能的能力。Command Ring由Operational register中的Command Ring Control Register来支持。

Enqueue pointer和Dequeue pointer是用来标志一个TRB Ring中的逻辑开始和结束的。TRB Ring的size由组成ring的segment的数量和大小决定的。Enqueue Pointer是R下一个Producer可用的Ring中的TRB地址,Producer从这位置创建一个新的工作项,然后将这个指针前移。Dequeue则是Consumer将要使用的TRB的地址。当Dequeue Pointer等于Enqueue pointer时,TRB Ring就是空的了。如果Enqueue pointer+1=Dequeue pointer,那么这个ring就是满的。在Enqueue Pointer-1和Dequeue Pointer之间的TRBs由Consumer拥有使用权。其他的TRBs就是Producer拥有使用权。每当这两个指针改变之后,那么TRB所有权就会发生转换。Consumer需要按序执行TRB。所有TRB都是16Bytes的大小。TRB Rings可能会比一个Page大,但是他们不能越过64K的界限(详见4.11.5.1)。

初始化,也就是当TRB ring在内存中创建或者如果它每次被重新初始化时,Ring中所有TRBs都需要被清“0”。这个状态表示一个空的队列。

注意:Transfer和Command Ring中的出入队指针并没有定义相应的物理xHCI寄存器,但是Event Ring定义了。

4.9.1 Transfer Descriptors

一个TD中包含一个或多个TRBs。TRB Chain (C) bit在所有TRB中都有设置,但是每个TD的最后一个TRB不会设置。xHCI可以为与一个TD相关的所有packets安排Max Packet Size USB 事务,可能除了最后一个packet(如果这个TD没有定义一个整数个的Max Packet Size data bytes)。

为生成一个0长度的USB事务,软件应该精确的定义一个只有一个TRB的TD,并且它的TRB Transfer Length字段应该等于0。注意这个TD可以包含non-Transfer TRBs,比如Event Data或者Link TRB。

在这个协议中有许多关于xHC应该“前移到下一个TD”的条件描述。但是,如果xHC在这些情况之一发生时正在处理一个TD的一个部分(a partially formed  TD),则不可能前进到下一个TD,并且当到达Enqueue Pointer时xHC将停止前进。在这种情形下,xHC认为Transfer Ring是空的即两个指针相等,接着当下一次doorbell为端点Rung,xHC应该尝试去进入下一个TD的范围。注意xHC应该通过一个Set TR Dequeue Pointer Command来说明新的TR Dequeue Pointer。

“部分完成的TD”通过以下情况来标识:Dequeue pointer引用的TRB中的Chain bit(CH)设置为“1”,并推进Dequeue将其设置为等于Enqueue Pointer。

注意: Command和Event TRBs并不支持Chain bit(CH),因此所有的Command Descriptors (CDs)和Event Descriptor (EDs)只有单个TRB构成。(后面还有两个note)

4.9.2 Transfer Ring  Management

这节描述Transfer Ring中Enqueue和Dequeue pointer的操作。如图所示,如表示一个Transfer Ring。Producer(host)在Enqueue  Pointer将item放入Transfer Ring,Consummer(xHC)在Dequeue Pointer把item取出。TRB中的Cycle bit字段标识了Transfer Ring中的Enqueue Pointer中的位置。消除了使用寄存器来定义。

软件使用并且维持对于各个Transfer Ring的Enqueue和Dequeue pointer的副本。在Transfer ring初始setup时,Enqueue和Dequeue Pointers对于每个Transfer Ring都是设置为第一个TRB的地址,并且写入Endpoint/Stream Context TR Dequeue Pointer 字段。软件通过增加其大小每次增加一个TRB size或在遇到链接TRB时将其与环形段指针字段的值重新加载来推进其Enqueue pointer的副本。

xHC同样对每个Transfer Ring维持着自己对于这两个指针的副本。当一个Transfer Ring被启用或被重置,xHC使用Endpoint/Stream Context TR Dequeue Pointer Filed来更新这两个副本。xHC使用Dequeue Pointer来决定从Transfer Ring的哪儿拿取下一个work Item。xHC更新Dequeue Pointer的方式和软件的更新方式一样。

xHC使用Enqueue Pointer来确定什么时候Transfer Ring是空的。当它从一个Tansfer Ring取出TRBs时,它会检测是否有一个Cycle bit事务。如果一个事务被检测到,ring就是空的了。

而反过来,Software使用Dequeue pointer确定什么时候Transfer ring是满的。当他处理tansfer Events,它使用Transfer Event TRB Pointer 字段来更新它自身维持的Dequeue Pointer。如果当前移Enqueue Pointer时使得它等与Dequeue Pointer那么表明Transfer Ring就是满的。

Producer将要保持一个Producer Cycle State(PCS)flag用于标识它应该写入TRB Cycle bit的值。Consumer维持一个Consumer Cycle State(CCS)flag,它用此flag来和它取出的TRB中Cycle bit进行比较。如果CCS flag等于TRB Cycle bit的值,那么Consumer将获得此TRB(Dequeue Pointer指向的)的所有权并且可以处理这个TRB。如果他们不等,那么consumer应该停止处理TRBs并且等待更多工作通知。

在上图中,TRBs由Producer插入并且设置Cycle位的值设为PCS。注意图中,“~PCS”表示PCS的倒置(inverted)。

为了形成一个Ring(环状队列)一个Link TRB应该放在Ring的最后,并指向第一个TRB。一个Ring中可以有多个Link TRBs,这些TRBs用来将Transfer Ring Segments连接在一起。在上图中Toggle Cycle bit设置在了Link TRB中。如果Producer遇到一个设置在一个link TRB中的Toggle Cycle它应切换其PCS标志的状态。如果Consumers遇到一个设置在Link TRB中的Toggle Cycle它应该切换它的CCS flag。Producer设置TRB Cycle bit为PCS flag的值当它写一个TRB来设置Enqueue pointer所指位置时。在图中,在遇到Link TRB后Producer将要遇到的下一个TRB是0。Link TRB中的Toggle Cycle的申明将会导致Producer转换PCS flag的状态。TRB0中的Cycle bit将被设置PCS的值。Link TRB允许传输环跨越页面边界并动态调整大小。

注意:所有在Dequeue Pointer和 Enqueue Pointer之间TRBs都属于Consumer并且不能被Producer改变。如果Ring是空的(两个相等)那么没有TRB属于Consumer。Ring中的任何TRBs不属于Consumer那么就属于Producer。

注意:如果Streams不能

4.9.2.1 Segmented Rings

Link TRB为非连续的TRB ring提供了支持。比如,如果连续的Memory Pages不能被系统软件分配来形成一个大的TRB Ring,那么Link TRBs能够被用来将多个Memory pages连和在一起形成一个大的Transfer Ring。

一个非连续TRB Ring是由Ring Segments组成的。给一个Ring segment是一个物理内存中的一个连续的块。Link TRB提供了一个64bit的指针指向ring的下一个segment。如果ring是由一个single segment组成的那么唯一的Link TRB将指向ring的开始。一个由多个segment ring组成的ring将使用Link TRB来界定一个segment的结束和下一个segment的开始。在一个Ring segment中最后一个TRB一定是Link TRB。

上图中说明了一个包含两个segment的segment Ring。在这个例子中每个segment都分配了4KB的连续内存块。Segment 0定义有256个TRBs,最后一个是link TRB指向下一个segment的开始。Segment 1定义有244个TRBs,并没有完全使用分配给它的4K buffer。这两个segments一起定义了500个TRB大小的ring,其中498个对于TDs来说是可访问的。注意Toggle Cycle flag只在Segment 1中被设置。

4.9.2.2 Pointer Advancement

当Dequeue Pointer向前推进时,他的值将调整指向下一个传输相关的将要被执行的TRB。xHC每次给这个指针的值增加16bytes,如果下一个TRB是Link TRB并且它的Cycle bit指明它是一个有效的TRB,那么xHC将会自动设置Dequeue Pointer指向Link TRB提供的地址。这个操作将会使Dequeue Pointer指向下一个segment的第一个TRB。

Software负责推进Enqueue Pointer。在它写TRBs时,它通过转换每个通过ring的Cycle bit来实现这种推进。

一旦开始(通过一个doorbell寄存器),xHC处理TRBs直到这个ring是空的。一个ring被定义为空的如果其Dequeue和Enqueue指针相等。Enqueue Pointer的值通过Cycle bit Transition来定义。为了阻止过载,software应该决定什么时候Ring是空的。ring会被定义为“full”如果推进Enqueue pointer指针会等于Dequeue指针。软件应该评估full条件是应该将TRBs考虑进去。如果Enqueue Pointer指针没有指向Link TRB,software可以给Enqueue Pointer的值增加一个TRB的size(16),然后判断两个指针是否相等。如果指向了一个link TRB,那么软件应该比较Link TRB中Ring Segment Pointer的值与Dequeue Pointer的值。

注意:Producer Cycle State(PCS)和Consumer Cycle State(CCS)flags分别被xHC和软件保持帮助识别排队指针的值。这些flags并没有定义在xHC寄存器或者数据结构中。

指针推进的规则:

.在初始化一个ring时,Cycle bit应该被软件初始化为“0”,在所有的segments的所有TRBs中。

.Producer Cycle State(PCS)和Consumer Cycle State (CCS) bits应该被设置为“1”当ring被初始化时。

.Cycle bit应该被Producer写入当前PCS bit的值。

.Cycle bit应该对于Consumer来说只读

.Consumer可以执行一个Dequeue Pointer指向的TRB,并且要满足该TRB的Cycle bit应该等于CCS。

.如果Enqueue指向了一个Link TRB,那么Enqueue Pointer应该被设置为Link TRB Ring Segment 

 Pointer 并且如果Toggle Cycle bit被设置为“1”在Link TRB中,则Producer应该将PCS的值将进行转 置。

.如果Dequeue指向了一个Link TRB,那么Dequeue Pointer应该被设置为Link TRB Ring Segment 

 Pointer 。 并且如果Toggle Cycle bit被设置为“1”在Link TRB中,则Producer应该将PCS的值将进行 转置。

注意:Cycle bit转换发生在Link TRB和Link TRB Ring Segment Pointer指向的segment的第一个TRB之 间。

注意:TR Dequeue Pointer和Link TRB并不需要指向一个memory page的开始。

4.9.2.3 Enlarging a Transfer Ring

为了增加Transfer Ring的size,软件需要分配和初始化一个新的segment。Software然后需要标识segment的边界(Link TRB),因为在这里他可能会添加新的segment。

注意:只有被Producer拥有的Link TRBs才可以被改变来指向新的segment。

图4-9说明了两个Segment Transfer Ring(A和B)这里Segment B中的TRBs 5-n和Segment A中的TRBs 0-3被consumer所拥有(xHC),而剩下的TRBs对于Producer(software)来说是可以访问的用于创建新的TDs。注意Toggle Cycle(TC)在Segment B的Link TRB中被设置而没有在Segment A中被设置,因此,Cycle bit的状态在每次通过整个传输环时被切换。

现在,考虑在4-9中软件怎么去增加ring的size?软件可以停止在Transfer ring中插入TDs,这暂时性停止了Enqueue Pointer的推进,然后再插入新的segment。软件只能改变属于它的Link TRBs,这样新的segment C只能在segment A和segment B之间被插入,见图4-10.

注意:如果Link TRB是没有被软件拥有并且也不是当前被xHCI执行的TD中的TRB。那么软件可以停止Transfer Ring来改变Link TRB,然后在重新起动Transfer Ring。如果Link TRB是当前被执行的xHCI中的的TRB,那么软件

在这个例子中,软件会初始化新的segment通过下面的操作:

.所有TRBs在新的segment C 到“0”包括Cycle bit.

.segment C中的最后一个TRB应该被设置为Link TRB。

.并且Segment C Link TRB(n) 的Ring Segment Pointer 字段应该被初始化来指向segment B的第一个TRB(0).

.segment C Link TRB(n)中的Toggle Cycle(TC)应该被设置,表示Segment C中的最后一个TRB和     Segment B中的第一个TRB之间的Cycle bit的转换。

软件应该修改segment A的Link pointer指针指向新的segment C。

.Segment A Link TRB(n)中的Ring segment Pointer字段应该初始化指向Segment C的第一个TRB(0).

.Segment A Link TRB(n)中的Toggle Cycle(TC)flag应该被设置为1,表示segments A和C中属于consumer的 TRBs之间的Cycle bit的转换。

软件需要确保新的segment中Cycle bit的状态,并且Link TRBs中的Toggle Cycle flags需要用来连接新的segment和已经存在的segments,不要导致Enqueue pointer的定义不一致。

给定初始条件如图4-9所示,为了保证在插入segments时Cycle bit一致,software需要:1) 在一个新的segments中将所有TRBs中的Cycle bits清零,并且修改该segment和新segment中的LinK TRB Toggle Cycle flags。2)设置新segment中的所有TRBs中的所有Cycle bit为“1”。

4.9.2.4 Shrinking a Transfer Ring

为了减少Transfer Ring的size,software应该表示一个segment界限(Link TRB)这里它会进行shrink operation(收缩操作)。

软件可以修改Link TRB Ring segment Pointer来设计规划一个或多个中间segments(并且或)设置Link TRB Ring Segment Pointer 指向一个TRB的位置。

4.9.3 Command Ring Management

这节描述对于Command Ring中Enqueue和Dequeue指针的操作。对于Command ring的操作是和Transfer rings的操作是一致的:

如果

4.9.4 Event Ring Management

注意一个xHC可以实现多个中断,每个都会有自己的Event Ring。这节描述对于单个Event Ring的操作。Event Ring和Transfer以及Command Ring之间的基本区别是,对于Event TRBs来说xHC是Producer,系统软件是consumer。xHC将Event TRBs写入Event Ring,并且更新TRBs中的Cycle bit来告知software当前Enqueue Pointer的位置。

xHC保持一个Event Ring Producer Cycle State (PCS) bit,将他初始化到1并且每次当Event Ring Enqueue Pointer 

Wraps回到Event Ring的开始时都要将其进行转换。PCS的值会被写入Cycle bit中,当xHC在Event Ring中生成一个Event TRB时。

软件维持一个Event Ring Consumer Cycle State (CCS) bit,将其初始化为1,并且每次当Event Ring Dequeue pointer指针从回到Event Ring的开始时都要将其进行转换。如果Dequeue pointer指向的Event TRB的Cycle bit值等于CCS,那么Event TRB是一个有效的event,软件处理它并且推进Dequeue指针。如果不等于CCS,那么软件将停止处理Event TRBs并且等待一个来自xHC的中断。当中断发生时,软件从中断的地方开始,检查Dequeue指向的TRB的Cycle bit,并对照CCS位进行检查。

系统软件需要写Event Ring Dequeue Pointer (ERDP) register来告知xHC它完成了对Event TRBs的处理并且包含了当前ERDP指向的Event TRB。

注意:在由软件处理的Event TRB中检测到Cycle bit不匹配,将指示xHC Event Ring的位置,并且事件环为空。软件应将该TRB的地址写入ERDP,以表明其已处理环中的所有事件。

Event Ring segments通过一个Event Ring Segment Table (ERST)来定义。ERST由一个基地址/大小对数组组成(ERST.BaseAddress 和 ERST.Size),每个定义一个Event Ring segment。在ERST(0)中的第一个element由ERST Base Address Register指向。ERST中元素的数量由ERST size Register定义。当xHC被初始化时,它开始在ERST中第0个元素表示的地址中写入Event TRB。xHC会维持对于写入一个segment的中的Event TRBs进行计数。当这个计数超过了ERST.size entry,xHC应该使用下一个ERST entry。ERST entries是一个循环队列,当ERST(ERSTSZ-1)被拿取后将会回到ERST (0).

操作一个Event Ring的规则:

. 在写入ERST Base Addr(ERSTBA)之前,系统软件应:

       . 将Event Ring Segment Table将要使用的Event Ring Segments都初始化为0。

       . 初始化ERST通过初始化table中的每个条目中的ERST.BaseAddress和ERST.Size。The ERST.Baseaddress字            段应该指向相关的Event Ring segment, ERST.Size应该表示这个Segment中的TRBs的数量。

       . 根据ERST中条目的数量,填写Event Ring Registers中的ERST Size字段。并且在Event Ring Dequeue 

         Pointer  (ERDP)寄存器写入ERST(0).BaseAddress值。

. 在ERST Base Address (ERSTBA)寄存器中写入ERST(0).BaseAddress的值。当ERSTBA寄存器被写后,      Event Ring State Machine被设置为开始状态。

. 系统软件应该推进Dequeue Pointer通过将最后处理的Event TRB的地址写入Event Ring Dequeue Pointer 寄存器(ERDP)。注意“最后处理的Event TRB”包括软件检测出Cycle bit 不匹配的情况。

. 系统软件负责确保ERST 条目有效的值

. 系统软件负责确保每个ERST条目(Event Ring segment) size至少是16.

如图所示,描述了xHCI推进Event Ring Enqueue Pointer (EREP)的算法。左边是推进EREP的算法,右边是用于检查Event Ring是否满的算法。

注意:1.对于Event Ring来说Producer Cycle State(PCS)flag只在Event Ring向后回到开始时才进行准换。

            2.如果USBCMD Run/Stop (R/S)的flag是0,那么Event Ring 状态机将会停止。

            3.一个阻塞Event Ring可以影响A blocked Event Ring may impact forward progress on endpoints whose TDs

target other Event Rings.

注意:1. 2. 3.

下面的步骤描述xHC Event Ring Enqueue Pointer (EREP) 推进算法(上图左边图片):

  1. 当ERST Base Address(ERSTBA)寄存器被初始写入,Event Ring 状态机将会进入Start state.

  2. xHC将其内部的PCS flag初始化为1.

  3. xHC设置它内部ERST Count为0.

  4. 接着xHC根据ERST Count (ERST=ERST[ERST Count])拿出Event Ring Segment Table中的条目并且使用Ring Segment Base Address字段 (ERSTE.BaseAddr)初始化它的Enqueue Pointer (EREP),并且使用Segment Size filed (ERSTE.Size) 来初始化TRB Count。

  5. 如果USBCMD Run/Stop (R/S) flag='0'那么Event Ring State Machine应该等待R/S返回到‘1’。当R/S等于1时,xHC应该继续检查是否发布了event。

  6. 当为这个Ring发布了event之后,xHC应改首先检查和这个ring是否是full的。如果不是xHC将Event TRB写入EREP标识的那个位置,并且将EREP推进16,同事TRB Count的值减1. Event TRB的Cycle bit被设置为PCS flag的值。如果没有event被发布,那么xHC将会返回第5步。

  7. 只要TRB Count是非0,那么xHC应改返回第5步,继续检查R/S或检查新的events

  8. 当TRB Count值到0时,xHC应该增加ERST Count并且评估它,否则将返回第5步.

            a. 如果ERST Count不等于ERSTSZ register的值,那么xHC应该返回第4步从ERST的下一个segment处理                 events

            b. 如果ERST Count等于ERSTSZ Register的值,那么xHC设置ERST Count 为“0”,转

               换Producer Cycle State(PCS)flag,然后返回第3步从ERST的第一个segment开始处理events.  

如果Event Ring已满,xHC应通过报告Event Ring已满错误来标记条件,这需要在Event Ring上放置一个Event。为了确保Event ring上有足够的空间来处理这个错误,当仍有空间供一个条目进入时,xHC应认为事件环已满。

接下来的步骤描述的是检查Event Ring是否是满的算法:

  1. 如果TRB Count比1大,那么xHC能在EREP上增加16并且对比ERDP决定是否Event Ring是满的。

  2. 如果TRB Count等于‘1’,那么xHC应该检查是否ERDP指向下一个segment的第一个条目。下一个Event Ring segment (NSP)地址的获取为ERST[(ERST count +1 )mod ERSTSZ].BaseAddr

           a. 如果NSP不等于ERDP,那么Event Ring有空间,Event Ring Full Check 存在。

           b. 如果NSP等于ERDP,那么Event Ring就是满的。xHC停止处理Transfer和Conmmand Ring,在EREP中写入一个Event Ring Full Error Event,推进EREP并且将TRB Count 减1.  

       3. 如果TRB Count不等于‘0’,那么在当前的segment中有空间供更多的events使用,因此返回第6步并且等 待ERDP的推进。

       4.如果TRB Count 等于“0”,那么增长ERST Count来推进EREP到下一个segment。

            a. 如果ERST Count不等于ERSTSZ register的值,那么xHC应该去第5步为ERST的下一个segment初始化状态机参数。

            b. 如果ERST Count等于ERSTSZ寄存器的值(也就是整个ERST走完一圈了,问:那会不会存在不够用的情况),那么通过设置ERST Count 为0推进EREP到ERST第一个segment,并且要转换Producer Cycle State (PCS) flag,然后到第5步为ERST的第一个segment设置初始化状态机参数。

        5. 为了初始化状态机参数,xHC根据ERST Count索引取出ERST中的条目(ERSTE=ERST[ESRT Count])并且使用Ring segment Base Address (ERSTE.BaseAddr)字段的值初始化它的Enqueue Pointer (EREP),使用Segment Size字段(ERSTE.Size)的值来初始化TRB Count。一旦EREP被推进到下一个segment那么进入第6步,并且等待ERDP的推进。

        6. Event Ring回保持是满的直到下一次时间软件写ERDP。当ERDP被写时,xHC通过回到步骤1将会确定这个新的ERDP值是否有空闲的空间在Event Ring上。

4.9.4.1 Changing the size of an Event Ring

为了增加Event ring的size,软件需要分配和初始化一个新的segment。然后软件根据在ERSTSZ上定义的offset初始化ERST对应的条目,包括新的Event Ring Segments的Address和Size并且将ERST的新size写入ERSTSZ。

软件可以确定当xHC开始使用新的segment时,要检查新的segment的第一个TRB的Completion Code是否是以一个非零(有效)条件。

考虑当存在两个segment(‘0’和‘1’,ERSTSZ=2,ERST(0))要增加第三个segment (segment ‘2’)的情况。软件会将新的Segment中的所有TRB初始化为‘0’。然后设置ERST(2).BaseAddr等于新segment的基地址,ERST(2).Size等于新segment支持的Event TRBs的数量,并将ERSTSZ设置为3。

如果ERSTSZ已经更新了,EREP刚好通过Segment 1的最后,xHC将不会开始使用新的segment,直到下一次通过整个Event Ring。如果EREP刚好在Segment 1的最后一个TRB的位置,那么xHC将会开始使用新的segment。

注意xHC将会在segment 2的TRBs的Cycle bit写入和segmnet 1相同的值。当软件在评估Dequeue pointer指向的 Event TRB时,软件会确定xHC什么时候开始使用新的Segment。当软件评估segment 1的最后一个TRB之后的Event TRB时,它需要检查Segment 2中的第一个TRB 中的Valid(Non-Zero) Completion Code,这个值是xHC开始使用这个新的segment的指示器。如果Completion Code是有效的,那么软件应该将Dequeue Pointer指针移向Segment 2的第一个TRB。如果Completion Code是无效值(‘0’),软件应该检查segment 0中第一个TRB的Cycle bit的状态,看看其是否匹配下一次通过整个Event Ring的状态(PCS值应该翻转,通过一次Event Ring时)。如果不匹配,这意味着EREP正指向Segment 1的最后一个TRB,并且Event Ring是空的。如果匹配,那么软件应该推进Dequeue Pointer到Segment ‘0’的第一个TRB。 如果Event Ring为空,则下次接收中断时,软件应重新评估segment 1到segment 2边界处的EREP方向。

软件应使用Event TRB完成代码字段的有效(非零)到无效('0')过渡来确定Dequeue pointer第一次通过新segment时Enqueue Pointer的位置。TRB Cycle bit在第一次通过新segment时应被视为无效,并且不应被软件用来确定Enqueue Pointer的位置。

在Enqueue Pointer首次通过整个新Segment之后,xHC应该在新添加的Event TRBs中初始化Cycle bit。

在Dequeue Pointer首次通过整个新的Segment之后,软件应该评估segment 2 中Cycle bit的状态来确定Enqueue Pointer的位置。

4.9.4.2 Shrinking an Event Ring

减少Event Ring的size,软件应该减少ERSTSZ寄存器的值。

在xHC停止使用这个segment时,软件根据这个segment(s)的首个TRB中Cycle bit的状态来确定移除这个segment(s)。

比如有三个segment,‘0’,‘1’,‘2’ (ERST Count = 3)并且Segment 2将要被删除。软件会将ERSTSZ寄存器设置为2。当ERSTSZ被写后,如果EREP指向Segment 2,xHC将不会停止使用这个名义上被删除的Segment 2,直到下一次通过整个Event Ring。当ERSTSZ被写后,如果EREP处于segment 1中,xHC将会马上停止使用新的segment。

当他评估Dequeue Pointer指向的Event TRB时,软件可以确定什么时候xHC停止使用名义上被删除的segment。当软件评估segment 1的最后一个TRB之后的TRB时,它会检查segment 2中的第一个TRB中的Cycle bit。如果Cycle bit满足要求,那么他会继续处理被删除segment上的TRB。如果Cycle bit不满足要求,那么软件应该检查segment 0中的第一个TRB的Cycle bit状态。如果该Cycle bit值和segment 1中的最后一个TRB的匹配,那么EREP将指向segment 1的最后一个TRB并且Event Ring已经是空的了。如果不匹配,那EREP已经推进到segment 0并且下一个将要处理的TRB是segment 0的第一个TRB。并且xHC已经停止使用删除的segment。 如果Event Ring为空,则下次收到中断时,软件应重新评估EREP在segment 1到 segment 2边界的方向。

4.9.4.3 Primary  and Secondary Event Ring

软件可用的中断器数量由HCSPARAMS1寄存器中的MaxIntrs字段定义。如果由超过一个中断器可用,那么第0个中断器就被认为是Primary Interrupter并且所有其他Interrupters认为是Secondary Interrupters。每个Interrupter都定义有一个相关的Event Ring。那与第0个Interrupter相关的Event Ring被称为是Primary Event Ring。与其他Interrupter相关的就称为Secondary Event Rings。在Secondary Event Ring能看到的Event TRB类型只有:

. Transfer Event

. Bandwidth Request Event

. Device Notification Event

. Host Controller Event

. Vendor defined event(optional)

由设备插槽生成的传输事件可以通过传输TRB中断器目标字段中的非“0”值定向到一个Secondary事件环。当TRB中断器目标字段清除为“0”时,所有传输事件应由xHC定向到Primary Event Ring。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/247177
推荐阅读
相关标签
  

闽ICP备14008679号