understanding linux usb ehci device driver(1)

来源:互联网 发布:西古德森数据 编辑:程序博客网 时间:2024/05/21 17:29

本文转载自:http://blog.csdn.net/lm_tom/article/details/1778031

大概一年多前,曾经在linux下调试过VIA的一款ehci host controller,当时受项目进度以及知识积累所限,未能深入理解EHCI以及linux下的软件层面实现. 随着个人USB技术的不断积累, 近期在工作之余, 写了一些对EHCI以及linux下实现的理解. 选择EHCI作为一个思考和研究的对象的出发点:
1),USB2.0以及EHCI是非常成功的,这些成功背后必然有技术的因素,对这些导致成功的技术的思考有利于未来在所从事的工作给出成功的设计和实现;
2),EHCI是usb 2.0 的PC架构下实现方式, 其实现从对处理器能力占用,性能保证以及软件架构都具有一定的通用性,对嵌入式下HC的设计和实现都有较强的参考价值,另外,PC架构下丰富的资源(开放的EHCI规范, linux usb源码开放,PC环境易于调试等)利于开发者掌握这些技术;
3), EHCI无疑是比较复杂的,对linux ehci的理解和思考有助于提高个人的设计能力.

主要包括以下三个部分:ehci specification overview, linux ehci device driver以及主要场景分析. 由于个人能力所限,错误在所难免,但欢迎提出意见.

 

ehci 规范定义了usb2.0 host controller寄存器层面的接口,同时包括了host controller driver和host controller软硬件之间的接口。Fig1-1中灰色部分是ehci规范的范围.

Fig1-1  Universal Serial Bus, Revision 2.0 System Block Diagram

USB 2.0 Host Controller一般包含1个支持高速模式的eHC和0~多个支持低速,全速模式的companion HCs(参考fig1-2),这样可以同时支持三种速度模式的usb设备。Port Routing Logic根据软件的配置以及所插入的usb device 的speed mode,将port1~portN映射到cHCs 或者 eHC的对应端口:

  .EHCD driver没有配置eHC,port routing logic将所插入设备的port映射到cHCs的对应port;

  .EHCD driver 配置了eHC后,eHC是所有root ports的默认owner, 当所插入设备不是高速时,eHC释放port owner给cHCs, 否则eHC保持port的owner.

---2

Fig1-2  USB 2.0 Host Controller

Fig1-3给出了EHCI的general architecture, 包括了pci configuration registers space, memory-based I/O registers space以及shared memory schedule space.

---3

Fig1-3 General Architecture of Enhanced Host Controller Interface

EHCI对两类传输类型提供了支持:periodic transfer 和 asynchronous transfer. Periodic 类型包括isochronous and interrupt transfer,   asynchronous类型包括control 和 bulk transfer.

    The periodic schedule is based on a time-oriented frame list that represents a slidingwindow of time of host controller work items. The asynchronous schedule is a simple circular list of schedule work items that provides a round-robin service opportunity for all asynchronous transfers.

1.1.1.   ehci定义的寄存器接口

主要包括了pci configuration registers space 以及  register space, 具体参考ehci specification ch2.   

Pci configureation registers space 包括pci header  and device specific registers, USBLEGSUP register, USBLEGCTLSTS register.(实际上ehc 不一定非通过pci device来实现,当不使用pci device方式实现时候,此处对应的寄存器格式应该会有变化)

Registers 被划分为两类: 只读的capability registers和read/write的操作寄存器. 操作寄存器用于访问eHC的状态, 控制eHC等, 是EHCD访问eHC的主要接口之一。

1.2.ehci定义的schedule interface

具体参考ehci specification ch3

定义软硬件间数据结构的接口,主要包含如下数据结构:

Periodic Frame List

   定义了包含1024,512 or 256(如果HC允许,可以通过USBCMD register配置)个element的表格,每个element为一个4byte-aligned的指针,可以指向iTD/QH/siTD/FSTN等结构; 一般需要将该结构对应的表格起始地址写入PERIODICLISTBASE寄存器,eHC结合FRINDEX寄存器即可找到当前frame所要调度的periodic schedule数据结构链表.

 

Asynchronous List Queue Head Pointer

   该指针指向以QH为元素的循环链表,所有asynchronous transfer(control/bulk) 的QH链接至此。

 

Isochronous (High-Speed) Transfer Descriptor (iTD)

   iTD仅仅被high speed Isochronous endpoints所使用,代表该endpoint和usb 设备间一个frame内的Isochronous传输, iTD只可以链接到Periodic Frame List中.

 

Split Transaction Isochronous Transfer Descriptor (siTD)

   通过usb 2.0 hub(not root hub)接入usb bus的fs usb Isochronous device,ehci使用siTD向设备对应endpoint传输数据。siTD只可以链接到Periodic Frame List中.

 

Queue Element Transfer Descriptor (qTD)

   qTD需要链接到QH才可以使用,qTD用于实现1个或者多个USB transaction.

 

Queue Head

   QH用作实现Interrupt, bulk 以及 control传输, 1个QH包含0~多个qTD.

 

Periodic Frame Span Traversal Node (FSTN)

       FSTN用于实现跨Frame的fs/ls split transaction.

1.3.ehci operational model

具体参考ehci specification ch4

 

Ehci中该部分主要从host controller以及host controller driver两个角度, 描述了各自的操作模型. 从该部分内容就可以看出HC 和 HCD间复杂的接口.

1.3.1.   Periodic schedule

Periodic schedule用于管理所有isochronous和interrupt 传输. Periodic schedule的基础是periodic frame list(Fig1-4), 软件将各种periodic schedule的数据结构(iTD,siTD, FSTN以及Interrupt QH)链接到periodic frame list的某个frame中, 生成一个poll rate从低到高的树状结构, 叶子对应的poll rate最低, 树根对应的poll rate最高

  软件设置USBCMD寄存器的periodic schedule enable bit后, HC会从PERIODICLISTBASE寄存器

找到periodic frame list, 结合FRINDEX寄存器即可找到当前frame所要调度的transaction 链表,这个链表就是从一个树叶到根的一个path, 在该frame对应的8个micro-frame,HC都会遍历一次该path, iTD/siTD/interrupt QH结构中都包含了micro-frame相关的schedule信息, 使得HC在合适的micro-frame完成对应的transaction.

---4

Fig1-4 Example Periodic Schedule

1.3.2.   Managing Isochronous Transfers Using iTDs

  iTD主要包含4个部分内容:

     . Next Link Pointer.

     . Transaction description array (8 uFrame array)

     . 7-element 的 buffer page pointer(最大可支持7*4KB传输)

     .endpoint capabilities information(including endpoint addressing, transfer direction, maximum packet size and high-bandwidth multiplier.)

1.3.2.1.         from HC view

  HC如何找到iTD?

     HC使用FRINDEX[12:3]去索引periodic frame list,得到对应的periodic frame list element, 该element对应的链表在当前帧包含的8个uFrame中各被扫描1次(即当前帧会被连续扫描8次), HC在扫描过程中可以将iTD fetch到HC chip内. 每个iTD包含8个transaction descriptor, HC通过FRINDEX[2:0]来索引对应的descriptor,进而在micro-frame生成对应的bus transaction.

    

  HC如何解析iTD并生成bus transaction?

     如果 (iTD.transaction_descriptor[N] .status & ACTIVE ) == 0, 那么HC会忽略该iTD,并沿着NEXT pointer到达下一个同步schedule data structure.(N = FRINDEX[2:0] )

     如果 (iTD.transaction_descriptor[N] .status & ACTIVE ) == 1, 那么开始解析该iTD:

        .使用iTD.transaction_descriptor[N].PG以及 iTD.transaction_descriptor[N] .Transaction_offset得到传输数据buffer的物理地址

        .使用endpoint addressing information 以及 I/O bit(均包含在iTD 的endpoint capabilities information)向对应的endpoint执行transaction. 完成后, HC会clear iTD.transaction_descriptor[N].status的ACTIVE位,并且回写其他一些状态信息到iTD.transaction_descriptor[N].status中.

 

  HC怎样在uFrame中执行多个iso transaction:

     Multfield(iTD的endpoint capabilities information)表示在一个uFrame中HC可以向该endpoint连续执行几个transaction, 取值范围为1~3. 事实上只有device的endpoint具有这种能力的话, HCD才会在iTD.Multi设置对应的值, device的endpoint descriptor中有对应的Multi能力描述信息.

1.3.2.2.         from HCD view

上层软件一般会请求HCD做一个HS ISO transfer,提供如下信息:

     .buffer address 以及 transfer length;

     .endpoint 信息.

HCD需要将这种请求转化成HC可以识别的iTD,并将其链接到periodic frame list中. HCD需要依据如下完成这种转化:

     .endpoint 的 interval 能力;

     .endpoint 的 MAXPACKETSIZE能力;

     .endpoint 的 Multi能力;

     .HCD需要保证同步传输在每个uFrame中所占据带宽不能超过80%(USB 2.0 spec规定).

1.3.3.   Asynchronous schedule

Asynchronous schedule用于管理control和bulk传输, 这两种传输都使用QH数据结构来实现调度. Asynchronous schedule从ASYNCLISTADDRregister得到 control/bulk传输的QH链表 head地址, HC即可遍历/解析asynchronous schedule的所有QH结构, 生成bus transaction.当HC完成asynchronous schedule processing时候, 就将上次访问的QH’s horizontal pointer保持在

ASYNCLISTADDR register, 以便下次asynchronous schedule可以继续上次的遍历. HC在如下情况下,完成一次asynchronous schedule的处理:

      .The end of a micro-frame occurs.

.The host controller detects an empty list condition.

.The schedule has been disabled via theAsynchronous Schedule Enable bit in the USBCMD

register.

     实际上,HC对control/bulk asynchronous 传输的调度采取round-robin的方式(Fig 1-5).

---5

Fig 1-5 General Format of Asynchronous Schedule List

1.3.3.1.         Adding Queue Heads to Asynchronous Schedule

HCD角度, 就是将一个QH结构添加到Asynchronous Schedule list中,算法如下:

InsertQueueHead (pQHeadCurrent, pQueueHeadNew)

--

-- Requirement: all inputs must be properly initialized.

--

-- pQHeadCurrent is a pointer to a queue head that is already in the active list

-- pQHeadNew is a pointer to the queue head to be added

--

-- This algorithm links a new queue head into a existing list

--

pQueueHeadNew.HorizontalPointer = pQueueHeadCurrent.HorizontalPointer

pQueueHeadCurrent.HorizontalPointer = physicalAddressOf(pQueueHeadNew)

End InsertQueueHead

 

需要注意的是, 软件需要保证添加QH过程中从HC 角度保持schedule的一致性: 所有QH结构的pointer field必须是有效的.

1.3.3.2.         Removing Queue Heads from Asynchronous Schedule

该部分从HCD角度说明如何从asynchronous schedule list中删除QH.

HCD unlink QH的算法如下:

 

 

UnlinkQueueHead (pQHeadPrevious, pQueueHeadToUnlink, pQHeadNext)

--

-- Requirement: all inputs must be properly initialized.

--

-- pQHeadPrevious is a pointer to a queue head that references the

-- queue head to remove

-- pQHeadToUnlink is a pointer to the queue head to be removed

-- pQheadNext is a pointer to a queue head still in the schedule. Software

-- provides this pointer with the following strict rules:

-- if the host software is one queue head, then pQHeadNext must be the

-- same as pQueueheadToUnlink.HorizontalPointer. If the host software is

-- unlinking a consecutive series of queue heads, pQHeadNext must be

-- set by software to the queue head remaining in the schedule.

-- This algorithm unlinks a queue head from a circular list

--

pQueueHeadPrevious.HorizontalPointer = pQueueHeadToUnlink.HorizontalPointer

pQueueHeadToUnlink.HorizontalPointer = pQHeadNext

End UnlinkQueueHead

 

从算法来看,软件操作非常简单, 但需要注意到: HC可以看作和主CPU并行运行的的处理器,

HC正在运行过程中删除某个QH的话,如何使得HC内部的状态(比如cache了QH pointer信息)和内存中实际的链表状态一致呢? EHCI提供了如下方法:

        软件UnlinkQueueHead ; //删除了内存中asynchronous schedule list中某个QH

        Set IAAD to USBCMD register; //通知HC内存中的某个asynchronous QH被删除

        使能IAA中断;

        …

        IAA  IRQ comes  //IAA中断到来,表示HC已经更新其内部状态,和内存保持一致

       

:

     IAAD: Interrupt on Async Advance Doorbell

     IAA  : Interrupt on Async Advance

1.3.3.3.         Empty Asynchronous Schedule Detection

该部分从HC角度说明.

HC使用如下信息来发现何时Asynchronous Schedule 为空:

  .H bit in QH data structure //由HC设置,asynchronous schedule中最多有1个QH设置了H bit

                        //设置H为1的QH为head ofreclaim list.

  .Reclamation bit in USBSTS register //HC遍历asynchronous schedule过程中发现了H为1的QH  //即将该位clear, 在开始执行一个transaction时候set to 1

HC发现H bit为1并且Reclamation bit 为0时候,认为发现了empty asynchronous schedule,即停止遍历asynchronous schedule.

1.3.3.4.         Restarting Asynchronous Schedule Before EOF

该部分从HC角度说明.

 

---6

Fig1-6 Example State Machine for Managing Asynchronous Schedule Traversal

检测到Empty List时候,HC会停止traversal进入idle. 那么为什么要停止呢,毕竟还没有到达end of micro-frame, 还可以执行尽可能多的transaction. 这是因为导致empty list的很多情况都是由于来自endpointNak/Nyet responses, 如果不停下来那么势必不必要的占用太多memory 总线带宽. 那么停下来后,是不是在current uFrame就不再asynchronous schedule呢? 其实不是, 从Fig1-6可以看出, 发现Empty List后, HC会进入 Async Sched Sleeping状态, 一般设置该状态的超时时间是10us,超时后又会进入Async Sched Active状态, 继续开始asynchronous schedule.

1.3.3.5.         Reclamation Status Bit (USBSTS Register)

该部分从HCD角度说明.

参考Empty Asynchronous Schedule Detection

1.3.4.   Managing Control/Bulk/Interrupt Transfers via Queue Heads

一个QH用来管理到一个endpoint的数据流. QH包含了endpoint的能力特性信息,包含了执行bus transaction的工作区. QH使用qTD来运行transaction, 每个qTD代表了一个或者多个Bus transaction.  HC会将执行qTD bus transaction时候的状态信息记录在QH.status field中,当完成一个qTD传输后,会把QH.status回写到qTD.status中, 同时不需要软件干预就可前进到下一个qTD.

   HC对QH的通用处理模型(Fig 1-7)如下:

      . read a queue head,

. execute a transaction from the overlay area,

. write back the results of the transaction to the overlay area

. move to the next queue head.

---7

Fig1-7 Host Controller Queue Head Traversal State Machine

Fig 1-7 HC QH traversal State Machine适用于各种类型的QH(control, bulk and Interrupt type),以及highspeed transaction , split transaction.

1.3.4.1.         Fetch Queue Head

HC 将QH结构读入芯片内部后,标志该状态结束.

1.3.4.2.         Advance Queue

To advance the queue, the host controller must find the next qTD, adjust pointers, perform the overlay and write back the results to the queue head.

当在FetchQHD状态, HC发现 QH overlay Active 和 HALT bits为0,即进入Advance Queue状态. 进入该状态后,HC确定 使用哪个指针来fetch a qTD, 然后fetches a qTD 并决定是否做overlay操作(当 I-bit == 1并且 Active-bit is 0, HC跳过对该QH的处理,退出该状态,并且使用当前QH的horizontal pointer到达下一个schedule data structure).

    如果 Bytes to Transfer !=0 并且 Alternate Next qTD Pointer.T ==0, HC使用 Alternate Next qTD Pointer来fetches a qTD, 否则HC使用 Next qTD Pointer. 如果 Next qTD Pointer.T==1, HC退出该状态并使用QH horizontal pointer到达下一个schedule data structure.

HC使用确定好的pointer fetches the referenced qTD, 如果the qTD.Active==1, HC设置current qTD Pointer值为所确定的取出qTD的指针, 然后performs the overlay; 如果 the qTD.Active ==0, HC退出该状态并使用QH horizontal pointer到达下一个schedule data structure.

HC 按照一系列原则 perform  overlay, 写入QH结构后, 退出该状态.

1.3.4.3.         Execute Transaction

进入该状态后, HC会执行一些pre-operations,并在执行QH所代表的transaction之前做一些

Pre-condition criteria的测试 这些pre-operations和pre-condition criteria对于interrupt QH和control/bulk QH是不同的.

 

Interrupt Transfer Pre-condition Criteria

  当 QH.S-mask & ( 1<< FRINDEX[2:0] ) != 0 时,HC 才会执行该QH的transactions.

 

Asynchronous Transfer Pre-operations

  HC判断是否需要reload the NAK Counter field, 如果需要的话,reload the NAK Count.

 

Asynchronous Transfer Pre-condition Criteria

  如果 QH. NakCnt!=0 || Reload Nak Counter ==0, HC才会执行该QH的transactions.

 

Transfer Type Independent Pre-operations

  Load the QH.Multi to HC 内部变量qHTransactionCounter, HC该实现对asynchronous QH是可选的,对 Interrupt QH是必须实现的.

 

Transfer Type Independent Pre-condition Criteria

  .HC是否可以在当前micro-frame内完成QH的一个transaction,如果不可以,那么退出该状态

  .如果 qHTransactionCounterfor an interrupt endpoint 等于0,那么HC退出该状态.

 

当所有的Pre-operations完成并且满足所有的Pre-condition Criteria后, HC设置USBCMD. Reclamation为1, 开始使用QH中的endpoint信息执行一个或者多个transaction, HC会循环qHTransactionCounter次,每执行一个transaction,qHTransactionCounter--. 当如下条件之一发生时,

HC结束该状态:

    .qHTransactionCounter == 0

  .The endpoint responds to the transaction with any handshake other than an ACK

.The transaction experiences a transaction error, or

.The Active bit in the queue head goes to a zero, or

.There is not enough time in the micro-frame left to execute the next transaction

 

每次transaction的执行结果会记录在on-chip overlay area,如果transaction的数据成功传输,overlay area的传输状态更新如下:

        Total Bytes to Transfer -=the number of bytes moved in the transaction

        Data toggle bit toggled

        Current page offset += the number of bytes moved in the transaction

        the C_Page field is updated to the appropriate value (if necessary)

当前transaction结束后, HC 将transaction的结果回写到QH’s overlay area in main memory.

 

如果transaction执行出错,传输状态不会更新, QH.CErr--, QH.status会记录错误信息. 如下事件会导致HC clear QH.status的ACTIVE bit, When theActive bit transitions from a one to a zero, the transfer in the overlay is considered complete.

   .CErr field decrements to zero.

   . The device responds to the transaction with a STALL PID.

   . The Total Bytes to Transferfield is zero after the transaction completes.

   . The PID code is an IN, and the number of bytes moved during the transaction is less than theMaximumPacket Length.

   . The PID Code field indicates an IN and the device sends more than the expected number of bytes

 

   当HC收到NAK时(并且RL==0),HC将传输结果回写到QH的overlay area. 对于high speed endpoint, QH的下述field需要被更新:

.NakCnt, dt, Total Bytes to Transfer,C_Page, Status, CERR, and Current Offset

对于full speed/low speed endpoint,需要更新QH如下的field:

.C-prog-mask, FrameTag and S-bytes.

1.3.4.4.         Write Back qTD

该状态又名 qTD retirement. 在该状态, HC将QH overlay area 回写到 QH. Current qTD Pointer 指向的目标qTD. 回写的field 至少包括:

        Total Bytes to Transfer,Cerr, and Status

1.3.4.5.         Follow Queue Head Horizontal Pointer

当如下事件发生时, HC使用QH. horizontal pointer到达下一个schedule data structure:

    .If theActive bit is a one on exit from the Execute Transaction state, or

.When the host controller exits the Write Back qTD state, or

.If the Advance Queue state fails to advance the queue because the target qTD is not active, or

.If the Halted bit is a one on exit from theFetch QH stat

:

   HC不需要等待当前transaction完成后,才使用QH. horizontal pointer读出下一个schedule data structure,但是必须完成当前transaction后,才可以执行下一个数据结构中的transaction.

1.3.4.6.         Adding Interrupt Queue Heads to the Periodic Schedule

类似与添加iTD到periodic schedule.

1.3.4.7.         Managing Transfer Complete Interrupts from Queue Heads

如果设置了qTD.IOC,那么该qTD完成后,HC会向CPU发出中断请求.

1.3.5.   Ping Control

Ping 协议是USB2.0新加的内容, 主要用于HS control/bulk endpoint, 为hs control和bulk传输的out transaction服务. Fig 1-8是ping control的状态转换表.

---8

Fig 1-8 Ping Control State Transition Table

1 Transaction Error (XactErr) is any time the host misses the handshake.

2 No transition change required for the Ping State bit. The Stall handshake results in the endpoint being halted (e.g.

Active set to zero and Halt set to a one). Software intervention is required to restart queue.

3 A Nyet response to an OUT means that the device has accepted the data, but cannot receive any more at this time. Host must advance the transfer state and additionally, transition the Ping State bit toDo Ping.

 

1.3.6.   Split Transactions

为了支持通过usb 2.0 hub接入总线的fs/ls 设备, ehci引入了split transaction. Usb2.0 规范在hs hub中集成了transaction translator(tt)来支持接入的fs/ls设备, tt充当了fs/ls host controller的角色, 负责执行到fs/ls设备的transaction. Split transaction是HC发到TT的transaction, 包括start-split transaction (ss)和 complete-split transaction(cs), ss用于HC请求TT发起一个fs/ls传输transaction, cs用于HC向TT查询ss发起的transaction是否完成,如果完成,会向cs响应并返回完成结果.

Ehci 通过 hs hub的device address以及所包含TT的port number来标识TT.

   Ehci规范中,Asynchronous schedule , Interrupt schedule 和 Isochronous schedule对split transaction的实现方法是不同的. Asynchronous schedule通过QH支持split transaction; Interrupt schedule 也是通过QH支持split transaction,同时 QH.uFrame S-mask用于设置HC在哪个micro-frame发起ss, QH.uFrame C-mask用于设置HC在哪些micro-frame发起cs, 为了解决跨frame问题(即有些CS事务需要安排到下一frame调度), 还引入了FSTN数据结构; Isochronous schedule 单独引入了siTD数据结构来支持fs/ls isochronous split transaction, siTD需要像iTD一样被链接到periodic schedule list中.

  Split transaction在ehci operational model章节中占据了不少篇幅来说明,同时也是ehci中的一个难点.