先上代码,
1. static void scan_async (struct ehci_hcd *ehci)
2. {
3. struct ehci_qh *qh;
4. bool check_unlinks_later = false;
5.
6. ehci->qh_scan_next = ehci->async->qh_next.qh;
7. while (ehci->qh_scan_next) {
8. qh = ehci->qh_scan_next;
9. ehci->qh_scan_next = qh->qh_next.qh;
10.
11. /* clean any finished work for this qh */
12. if (!list_empty(&qh->qtd_list)) {
13. int temp;
14.
15. /*
16. * Unlinks could happen here; completion reporting
17. * drops the lock. That's why ehci->qh_scan_next
18. * always holds the next qh to scan; if the next qh
19. * gets unlinked then ehci->qh_scan_next is adjusted
20. * in single_unlink_async().
21. */
22. temp = qh_completions(ehci, qh);
23. if (unlikely(temp)) {
24. start_unlink_async(ehci, qh);
25. } else if (list_empty(&qh->qtd_list)
26. && qh->qh_state == QH_STATE_LINKED) {
27. qh->unlink_cycle = ehci->async_unlink_cycle;
28. check_unlinks_later = true;
29. }
30. }
31. }
32.
33. /*
34. * Unlink empty entries, reducing DMA usage as well
35. * as HCD schedule-scanning costs. Delay for any qh
36. * we just scanned, there's a not-unusual case that it
37. * doesn't stay idle for long.
38. */
39. if (check_unlinks_later && ehci->rh_state == EHCI_RH_RUNNING &&
40. !(ehci->enabled_hrtimer_events &
41. BIT(EHCI_HRTIMER_ASYNC_UNLINKS))) {
42. ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);
43. ++ehci->async_unlink_cycle;
44. }
45. }
46.
Asynchronous传输在EHCI中由qh和qtd来完成的,从通信模型的抽象层面上来说,qh和qtd分别代表了通信的一方,qh代表USB device方(准确的说是device上的endpoint),qtd代表CPU方(实际上是某块DMA内存区域)。分配给device endpoint的qh是伴随device在HCD中一直存在的,只要device没有被拔出,为device endpoint分配的qh就是固定的;相对而言CPU方的用于数据传输的内存区域却是变化的,这也是显而易见的,所以在完成数据传输后分配的qtd会被回收。而scan_async()函数的工作就是去check传输的状况,并回收qtd。
首先了解一下EHCI asynchronous传输是怎样利用qh和qtd来完成数据传输的。如图1所示,CPU通过由EHCI HC提供的一组register来与之交互,qh和qtd是存在于内存中的数据段,HC需要从内存中将之读取到它的缓存中,HC正是通过EHCI提供的这组register中的AsyncListAddr获取到内存中qh的地址的。具体的过程是,CPU先把多个qh组成的一个循环队列头qh的物理地址写入AsyncListAddr中,HC再根据AsyncListAddr的值去内存寻址qh的所在位置。构成一个qh循环队列是通过qh结构体中的头四个字节,去指向下一个qh的物理地址实现的,并且最后一个qh将指回首个qh,而qtd则使依附在qh中的,即HC通过AsyncListAddr找到qh,在通过qh找到qtd。更详细的细节可参考EHCI spec。
图1
Linux中ehci driver对qh的组织方式是先分配一个不依附于任何endpoint的qh数据结构,作为qh循环队列的头,这个qh不用于实际的数据传输,只用于寻址下一个qh,这个qh的物理地址写入AsyncListAddr,如图1所示,并把qh的虚拟地址保存在ehci->async中。
回到qtd回收的讨论中来,scan_async()函数中第25行的qh_completions()函数完成了真正的qtd扫尾工作,那就先从这个qh_completions()说起,代码如下。
1. /*
2. * Process and free completed qtds for a qh, returning URBs to drivers.
3. * Chases up to qh->hw_current. Returns nonzero if the caller should
4. * unlink qh.
5. */
6. static unsigned
7. qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
8. {
9. struct ehci_qtd *last, *end = qh->dummy;
10. struct list_head *entry, *tmp;
11. int last_status;
12. int stopped;
13. u8 state;
14. struct ehci_qh_hw *hw = qh->hw;
15.
16. /* completions (or tasks on other cpus) must never clobber HALT
17. * till we've gone through and cleaned everything up, even when
18. * they add urbs to this qh's queue or mark them for unlinking.
19. *
20. * NOTE: unlinking expects to be done in queue order.
21. *
22. * It's a bug for qh->qh_state to be anything other than
23. * QH_STATE_IDLE, unless our caller is scan_async() or
24. * scan_intr().
25. */
26. state = qh->qh_state;
27. qh->qh_state = QH_STATE_COMPLETING;
28. stopped = (state == QH_STATE_IDLE);
29.
30. rescan:
31. last = NULL;
32. last_status = -EINPROGRESS;
33. qh->dequeue_during_giveback = 0;
34.
35. /* remove de-activated QTDs from front of queue.
36. * after faults (including short reads), cleanup this urb
37. * then let the queue advance.
38. * if queue is stopped, handles unlinks.
39. */
40. list_for_each_safe (entry, tmp, &qh->qtd_list) {
41. struct ehci_qtd *qtd;
42. struct urb *urb;
43. u32 token = 0;
44.
45. qtd = list_entry (entry, struct ehci_qtd, qtd_list);
46. urb = qtd->urb;
47.
48. /* clean up any state from previous QTD ...*/
49. if (last) {
50. if (likely (last->urb != urb)) {
51. ehci_urb_done(ehci, last->urb, last_status);
52. last_status = -EINPROGRESS;
53. }
54. ehci_qtd_free (ehci, last);
55. last = NULL;
56. }
57.
58. /* ignore urbs submitted during completions we reported */
59. if (qtd == end)
60. break;
61.
62. /* hardware copies qtd out of qh overlay */
63. rmb ();
64. token = hc32_to_cpu(ehci, qtd->hw_token);
65.
66. /* always clean up qtds the hc de-activated */
67. retry_xacterr:
68. if ((token & QTD_STS_ACTIVE) == 0) {
69.
70. /* Report Data Buffer Error: non-fatal but useful */
71. if (token & QTD_STS_DBE)
72. ehci_dbg(ehci,
73. "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
74. urb,
75. usb_endpoint_num(&urb->ep->desc),
76. usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out",
77. urb->transfer_buffer_length,
78. qtd,
79. qh);
80.
81. /* on STALL, error, and short reads this urb must
82. * complete and all its qtds must be recycled.
83. */
84. if ((token & QTD_STS_HALT) != 0) {
85.
86. /* retry transaction errors until we
87. * reach the software xacterr limit
88. */
89. if ((token & QTD_STS_XACT) &&
90. QTD_CERR(token) == 0 &&
91. ++qh->xacterrs < QH_XACTERR_MAX &&
92. !urb->unlinked) {
93. ehci_dbg(ehci,
94. "detected XactErr len %zu/%zu retry %d\n",
95. qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
96.
97. /* reset the token in the qtd and the
98. * qh overlay (which still contains
99. * the qtd) so that we pick up from
100. * where we left off
101. */
102. token &= ~QTD_STS_HALT;
103. token |= QTD_STS_ACTIVE |
104. (EHCI_TUNE_CERR << 10);
105. qtd->hw_token = cpu_to_hc32(ehci,
106. token);
107. wmb();
108. hw->hw_token = cpu_to_hc32(ehci,
109. token);
110. goto retry_xacterr;
111. }
112. stopped = 1;
113.
114. /* magic dummy for some short reads; qh won't advance.
115. * that silicon quirk can kick in with this dummy too.
116. *
117. * other short reads won't stop the queue, including
118. * control transfers (status stage handles that) or
119. * most other single-qtd reads ... the queue stops if
120. * URB_SHORT_NOT_OK was set so the driver submitting
121. * the urbs could clean it up.
122. */
123. } else if (IS_SHORT_READ (token)
124. && !(qtd->hw_alt_next
125. & EHCI_LIST_END(ehci))) {
126. stopped = 1;
127. }
128.
129. /* stop scanning when we reach qtds the hc is using */
130. } else if (likely (!stopped
131. && ehci->rh_state >= EHCI_RH_RUNNING)) {
132. break;
133.
134. /* scan the whole queue for unlinks whenever it stops */
135. } else {
136. stopped = 1;
137.
138. /* cancel everything if we halt, suspend, etc */
139. if (ehci->rh_state < EHCI_RH_RUNNING)
140. last_status = -ESHUTDOWN;
141.
142. /* this qtd is active; skip it unless a previous qtd
143. * for its urb faulted, or its urb was canceled.
144. */
145. else if (last_status == -EINPROGRESS && !urb->unlinked)
146. continue;
147.
148. /*
149. * If this was the active qtd when the qh was unlinked
150. * and the overlay's token is active, then the overlay
151. * hasn't been written back to the qtd yet so use its
152. * token instead of the qtd's. After the qtd is
153. * processed and removed, the overlay won't be valid
154. * any more.
155. */
156. if (state == QH_STATE_IDLE &&
157. qh->qtd_list.next == &qtd->qtd_list &&
158. (hw->hw_token & ACTIVE_BIT(ehci))) {
159. token = hc32_to_cpu(ehci, hw->hw_token);
160. hw->hw_token &= ~ACTIVE_BIT(ehci);
161.
162. /* An unlink may leave an incomplete
163. * async transaction in the TT buffer.
164. * We have to clear it.
165. */
166. ehci_clear_tt_buffer(ehci, qh, urb, token);
167. }
168. }
169.
170. /* unless we already know the urb's status, collect qtd status
171. * and update count of bytes transferred. in common short read
172. * cases with only one data qtd (including control transfers),
173. * queue processing won't halt. but with two or more qtds (for
174. * example, with a 32 KB transfer), when the first qtd gets a
175. * short read the second must be removed by hand.
176. */
177. if (last_status == -EINPROGRESS) {
178. last_status = qtd_copy_status(ehci, urb,
179. qtd->length, token);
180. if (last_status == -EREMOTEIO
181. && (qtd->hw_alt_next
182. & EHCI_LIST_END(ehci)))
183. last_status = -EINPROGRESS;
184.
185. /* As part of low/full-speed endpoint-halt processing
186. * we must clear the TT buffer (11.17.5).
187. */
188. if (unlikely(last_status != -EINPROGRESS &&
189. last_status != -EREMOTEIO)) {
190. /* The TT's in some hubs malfunction when they
191. * receive this request following a STALL (they
192. * stop sending isochronous packets). Since a
193. * STALL can't leave the TT buffer in a busy
194. * state (if you believe Figures 11-48 - 11-51
195. * in the USB 2.0 spec), we won't clear the TT
196. * buffer in this case. Strictly speaking this
197. * is a violation of the spec.
198. */
199. if (last_status != -EPIPE)
200. ehci_clear_tt_buffer(ehci, qh, urb,
201. token);
202. }
203. }
204.
205. /* if we're removing something not at the queue head,
206. * patch the hardware queue pointer.
207. */
208. if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
209. last = list_entry (qtd->qtd_list.prev,
210. struct ehci_qtd, qtd_list);
211. last->hw_next = qtd->hw_next;
212. }
213.
214. /* remove qtd; it's recycled after possible urb completion */
215. list_del (&qtd->qtd_list);
216. last = qtd;
217.
218. /* reinit the xacterr counter for the next qtd */
219. qh->xacterrs = 0;
220. }
221.
222. /* last urb's completion might still need calling */
223. if (likely (last != NULL)) {
224. ehci_urb_done(ehci, last->urb, last_status);
225. ehci_qtd_free (ehci, last);
226. }
227.
228. /* Do we need to rescan for URBs dequeued during a giveback? */
229. if (unlikely(qh->dequeue_during_giveback)) {
230. /* If the QH is already unlinked, do the rescan now. */
231. if (state == QH_STATE_IDLE)
232. goto rescan;
233.
234. /* Otherwise the caller must unlink the QH. */
235. }
236.
237. /* restore original state; caller must unlink or relink */
238. qh->qh_state = state;
239.
240. /* be sure the hardware's done with the qh before refreshing
241. * it after fault cleanup, or recovering from silicon wrongly
242. * overlaying the dummy qtd (which reduces DMA chatter).
243. *
244. * We won't refresh a QH that's linked (after the HC
245. * stopped the queue). That avoids a race:
246. * - HC reads first part of QH;
247. * - CPU updates that first part and the token;
248. * - HC reads rest of that QH, including token
249. * Result: HC gets an inconsistent image, and then
250. * DMAs to/from the wrong memory (corrupting it).
251. *
252. * That should be rare for interrupt transfers,
253. * except maybe high bandwidth ...
254. */
255. if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci))
256. qh->exception = 1;
257.
258. /* Let the caller know if the QH needs to be unlinked. */
259. return qh->exception;
260. }
函数qh_completions()比较长,但几个if-else的判断语句占了大部分,qh_completions()中通过对qh下链接的qtd进行逐个遍历,来判断传输的情况,HC会把传输的实际状况值回写到qtd中的token字段的status中,Status共有8位,每一位都单独代表一种传输状态,除第7位外均代表了一种出错状态。所以对这样的一段if-else语句,如果数据传输中没有出错,大部分的代码都是会被bypass掉的。
还是从头讲起吧,第40行的list_for_each_safe中对qtd_list进行遍历,其中函数qh_completions()的参数qh上关联了一个qtd队列,list_for_each_safe逐个的把qh上的qtd取出放在指针entry中,list_for_each_safe的特点是可以中途删除entry,通过指针tmp去找到下一个entry。
第44行,list_entry得到entry所指qtd的指针地址,放在指针变量qtd,通过这样几步就找出了qtd的数据结构实际在内存中的地址。得到这些qtd的实际所在后,就要根据其的实际情况进行处理。
第47行,指针last的初始值为NULL,首次执行到这里时,直接跳过整个if语句,当再一次执行到此处时,如果前一次的处理中有qtd是执行完传输的(包括传输出错),last此时就会指向了前一个qtd,并在if语句中的ehci_qtd_free()函数中把分配的qtd空间释放掉。由多个qtd形成的队列是一个单向链表,链表的末尾的qtd被设置成不可用的状态,表示传输的完结点,可以通过qh->dummy指针找到这个qtd,即这个qtd是一个dummy,实际的内容为空,用于标记qtd链表的结束。一个qtd链表中的urb指针的指向都是相同的,除了最末这一个dummy qtd,所以在遍历到最后的qtd时“last->urb != urb”满足。49行ehci_urb_done()会被调用,ehci_urb_done()要做的一件事是回调urb->complete()函数指针,从而使控制权回到USB device Driver中,这就是我们填充一个urb的回调函数的触发处。57行的判断遍历到最后的dummy qtd,就跳出循环,表明整个qtd链表已被处理完了。
前面讲过,HC在处理完一个qtd后,反映处理结果的值会回写到当前qtd的token字段中,HCD读取这个token的Status值后,可以获知HC的传输情况。第61行把qtd的token值暂存到变量token中。Token的[7:0]位是状态值,其中第7位为Active位,由HCD置1,表明qtd处于激活状态,这样HC可能正在处理该qtd,或准备处理。当传输完成或出错后,Active位由HC置0。如果执行该段代码是由中断触发的,那么Active位一定为0,即有一次传输结束。如果是由timer polling执行到此处,那么Active位的值就可能为0或1,即不一定有传输完成。这里假设捕获到一次qtd的传输完成了,即Active位等于0,看看接下来的处理。
第66行处,是对Data Buffer Error的处理,token第5位被置1,表明发生了这样的错误。这样的错误,在EHCI SPEC里说,不被视作传输错误,会强制endpoint重发一次,所以代码也只是做了打印。
如果有一次qtd的传输完成,Active位被置为0,进入64行的if语句内部。接下来就是一个检测处理了,token的第6位为Halted位,当该位被HC置1时,就表明当前qtd的传输出现了错误,而且与该endpoint的传输都被停掉,同时Active位会被置0。Halted位被置1,不能确切的知道错误的类型和原因,token的3位进一步指明了halted的原因。Token的第3位XactErr当被HC置1时,表明HC没有收到device发回的有效应答包,这时HC的传输已经停下来了,传输出错的qtd依然保留在qh的overlay中,出现这样的错误HCD的处理方式是,由软件把Halted位清零,token[11:10] CERR位设为0x3,Active位置1再次使能该qtd,让HC重新传输这个qtd。第102行的goto语句返回到retry_xacterr处,重复以上动作,直到传输成功为止。
如前面的假设Active位为1,那么接下来的else-if-else代码段,就可以忽略了,这两段代码check了HC的运行状态,120-122行检测到HC正在running,所以什么都不做,跳出循环。
第153行,变量last_status通过qtd_copy_status()获取到,前面代码对一次qtd的传输后的状态处理是针对halted的,在函数qtd_copy_status()中会把实际传输的数据长度更新到urb->actual_length中,如果一个qtd上的数据只完成了部分的传输,即实际传输的数据量小于要求的传输量,那么会被视为一个SHORT错误,qtd_copy_status()会返回这些错误值。
在182行处的变量stopped在104行赋值为1,指针qtd如果指向qtd链表的首个qtd,那么qtd->qtd_list.prev 就指向了qh->qtd_list,qtd链表上的传输要按这样的链表上的顺序依次传输,一旦qtd上的传输完成了,也应该是依次被从链表上remove,被移除的qtd的下一个qtd就被挪到链表首,如果将要从链表上移除的qtd的前一项未指向链表头,而是另一个qtd,这里要把这前一个qtd-> hw_next等于当前要被移除qtd-> hw_next的值。由多个qtd构成的链表,在HC看来是通过物理地址相连的单向链表,在HCD看来是一个双向的链表。
在188行处把qtd从链表队列中删除,指针last此时就指向这个被移除的qtd,如果qtd不是链表的末项,再一次的循环时47行处qtd被真正的回收。
前面讲过整个遍历会从58行break语句退出,即遍历到dummy qtd后,结束退出。从193行开始,如果指针last非空,那么一定是指向一个qtd链表队列的末尾处(非dummy qtd),前面提到过一个qtd链表队列,构成了一个完整的逻辑传输,整个qtd list被传输完毕后,就可以通知usb device driver即调用urb->complete()回调函数了。最再将这个qtd的空间回收。
在这里整个qh_completions()函数就差不多讲完了,后面的两个if判断语句,一个是关于再次遍历的问题,另一个是对qh进行refresh。关于qh_refresh()函数可以参考前面的文章。最后qh_completions()函数返回count值,如果成功的完成了一次qtd队列的处理,count返回1。
对qh_completions()做一个小结,对qh上连接的qtd队列,在完成传输后,对qtd项做后续的处理。
现在回到函数scan_async()中,刚才把最长的qh_completions()函数讲完了,现在来讲scan_async()函数就轻松多了。在贴一次scan_async()的代码。
static void scan_async (struct ehci_hcd *ehci)
{
bool stopped;
struct ehci_qh *qh;
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
stopped = (ehci->rh_state != EHCI_RH_RUNNING);
ehci->qh_scan_next = ehci->async->qh_next.qh;
while (ehci->qh_scan_next) {
qh = ehci->qh_scan_next;
ehci->qh_scan_next = qh->qh_next.qh;
rescan:
/* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) {
int temp;
/*
* Unlinks could happen here; completion reporting
* drops the lock. That's why ehci->qh_scan_next
* always holds the next qh to scan; if the next qh
* gets unlinked then ehci->qh_scan_next is adjusted
* in start_unlink_async().
*/
qh = qh_get(qh);
temp = qh_completions(ehci, qh);
if (qh->needs_rescan)
unlink_async(ehci, qh);
qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
qh_put(qh);
if (temp != 0)
goto rescan;
}
/* unlink idle entries, reducing DMA usage as well
* as HCD schedule-scanning costs. delay for any qh
* we just scanned, there's a not-unusual case that it
* doesn't stay idle for long.
* (plus, avoids some kind of re-activation race.)
*/
if (list_empty(&qh->qtd_list)
&& qh->qh_state == QH_STATE_LINKED) {
if (!ehci->reclaim && (stopped ||
time_after_eq(jiffies, qh->unlink_time)))
start_unlink_async(ehci, qh);
else
action = TIMER_ASYNC_SHRINK;
}
}
if (action == TIMER_ASYNC_SHRINK)
timer_action (ehci, TIMER_ASYNC_SHRINK);
}
前面在分析qh_completions()时,知道其是对qtd链表队列进行遍历逐项处理,而这些qtd队列是与某个qh相关联的。类似scan_async()是对qh构成的队列进行遍历,逐个处理qh。如图1右侧所示,即是qh构成的链表。在内存中qh与qtd的组成的数据结构,应是图2所示的连接结构,最后的一个qh的next应该指向头个qh,形成一个循环,如图1,这里没有画出来。图中的scan_async箭头,表明了scan_async()函数负责qh的处理,箭头qh_completions是对qtd的处理。
图2
结合图2来表述scan_async()的流程,来qh的循环队列中,依次取出各个qh,并把qh上的qtd_list交给qh_completions()处理。
函数scan_async()的代码分析就到此为止了。