xHCI的工作流程
xHC有三条类型的操作队列,一条是整个HOST的命令队列(command ring),一条是每一个EP对应的传输队列(transfer ring),还有一条是整个HOST的事件队列(event ring). 与这个问题相关的是后面两条.
软件作为生产者(这里就是Windows8 xHCI HOST DRIVER)将需要传输的内容以TRB(transfer request block)的形式放入transfer ring. xHC host作为消费者,取出这些TRB,进行相应的数据传输操作.
在xHC host执行完相应的操作,无论成功还是失败,它将作为生产者,向event ring中放入一个TRB, 作为向软件对一笔传输事务的结果报告,软件在相应中断产生后的DPC处理中,作为消费者从event ring中取出该TRB,进行相应的处理.
ring segment trb td 的关系
记录相关数据结构之前,先上一张图,这样就基本一目了然了
USB XHCI HOST有三种RING
分别为COMMAND, EVENT 与TRANSFER
这里所说的是TRANSFER RING
一个RING可能由一个或者多个SEGMENT构成
每一个SEGMENT则有多个TRB构成
多个SEGMENT的链接是由LINK TRB来实现的,LINK就像一个单链表,最后一个LINK TRB指向第一个SEGMENT,由此,形成了一个环,RING
TRANSFER TRB有以下几种类型:
针对USB CONTROL TRANSFER的SETUP, DATA, STATUS TRBs
针对BULK, INTERRUPT, ISO TRANSFER的NORMAL TRB
针对ISO TRANSFER的ISOCH TRB (ISO TD由一个ISOCH TRB与0个或多个NORMAL TRB构成)
SW将需要硬件完成的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置位。
xhci数据结构描述
struct xhci_segment {
union xhci_trb *trbs;
/* private to HCD */
struct xhci_segment *next;
dma_addr_t dma;
/* Max packet sized bounce buffer for td-fragmant alignment */
dma_addr_t bounce_dma;
void *bounce_buf;
unsigned int bounce_offs;
unsigned int bounce_len;
};
第一个相关的数据结构,segment
1. union xhci_trb *trbs;
一个segment一般由多个trb构成,由于xhci定义了许多种trb,所以,linux driver定义了一个union
union xhci_trb *trbs; 即指向一段内存,该内存是连续的多个trb数据结构
2. struct xhci_segment *next;
硬件上,多个segment是通过link trb来串起来的
而软件上,则通过定义一个segment类型的指针来串起多个seg
3. dma_addr_t dma;
该段trbs的首总线地址,硬件通过该地址来取trbs
4. void *bounce_buf;
unsigned int bounce_offs;
unsigned int bounce_len;
这三个成员,是Linux driver最近针对XHCI SPEC 4.11.7.1 TD Fragments 加入的,本人还没有仔细研究,研究完了,再加到评论当中。
struct xhci_td {
struct list_head td_list;
struct list_head cancelled_td_list;
struct urb *urb;
struct xhci_segment *start_seg;
union xhci_trb *first_trb;
union xhci_trb *last_trb;
struct xhci_segment *bounce_seg;
/* actual_length of the URB has already been set */
bool urb_length_set;
};
1. struct list_head td_list;
硬件上,一个TD(transfer descriptor)是由CH bit来实现的,即一个TD中的所有TRB,除了最后一个的CH BIT置1,最后一个为0, 这样,RING当中的TD与TD之间,就分隔开了。
软件上则是通过list_head的形式来管理,TD。
2. struct list_head cancelled_td_list;
取消掉的TD LIST。
3. struct urb *urb;
URB USB REQUEST BLOCK
URB是比较上层的数据结构,最终,是被XHCI DRIVER分解为TRB的.
4. struct xhci_segment *start_seg;
一个TD中,对应的第一个SEGMENT。
5. union xhci_trb *first_trb;
union xhci_trb *last_trb;
一个起始TRB与一个结束TRB,他们及他们之间的TRB,构成了一个TD。
6. struct xhci_segment *bounce_seg;
没有研究,猜测与XHCI SPEC 4.11.7.1 TD Fragments,最近更新。
7. bool urb_length_set;
一个布尔变量,用来判断,URB中的actual transfer length是否已经被设置过了。
struct xhci_ring {
struct xhci_segment *first_seg;
struct xhci_segment *last_seg;
union xhci_trb *enqueue;
struct xhci_segment *enq_seg;
unsigned int enq_updates;
union xhci_trb *dequeue;
struct xhci_segment *deq_seg;
unsigned int deq_updates;
struct list_head td_list;
/*
* Write the cycle state into the TRB cycle field to give ownership of
* the TRB to the host controller (if we are the producer), or to check
* if we own the TRB (if we are the consumer). See section 4.9.1.
*/
u32 cycle_state;
unsigned int stream_id;
unsigned int num_segs;
unsigned int num_trbs_free;
unsigned int num_trbs_free_temp;
unsigned int bounce_buf_len;
enum xhci_ring_type type;
bool last_td_was_short;
struct radix_tree_root *trb_address_map;
};
RING由SEGMENT构成。
1. struct xhci_segment *first_seg;
struct xhci_segment *last_seg;
第一个与最后一个SEGMENT
2. union xhci_trb *enqueue;
struct xhci_segment *enq_seg;
unsigned int enq_updates;
union xhci_trb *dequeue;
struct xhci_segment *deq_seg;
unsigned int deq_updates;
针对RING当中的TRB,有生产与消费的关系。
生产者(SW)通过enqueue ptr来指定放入TRB的位置,消费者(HW)通过dequeue ptr来指定取得TRB的位置
3. struct list_head td_list;
一个RING当中,可能会存在多个TD
4. u32 cycle_state;
TRB中有一个CYCLE BIT, 生产者与消费者统一,这样,消费者就可以判断,当前dequeue ptr指向的TRB是有效需要执行的,还是不需要执行的无效TRB。
5. unsigned int stream_id;
与BULK STREAMING相关, 一个STREAM ID对应BULK EP的一个STREAMING。
6. unsigned int num_segs;
unsigned int num_trbs_free;
unsigned int num_trbs_free_temp;
seg, trb的统计数据
7. unsigned int bounce_buf_len;
可能还是与XHCI SPEC 4.11.7.1 TD Fragments ,最近更新
8. enum xhci_ring_type type;
枚举变量,为CMD, EVENT, TRANSFER中的一种
9. bool last_td_was_short;
布尔变量,表示一个TD是否为短包结束
10. struct radix_tree_root *trb_address_map;
RADIX TREE,方便查找TRB。
原文链接:
https://blog.****.net/u013140088/article/details/55517694
https://blog.****.net/u013140088/article/details/56278303