赞
踩
xhci 数据结构主要在手册上有详细的定义,本文根据手册进行归纳总结:
重点关注的包括:
设备上下文数据结构由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主要是有关 包含与整个设备有关的信息,或影响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使用,除非插槽处于“禁用”状态,否则不得由系统软件修改。
重点参数:
针对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是一个循环队列,xHC使用三种类型的Ring:
备注:每个设备,插入的过程中,会根据设备反馈的设备描述符,注册相应的多个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 };
重点介绍每个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_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_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 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。