Rev 3826 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3826 | Rev 4418 | ||
---|---|---|---|
Line 8... | Line 8... | ||
8 | ; * for every millisecond, take all bandwidth scheduled to periodic transfers, |
8 | ; * for every millisecond, take all bandwidth scheduled to periodic transfers, |
9 | ; * calculate maximum over all milliseconds, |
9 | ; * calculate maximum over all milliseconds, |
10 | ; * select a variant which minimizes that maximum; |
10 | ; * select a variant which minimizes that maximum; |
11 | ; when removing a pipe, do nothing (except for bookkeeping). |
11 | ; when removing a pipe, do nothing (except for bookkeeping). |
Line 12... | Line 12... | ||
12 | 12 | ||
- | 13 | ; The caller must provide CONTROLLER_NAME define. |
|
- | 14 | macro define_controller_name name |
|
13 | ; sanity check: structures in UHCI and OHCI should be the same |
15 | { |
- | 16 | _hci_static_ep.SoftwarePart = name # _static_ep.SoftwarePart |
|
- | 17 | _hci_static_ep.NextList = name # _static_ep.NextList |
|
- | 18 | sizeof._hci_static_ep = sizeof. # name # _static_ep |
|
- | 19 | } |
|
14 | if (sizeof.ohci_static_ep=sizeof.uhci_static_ep)&(ohci_static_ep.SoftwarePart=uhci_static_ep.SoftwarePart)&(ohci_static_ep.NextList=uhci_static_ep.NextList) |
20 | |
15 | ; Select a list for a new pipe. |
21 | ; Select a list for a new pipe. |
16 | ; in: esi -> usb_controller, maxpacket, type, interval can be found in the stack |
22 | ; in: esi -> usb_controller, maxpacket, type, interval can be found in the stack |
17 | ; in: ecx = 2 * maximal interval = total number of periodic lists + 1 |
23 | ; in: ecx = 2 * maximal interval = total number of periodic lists + 1 |
18 | ; in: edx -> {u|o}hci_static_ep for the first list |
24 | ; in: edx -> {u|o}hci_static_ep for the first list |
Line 63... | Line 69... | ||
63 | ; * the outermost loop checks all variants. |
69 | ; * the outermost loop checks all variants. |
64 | ; 2. Calculate offset between the first list and the first list for the |
70 | ; 2. Calculate offset between the first list and the first list for the |
65 | ; selected interval, in bytes; save in the stack for step 4. |
71 | ; selected interval, in bytes; save in the stack for step 4. |
66 | sub eax, ecx |
72 | sub eax, ecx |
67 | sub eax, ecx |
73 | sub eax, ecx |
68 | imul eax, sizeof.ohci_static_ep |
74 | imul eax, sizeof._hci_static_ep |
69 | push eax |
75 | push eax |
70 | imul ebx, ecx, sizeof.ohci_static_ep |
76 | imul ebx, ecx, sizeof._hci_static_ep |
71 | ; 3. Select the best variant. |
77 | ; 3. Select the best variant. |
72 | ; 3a. The outermost loop. |
78 | ; 3a. The outermost loop. |
73 | ; Prepare for the loop: set the current optimal bandwidth to maximum |
79 | ; Prepare for the loop: set the current optimal bandwidth to maximum |
74 | ; possible value (so that any variant will pass the first comparison), |
80 | ; possible value (so that any variant will pass the first comparison), |
75 | ; calculate delta for the intermediate loop. |
81 | ; calculate delta for the intermediate loop. |
Line 88... | Line 94... | ||
88 | .calc_max_bandwidth: |
94 | .calc_max_bandwidth: |
89 | ; 3c. The innermost loop. Sum over all lists. |
95 | ; 3c. The innermost loop. Sum over all lists. |
90 | xor eax, eax |
96 | xor eax, eax |
91 | push edx |
97 | push edx |
92 | .calc_bandwidth: |
98 | .calc_bandwidth: |
93 | add eax, [edx+ohci_static_ep.SoftwarePart+usb_static_ep.Bandwidth] |
99 | add eax, [edx+_hci_static_ep.SoftwarePart+usb_static_ep.Bandwidth] |
94 | mov edx, [edx+ohci_static_ep.NextList] |
100 | mov edx, [edx+_hci_static_ep.NextList] |
95 | test edx, edx |
101 | test edx, edx |
96 | jnz .calc_bandwidth |
102 | jnz .calc_bandwidth |
97 | pop edx |
103 | pop edx |
98 | ; 3d. The intermediate loop continued: update maximum. |
104 | ; 3d. The intermediate loop continued: update maximum. |
99 | cmp eax, edi |
105 | cmp eax, edi |
Line 113... | Line 119... | ||
113 | ja @f |
119 | ja @f |
114 | mov [.bandwidth], edi |
120 | mov [.bandwidth], edi |
115 | mov [.target], edx |
121 | mov [.target], edx |
116 | @@: |
122 | @@: |
117 | ; 3g. The outermost loop continued: advance counter. |
123 | ; 3g. The outermost loop continued: advance counter. |
118 | add edx, sizeof.ohci_static_ep |
124 | add edx, sizeof._hci_static_ep |
119 | dec ecx |
125 | dec ecx |
120 | jnz .varloop |
126 | jnz .varloop |
121 | ; 4. Calculate bandwidth for the new pipe. |
127 | ; 4. Calculate bandwidth for the new pipe. |
122 | mov eax, [.maxpacket] |
128 | mov eax, [.maxpacket] |
123 | mov cl, [.speed] |
129 | mov cl, [.speed] |
Line 133... | Line 139... | ||
133 | mov ecx, eax |
139 | mov ecx, eax |
134 | add ecx, [.bandwidth] |
140 | add ecx, [.bandwidth] |
135 | cmp ecx, 10800 |
141 | cmp ecx, 10800 |
136 | ja .no_bandwidth |
142 | ja .no_bandwidth |
137 | ; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
143 | ; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
138 | add edx, ohci_static_ep.SoftwarePart |
144 | add edx, _hci_static_ep.SoftwarePart |
139 | add [edx+usb_static_ep.Bandwidth], eax |
145 | add [edx+usb_static_ep.Bandwidth], eax |
140 | pop edi ebx ; restore used registers to be stdcall |
146 | pop edi ebx ; restore used registers to be stdcall |
141 | ret |
147 | ret |
142 | .no_bandwidth: |
148 | .no_bandwidth: |
143 | dbgstr 'Periodic bandwidth limit reached' |
149 | dbgstr 'Periodic bandwidth limit reached' |
144 | xor edx, edx |
150 | xor edx, edx |
145 | pop edi ebx |
151 | pop edi ebx |
146 | ret |
152 | ret |
147 | endp |
153 | endp |
148 | ; sanity check, part 2 |
- | |
149 | else |
- | |
150 | .err select_interrupt_list must be different for UHCI and OHCI |
- | |
151 | end if |
- | |
Line 152... | Line 154... | ||
152 | 154 | ||
153 | ; Pipe is removing, update the corresponding lists. |
155 | ; Pipe is removing, update the corresponding lists. |
154 | ; We do not reorder anything, so just update book-keeping variable |
156 | ; We do not reorder anything, so just update book-keeping variable |
155 | ; in the list header. |
157 | ; in the list header. |
Line 226... | Line 228... | ||
226 | ; 16 bits for PRE packet, 4 bits for hub delay, 8*20 bits for Handshake packet, |
228 | ; 16 bits for PRE packet, 4 bits for hub delay, 8*20 bits for Handshake packet, |
227 | ; 8*2 bits for another inter-packet delay. |
229 | ; 8*2 bits for another inter-packet delay. |
228 | lea eax, [ecx+edx+778] |
230 | lea eax, [ecx+edx+778] |
229 | ret |
231 | ret |
230 | endp |
232 | endp>=>>=> |
231 | - | ||
232 | ; USB2 scheduler. |
- | |
233 | ; There are two parts: high-speed pipes and split-transaction pipes. |
- | |
234 | ; |
- | |
235 | ; High-speed scheduler uses the same algorithm as USB1 scheduler: |
- | |
236 | ; when adding a pipe, optimize the following quantity: |
- | |
237 | ; * for every microframe, take all bandwidth scheduled to periodic transfers, |
- | |
238 | ; * calculate maximum over all microframes, |
- | |
239 | ; * select a variant which minimizes that maximum; |
- | |
240 | ; * if there are several such variants, |
- | |
241 | ; prefer those that are closer to end of frame |
- | |
242 | ; to minimize collisions with split transactions; |
- | |
243 | ; when removing a pipe, do nothing (except for bookkeeping). |
- | |
244 | ; in: esi -> usb_controller |
- | |
245 | ; out: edx -> usb_static_ep, eax = S-Mask |
- | |
246 | proc ehci_select_hs_interrupt_list |
- | |
247 | ; inherit some variables from usb_open_pipe |
- | |
248 | virtual at ebp-12 |
- | |
249 | .targetsmask dd ? |
- | |
250 | .bandwidth dd ? |
- | |
251 | .target dd ? |
- | |
252 | dd ? |
- | |
253 | dd ? |
- | |
254 | .config_pipe dd ? |
- | |
255 | .endpoint dd ? |
- | |
256 | .maxpacket dd ? |
- | |
257 | .type dd ? |
- | |
258 | .interval dd ? |
- | |
259 | end virtual |
- | |
260 | ; prolog, initialize local vars |
- | |
261 | or [.bandwidth], -1 |
- | |
262 | or [.target], -1 |
- | |
263 | or [.targetsmask], -1 |
- | |
264 | push ebx edi ; save used registers to be stdcall |
- | |
265 | ; 1. In EHCI, every list describes one millisecond = 8 microframes. |
- | |
266 | ; Thus, there are two significantly different branches: |
- | |
267 | ; for pipes with interval >= 8 microframes, advance to 2, |
- | |
268 | ; for pipes which should be planned in every frame (one or more microframes), |
- | |
269 | ; go to 9. |
- | |
270 | ; Note: the actual interval for high-speed devices is 2^([.interval]-1), |
- | |
271 | ; (the core specification forbids [.interval] == 0) |
- | |
272 | mov ecx, [.interval] |
- | |
273 | dec ecx |
- | |
274 | cmp ecx, 3 |
- | |
275 | jb .every_frame |
- | |
276 | ; 2. Determine the actual interval in milliseconds. |
- | |
277 | sub ecx, 3 |
- | |
278 | cmp ecx, 5 ; maximum 32ms |
- | |
279 | jbe @f |
- | |
280 | movi ecx, 5 |
- | |
281 | @@: |
- | |
282 | ; There are four nested loops, |
- | |
283 | ; * Loop #4 (the innermost one) calculates the total periodic bandwidth |
- | |
284 | ; scheduled in the given microframe of the given millisecond. |
- | |
285 | ; * Loop #3 calculates the maximum over all milliseconds |
- | |
286 | ; in the given variant, that is the quantity we're trying to minimize. |
- | |
287 | ; * Loops #1 and #2 check all variants; |
- | |
288 | ; loop #1 is responsible for the target millisecond, |
- | |
289 | ; loop #2 is responsible for the microframe within millisecond. |
- | |
290 | ; 3. Prepare for loops. |
- | |
291 | ; ebx = number of iterations of loop #1 |
- | |
292 | ; [esp] = delta of counter for loop #3, in bytes |
- | |
293 | ; [esp+4] = delta between the first group and the target group, in bytes |
- | |
294 | movi ebx, 1 |
- | |
295 | movi edx, sizeof.ehci_static_ep |
- | |
296 | shl ebx, cl |
- | |
297 | shl edx, cl |
- | |
298 | mov eax, 64*sizeof.ehci_static_ep |
- | |
299 | sub eax, edx |
- | |
300 | sub eax, edx |
- | |
301 | push eax |
- | |
302 | push edx |
- | |
303 | ; 4. Select the best variant. |
- | |
304 | ; 4a. Loop #1: initialize counter = pointer to ehci_static_ep for |
- | |
305 | ; the target millisecond in the first group. |
- | |
306 | lea edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
- | |
307 | .varloop0: |
- | |
308 | ; 4b. Loop #2: initialize counter = microframe within the target millisecond. |
- | |
309 | xor ecx, ecx |
- | |
310 | .varloop: |
- | |
311 | ; 4c. Loop #3: save counter of loop #1, |
- | |
312 | ; initialize counter with the value of loop #1 counter, |
- | |
313 | ; initialize maximal bandwidth = zero. |
- | |
314 | xor edi, edi |
- | |
315 | push edx |
- | |
316 | virtual at esp |
- | |
317 | .saved_counter1 dd ? ; step 4c |
- | |
318 | .loop3_delta dd ? ; step 3 |
- | |
319 | .target_delta dd ? ; step 3 |
- | |
320 | end virtual |
- | |
321 | .calc_max_bandwidth: |
- | |
322 | ; 4d. Loop #4: initialize counter with the value of loop #3 counter, |
- | |
323 | ; initialize total bandwidth = zero. |
- | |
324 | xor eax, eax |
- | |
325 | push edx |
- | |
326 | .calc_bandwidth: |
- | |
327 | ; 4e. Loop #4: add the bandwidth from the current list |
- | |
328 | ; and advance to the next list, while there is one. |
- | |
329 | add ax, [edx+ehci_static_ep.Bandwidths+ecx*2] |
- | |
330 | mov edx, [edx+ehci_static_ep.NextList] |
- | |
331 | test edx, edx |
- | |
332 | jnz .calc_bandwidth |
- | |
333 | ; 4f. Loop #4 end: restore counter of loop #3. |
- | |
334 | pop edx |
- | |
335 | ; 4g. Loop #3: update maximal bandwidth. |
- | |
336 | cmp eax, edi |
- | |
337 | jb @f |
- | |
338 | mov edi, eax |
- | |
339 | @@: |
- | |
340 | ; 4h. Loop #3: advance the counter and repeat while within the first group. |
- | |
341 | lea eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller] |
- | |
342 | add edx, [.loop3_delta] |
- | |
343 | cmp edx, eax |
- | |
344 | jb .calc_max_bandwidth |
- | |
345 | ; 4i. Loop #3 end: restore counter of loop #1. |
- | |
346 | pop edx |
- | |
347 | ; 4j. Loop #2: if the current variant is better (maybe not strictly) |
- | |
348 | ; then the previous optimum, update the optimal bandwidth and the target. |
- | |
349 | cmp edi, [.bandwidth] |
- | |
350 | ja @f |
- | |
351 | jb .update |
- | |
352 | cmp ecx, [.targetsmask] |
- | |
353 | jb @f |
- | |
354 | .update: |
- | |
355 | mov [.bandwidth], edi |
- | |
356 | mov [.target], edx |
- | |
357 | mov [.targetsmask], ecx |
- | |
358 | @@: |
- | |
359 | ; 4k. Loop #2: continue 8 times for every microframe. |
- | |
360 | inc ecx |
- | |
361 | cmp ecx, 8 |
- | |
362 | jb .varloop |
- | |
363 | ; 4l. Loop #1: advance counter and repeat ebx times, |
- | |
364 | ; ebx was calculated in step 3. |
- | |
365 | add edx, sizeof.ehci_static_ep |
- | |
366 | dec ebx |
- | |
367 | jnz .varloop0 |
- | |
368 | ; 5. Calculate bandwidth for the new pipe. |
- | |
369 | mov eax, [.maxpacket] |
- | |
370 | call calc_hs_bandwidth |
- | |
371 | mov ecx, [.maxpacket] |
- | |
372 | shr ecx, 11 |
- | |
373 | inc ecx |
- | |
374 | and ecx, 3 |
- | |
375 | imul eax, ecx |
- | |
376 | ; 6. Get the pointer to the best list. |
- | |
377 | pop edx ; restore value from step 3 |
- | |
378 | pop edx ; get delta calculated in step 3 |
- | |
379 | add edx, [.target] |
- | |
380 | ; 7. Check that bandwidth for the new pipe plus old bandwidth |
- | |
381 | ; still fits to maximum allowed by the core specification |
- | |
382 | ; current [.bandwidth] + new bandwidth <= limit; |
- | |
383 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe |
- | |
384 | mov ecx, [.bandwidth] |
- | |
385 | add ecx, eax |
- | |
386 | cmp ecx, 48000 |
- | |
387 | ja .no_bandwidth |
- | |
388 | ; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
- | |
389 | mov ecx, [.targetsmask] |
- | |
390 | add [edx+ehci_static_ep.Bandwidths+ecx*2], ax |
- | |
391 | add edx, ehci_static_ep.SoftwarePart |
- | |
392 | movi eax, 1 |
- | |
393 | shl eax, cl |
- | |
394 | pop edi ebx ; restore used registers to be stdcall |
- | |
395 | ret |
- | |
396 | .no_bandwidth: |
- | |
397 | dbgstr 'Periodic bandwidth limit reached' |
- | |
398 | xor eax, eax |
- | |
399 | xor edx, edx |
- | |
400 | pop edi ebx |
- | |
401 | ret |
- | |
402 | .every_frame: |
- | |
403 | ; The pipe should be scheduled every frame in two or more microframes. |
- | |
404 | ; 9. Calculate maximal bandwidth for every microframe: three nested loops. |
- | |
405 | ; 9a. The outermost loop: ebx = microframe to calculate. |
- | |
406 | xor ebx, ebx |
- | |
407 | .calc_all_bandwidths: |
- | |
408 | ; 9b. The intermediate loop: |
- | |
409 | ; edx = pointer to ehci_static_ep in the first group, [esp] = counter, |
- | |
410 | ; edi = maximal bandwidth |
- | |
411 | lea edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
- | |
412 | xor edi, edi |
- | |
413 | push 32 |
- | |
414 | .calc_max_bandwidth2: |
- | |
415 | ; 9c. The innermost loop: calculate bandwidth for the given microframe |
- | |
416 | ; in the given frame. |
- | |
417 | xor eax, eax |
- | |
418 | push edx |
- | |
419 | .calc_bandwidth2: |
- | |
420 | add ax, [edx+ehci_static_ep.Bandwidths+ebx*2] |
- | |
421 | mov edx, [edx+ehci_static_ep.NextList] |
- | |
422 | test edx, edx |
- | |
423 | jnz .calc_bandwidth2 |
- | |
424 | pop edx |
- | |
425 | ; 9d. The intermediate loop continued: update maximal bandwidth. |
- | |
426 | cmp eax, edi |
- | |
427 | jb @f |
- | |
428 | mov edi, eax |
- | |
429 | @@: |
- | |
430 | add edx, sizeof.ehci_static_ep |
- | |
431 | dec dword [esp] |
- | |
432 | jnz .calc_max_bandwidth2 |
- | |
433 | pop eax |
- | |
434 | ; 9e. Push the calculated maximal bandwidth and continue the outermost loop. |
- | |
435 | push edi |
- | |
436 | inc ebx |
- | |
437 | cmp ebx, 8 |
- | |
438 | jb .calc_all_bandwidths |
- | |
439 | virtual at esp |
- | |
440 | .bandwidth7 dd ? |
- | |
441 | .bandwidth6 dd ? |
- | |
442 | .bandwidth5 dd ? |
- | |
443 | .bandwidth4 dd ? |
- | |
444 | .bandwidth3 dd ? |
- | |
445 | .bandwidth2 dd ? |
- | |
446 | .bandwidth1 dd ? |
- | |
447 | .bandwidth0 dd ? |
- | |
448 | end virtual |
- | |
449 | ; 10. Select the best variant. |
- | |
450 | ; edx = S-Mask = bitmask of scheduled microframes |
- | |
451 | movi edx, 0x11 |
- | |
452 | cmp ecx, 1 |
- | |
453 | ja @f |
- | |
454 | mov dl, 0x55 |
- | |
455 | jz @f |
- | |
456 | mov dl, 0xFF |
- | |
457 | @@: |
- | |
458 | ; try all variants edx, edx shl 1, edx shl 2, ... |
- | |
459 | ; while they fit in the lower byte (8 microframes per frame) |
- | |
460 | .select_best_mframe: |
- | |
461 | xor edi, edi |
- | |
462 | mov ecx, edx |
- | |
463 | mov eax, esp |
- | |
464 | .calc_mframe: |
- | |
465 | add cl, cl |
- | |
466 | jnc @f |
- | |
467 | cmp edi, [eax] |
- | |
468 | jae @f |
- | |
469 | mov edi, [eax] |
- | |
470 | @@: |
- | |
471 | add eax, 4 |
- | |
472 | test cl, cl |
- | |
473 | jnz .calc_mframe |
- | |
474 | cmp [.bandwidth], edi |
- | |
475 | jb @f |
- | |
476 | mov [.bandwidth], edi |
- | |
477 | mov [.targetsmask], edx |
- | |
478 | @@: |
- | |
479 | add dl, dl |
- | |
480 | jnc .select_best_mframe |
- | |
481 | ; 11. Restore stack after step 9. |
- | |
482 | add esp, 8*4 |
- | |
483 | ; 12. Get the pointer to the target list (responsible for every microframe). |
- | |
484 | lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller] |
- | |
485 | ; 13. Calculate bandwidth on the bus. |
- | |
486 | mov eax, [.maxpacket] |
- | |
487 | call calc_hs_bandwidth |
- | |
488 | mov ecx, [.maxpacket] |
- | |
489 | shr ecx, 11 |
- | |
490 | inc ecx |
- | |
491 | and ecx, 3 |
- | |
492 | imul eax, ecx |
- | |
493 | ; 14. Check that current [.bandwidth] + new bandwidth <= limit; |
- | |
494 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
- | |
495 | mov ecx, [.bandwidth] |
- | |
496 | add ecx, eax |
- | |
497 | cmp ecx, 48000 |
- | |
498 | ja .no_bandwidth |
- | |
499 | ; 15. Update bandwidths including the new pipe. |
- | |
500 | mov ecx, [.targetsmask] |
- | |
501 | lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart] |
- | |
502 | .update_bandwidths: |
- | |
503 | shr ecx, 1 |
- | |
504 | jnc @f |
- | |
505 | add [edi], ax |
- | |
506 | @@: |
- | |
507 | add edi, 2 |
- | |
508 | test ecx, ecx |
- | |
509 | jnz .update_bandwidths |
- | |
510 | ; 16. Return target list and target S-Mask. |
- | |
511 | mov eax, [.targetsmask] |
- | |
512 | pop edi ebx ; restore used registers to be stdcall |
- | |
513 | ret |
- | |
514 | endp |
- | |
515 | - | ||
516 | ; Pipe is removing, update the corresponding lists. |
- | |
517 | ; We do not reorder anything, so just update book-keeping variable |
- | |
518 | ; in the list header. |
- | |
519 | proc ehci_hs_interrupt_list_unlink |
- | |
520 | movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] |
- | |
521 | ; calculate bandwidth |
- | |
522 | call calc_hs_bandwidth |
- | |
523 | mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
- | |
524 | shr ecx, 30 |
- | |
525 | imul eax, ecx |
- | |
526 | movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
- | |
527 | ; get target list |
- | |
528 | mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
- | |
529 | ; update bandwidth |
- | |
530 | .dec_bandwidth: |
- | |
531 | shr ecx, 1 |
- | |
532 | jnc @f |
- | |
533 | sub word [edx+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
- | |
534 | @@: |
- | |
535 | add edx, 2 |
- | |
536 | test ecx, ecx |
- | |
537 | jnz .dec_bandwidth |
- | |
538 | ; return |
- | |
539 | ret |
- | |
540 | endp |
- | |
541 | - | ||
542 | ; Helper procedure for USB2 scheduler: calculate bandwidth on the bus. |
- | |
543 | ; in: low 11 bits of eax = payload size in bytes |
- | |
544 | ; out: eax = maximal bandwidth in HS-bits |
- | |
545 | proc calc_hs_bandwidth |
- | |
546 | and eax, (1 shl 11) - 1 ; get payload for one transaction |
- | |
547 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
- | |
548 | ; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing; |
- | |
549 | ; total 28/3 = 9+1/3 |
- | |
550 | mov edx, 55555556h |
- | |
551 | lea ecx, [eax*9] |
- | |
552 | mul edx |
- | |
553 | ; Add 989 extra bits: 68 bits for Token packet (32 for SYNC, 24 for token+address, |
- | |
554 | ; 4 extra bits for possible bit stuffing in token+address, 8 for EOP), |
- | |
555 | ; 736 bits for bus turn-around, 40 bits for SYNC+EOP in Data packet, |
- | |
556 | ; 8 bits for inter-packet delay, 49 bits for Handshake packet, |
- | |
557 | ; 88 bits for another inter-packet delay. |
- | |
558 | lea eax, [ecx+edx+989] |
- | |
559 | ret |
- | |
560 | endp |
- | |
561 | - | ||
562 | ; Split-transaction scheduler (aka TT scheduler, TT stands for Transaction |
- | |
563 | ; Translator, section 11.14 of the core spec) needs to schedule three event |
- | |
564 | ; types on two buses: Start-Split and Complete-Split on HS bus and normal |
- | |
565 | ; transaction on FS/LS bus. |
- | |
566 | ; Assume that FS/LS bus is more restricted and more important to be scheduled |
- | |
567 | ; uniformly, so select the variant which minimizes maximal used bandwidth |
- | |
568 | ; on FS/LS bus and does not overflow HS bus. |
- | |
569 | ; If there are several such variants, prefer variants which is closest to |
- | |
570 | ; start of frame, and within the same microframe consider HS bandwidth |
- | |
571 | ; utilization as a last criteria. |
- | |
572 | - | ||
573 | ; The procedure ehci_select_tt_interrupt_list has been splitted into several |
- | |
574 | ; macro, each representing a logical step of the procedure, |
- | |
575 | ; to simplify understanding what is going on. Consider all the following macro |
- | |
576 | ; as logical parts of one procedure, they are meaningless outside the context. |
- | |
577 | - | ||
578 | ; Given a frame, calculate bandwidth occupied by already opened pipes |
- | |
579 | ; in every microframe. |
- | |
580 | ; Look for both HS and FS/LS buses: there are 16 words of information, |
- | |
581 | ; 8 for HS bus, 8 for FS/LS bus, for every microframe. |
- | |
582 | ; Since we count already opened pipes, the total bandwidth in every microframe |
- | |
583 | ; is less than 60000 bits (and even 60000*80% bits), otherwise the scheduler |
- | |
584 | ; would not allow to open those pipes. |
- | |
585 | ; edi -> first list for the frame |
- | |
586 | macro tt_calc_bandwidth_in_frame |
- | |
587 | { |
- | |
588 | local .lists, .pipes, .pipes_done, .carry |
- | |
589 | ; 1. Zero everything. |
- | |
590 | xor eax, eax |
- | |
591 | mov edx, edi |
- | |
592 | repeat 4 |
- | |
593 | mov dword [.budget+(%-1)*4], eax |
- | |
594 | end repeat |
- | |
595 | repeat 4 |
- | |
596 | mov dword [.hs_bandwidth+(%-1)*4], eax |
- | |
597 | end repeat |
- | |
598 | mov [.total_budget], ax |
- | |
599 | ; Loop over all lists for the given frame. |
- | |
600 | .lists: |
- | |
601 | ; 2. Total HS bandwidth for all pipes in one list is kept inside list header, |
- | |
602 | ; add it. Note that overflow is impossible, so we may add entire dwords. |
- | |
603 | mov ebx, [edx+ehci_static_ep.SoftwarePart+usb_static_ep.NextVirt] |
- | |
604 | repeat 4 |
- | |
605 | mov eax, dword [edx+ehci_static_ep.Bandwidths+(%-1)*4] |
- | |
606 | add dword [.hs_bandwidth+(%-1)*4], eax |
- | |
607 | end repeat |
- | |
608 | ; Loop over all pipes in the given list. |
- | |
609 | add edx, ehci_static_ep.SoftwarePart |
- | |
610 | .pipes: |
- | |
611 | cmp ebx, edx |
- | |
612 | jz .pipes_done |
- | |
613 | ; 3. For every pipe in every list for the given frame: |
- | |
614 | ; 3a. Check whether the pipe resides on the same FS/LS bus as the new pipe. |
- | |
615 | ; If not, skip this pipe. |
- | |
616 | mov eax, [ebx+usb_pipe.DeviceData] |
- | |
617 | mov eax, [eax+usb_device_data.TTHub] |
- | |
618 | cmp eax, [.tthub] |
- | |
619 | jnz @f |
- | |
620 | ; 3b. Calculate FS/LS budget for the opened pipe. |
- | |
621 | ; Note that eax = TTHub after 3a. |
- | |
622 | call tt_calc_budget |
- | |
623 | ; 3c. Update total budget: add the value from 3b |
- | |
624 | ; to the budget of the first microframe scheduled for this pipe. |
- | |
625 | bsf ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
- | |
626 | add [.budget+ecx*2], ax |
- | |
627 | @@: |
- | |
628 | mov ebx, [ebx+usb_pipe.NextVirt] |
- | |
629 | jmp .pipes |
- | |
630 | .pipes_done: |
- | |
631 | mov edx, [edx+ehci_static_ep.NextList-ehci_static_ep.SoftwarePart] |
- | |
632 | test edx, edx |
- | |
633 | jnz .lists |
- | |
634 | ; 4. If the budget for some microframe is exceeded, carry it to the following |
- | |
635 | ; microframe(s). The actual size of one microframe is 187.5 raw bytes; |
- | |
636 | ; the core spec says that 188 bytes should be scheduled in every microframe. |
- | |
637 | xor eax, eax |
- | |
638 | xor ecx, ecx |
- | |
639 | .carry: |
- | |
640 | xor edx, edx |
- | |
641 | add ax, [.budget+ecx*2] |
- | |
642 | cmp ax, 188 |
- | |
643 | jbe @f |
- | |
644 | mov dx, ax |
- | |
645 | mov ax, 188 |
- | |
646 | sub dx, ax |
- | |
647 | @@: |
- | |
648 | mov [.budget+ecx*2], ax |
- | |
649 | add [.total_budget], ax |
- | |
650 | mov ax, dx |
- | |
651 | inc ecx |
- | |
652 | cmp ecx, 8 |
- | |
653 | jb .carry |
- | |
654 | } |
- | |
655 | - | ||
656 | ; Checks whether the new pipe fits in the existing FS budget |
- | |
657 | ; starting from the given microframe. If not, mark the microframe |
- | |
658 | ; as impossible for scheduling. |
- | |
659 | ; in: ecx = microframe |
- | |
660 | macro tt_exclude_microframe_if_no_budget |
- | |
661 | { |
- | |
662 | local .loop, .good, .bad |
- | |
663 | ; 1. If the new budget plus the current budget does not exceed 188 bytes, |
- | |
664 | ; the variant is possible. |
- | |
665 | mov ax, [.budget+ecx*2] |
- | |
666 | mov edx, ecx |
- | |
667 | add ax, [.new_budget] |
- | |
668 | sub ax, 188 |
- | |
669 | jbe .good |
- | |
670 | ; 2. Otherwise, |
- | |
671 | ; a) nothing should be scheduled in some following microframes, |
- | |
672 | ; b) after adding the new budget everything should fit in first 6 microframes, |
- | |
673 | ; this guarantees that even in the worst case 90% limit is satisfied. |
- | |
674 | .loop: |
- | |
675 | cmp edx, 5 |
- | |
676 | jae .bad |
- | |
677 | cmp [.budget+(edx+1)*2], 0 |
- | |
678 | jnz .bad |
- | |
679 | inc edx |
- | |
680 | sub ax, 188 |
- | |
681 | ja .loop |
- | |
682 | .bad: |
- | |
683 | btr [.possible_microframes], ecx |
- | |
684 | .good: |
- | |
685 | } |
- | |
686 | - | ||
687 | ; Calculate data corresponding to the particular scheduling variant for the new pipe. |
- | |
688 | ; Data describe the current scheduling state collected over all frames touched |
- | |
689 | ; by the given variant: maximal HS bandwidth, maximal FS/LS budget, |
- | |
690 | ; which microframes fit in the current FS/LS budget for all frames. |
- | |
691 | macro tt_calc_statistics_for_one_variant |
- | |
692 | { |
- | |
693 | local .frames, .microframes |
- | |
694 | ; 1. Initialize: zero maximal bandwidth, |
- | |
695 | ; first 6 microframes are possible for scheduling. |
- | |
696 | xor eax, eax |
- | |
697 | repeat 4 |
- | |
698 | mov dword [.max_hs_bandwidth+(%-1)*4], eax |
- | |
699 | end repeat |
- | |
700 | mov [.max_fs_bandwidth], ax |
- | |
701 | mov [.possible_microframes], 0x3F |
- | |
702 | ; Loop over all frames starting with [.variant] advancing by [.variant_delta]. |
- | |
703 | mov edi, [.variant] |
- | |
704 | .frames: |
- | |
705 | ; 2. Calculate statistics for one frame. |
- | |
706 | tt_calc_bandwidth_in_frame |
- | |
707 | ; 3. Update maximal FS budget. |
- | |
708 | mov ax, [.total_budget] |
- | |
709 | cmp ax, [.max_fs_bandwidth] |
- | |
710 | jb @f |
- | |
711 | mov [.max_fs_bandwidth], ax |
- | |
712 | @@: |
- | |
713 | ; 4. For every microframe, update maximal HS bandwidth |
- | |
714 | ; and check whether the microframe is allowed for scheduling. |
- | |
715 | xor ecx, ecx |
- | |
716 | .microframes: |
- | |
717 | mov ax, [.hs_bandwidth+ecx*2] |
- | |
718 | cmp ax, [.max_hs_bandwidth+ecx*2] |
- | |
719 | jb @f |
- | |
720 | mov [.max_hs_bandwidth+ecx*2], ax |
- | |
721 | @@: |
- | |
722 | tt_exclude_microframe_if_no_budget |
- | |
723 | inc ecx |
- | |
724 | cmp ecx, 8 |
- | |
725 | jb .microframes |
- | |
726 | ; Stop loop when outside of first descriptor group. |
- | |
727 | lea eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller] |
- | |
728 | add edi, [.variant_delta] |
- | |
729 | cmp edi, eax |
- | |
730 | jb .frames |
- | |
731 | } |
- | |
732 | - | ||
733 | struct usb_split_info |
- | |
734 | microframe_mask dd ? ; lower byte is S-mask, second byte is C-mask |
- | |
735 | ssplit_bandwidth dd ? |
- | |
736 | csplit_bandwidth dd ? |
- | |
737 | ends |
- | |
738 | - | ||
739 | ; Check whether the current variant and the current microframe are allowed |
- | |
740 | ; for scheduling. If so, check whether they are better than the previously |
- | |
741 | ; selected variant+microframe, if any. If so, update the previously selected |
- | |
742 | ; variant+microframe to current ones. |
- | |
743 | ; ecx = microframe, [.variant] = variant |
- | |
744 | macro tt_check_variant_microframe |
- | |
745 | { |
- | |
746 | local .nothing, .update, .ssplit, .csplit, .csplit_done |
- | |
747 | ; 1. If the current microframe does not fit in existing FS budget, do nothing. |
- | |
748 | bt [.possible_microframes], ecx |
- | |
749 | jnc .nothing |
- | |
750 | ; 2. Calculate maximal HS bandwidth over all affected microframes. |
- | |
751 | ; 2a. Start-split phase: one or more microframes starting with ecx, |
- | |
752 | ; coded in lower byte of .info.microframe_mask. |
- | |
753 | xor ebx, ebx |
- | |
754 | xor edx, edx |
- | |
755 | .ssplit: |
- | |
756 | lea eax, [ecx+edx] |
- | |
757 | movzx eax, [.max_hs_bandwidth+eax*2] |
- | |
758 | add eax, [.info.ssplit_bandwidth] |
- | |
759 | cmp ebx, eax |
- | |
760 | ja @f |
- | |
761 | mov ebx, eax |
- | |
762 | @@: |
- | |
763 | inc edx |
- | |
764 | bt [.info.microframe_mask], edx |
- | |
765 | jc .ssplit |
- | |
766 | ; 2b. Complete-split phase: zero or more microframes starting with |
- | |
767 | ; ecx+(last start-split microframe)+2, |
- | |
768 | ; coded in second byte of .info.microframe_mask. |
- | |
769 | add edx, 8 |
- | |
770 | .csplit: |
- | |
771 | inc edx |
- | |
772 | bt [.info.microframe_mask], edx |
- | |
773 | jnc .csplit_done |
- | |
774 | lea eax, [ecx+edx] |
- | |
775 | cmp eax, 8 |
- | |
776 | jae .csplit_done |
- | |
777 | movzx eax, [.max_hs_bandwidth+(eax-8)*2] |
- | |
778 | add eax, [.info.csplit_bandwidth] |
- | |
779 | cmp ebx, eax |
- | |
780 | ja .csplit |
- | |
781 | mov ebx, eax |
- | |
782 | jmp .csplit |
- | |
783 | .csplit_done: |
- | |
784 | ; 3. Check that current HS bandwidth + new bandwidth <= limit; |
- | |
785 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
- | |
786 | cmp ebx, 48000 |
- | |
787 | ja .nothing |
- | |
788 | ; 4. This variant is possible for scheduling. |
- | |
789 | ; Check whether it is better than the currently selected one. |
- | |
790 | ; 4a. The primary criteria: FS/LS bandwidth. |
- | |
791 | mov ax, [.max_fs_bandwidth] |
- | |
792 | cmp ax, [.best_fs_bandwidth] |
- | |
793 | ja .nothing |
- | |
794 | jb .update |
- | |
795 | ; 4b. The secondary criteria: prefer microframes which are closer to start of frame. |
- | |
796 | cmp ecx, [.targetsmask] |
- | |
797 | ja .nothing |
- | |
798 | jb .update |
- | |
799 | ; 4c. The last criteria: HS bandwidth. |
- | |
800 | cmp ebx, [.bandwidth] |
- | |
801 | ja .nothing |
- | |
802 | .update: |
- | |
803 | ; 5. This variant is better than the previously selected. |
- | |
804 | ; Update the best variant with current data. |
- | |
805 | mov [.best_fs_bandwidth], ax |
- | |
806 | mov [.bandwidth], ebx |
- | |
807 | mov [.targetsmask], ecx |
- | |
808 | mov eax, [.variant] |
- | |
809 | mov [.target], eax |
- | |
810 | .nothing: |
- | |
811 | } |
- | |
812 | - | ||
813 | ; TT scheduler: add new pipe. |
- | |
814 | ; in: esi -> usb_controller, edi -> usb_pipe |
- | |
815 | ; out: edx -> usb_static_ep, eax = S-Mask |
- | |
816 | proc ehci_select_tt_interrupt_list |
- | |
817 | virtual at ebp-12-.local_vars_size |
- | |
818 | .local_vars_start: |
- | |
819 | .info usb_split_info |
- | |
820 | .new_budget dw ? |
- | |
821 | .total_budget dw ? |
- | |
822 | .possible_microframes dd ? |
- | |
823 | .tthub dd ? |
- | |
824 | .budget rw 8 |
- | |
825 | .hs_bandwidth rw 8 |
- | |
826 | .max_hs_bandwidth rw 8 |
- | |
827 | .max_fs_bandwidth dw ? |
- | |
828 | .best_fs_bandwidth dw ? |
- | |
829 | .variant dd ? |
- | |
830 | .variant_delta dd ? |
- | |
831 | .target_delta dd ? |
- | |
832 | .local_vars_size = $ - .local_vars_start |
- | |
833 | - | ||
834 | .targetsmask dd ? |
- | |
835 | .bandwidth dd ? |
- | |
836 | .target dd ? |
- | |
837 | dd ? |
- | |
838 | dd ? |
- | |
839 | .config_pipe dd ? |
- | |
840 | .endpoint dd ? |
- | |
841 | .maxpacket dd ? |
- | |
842 | .type dd ? |
- | |
843 | .interval dd ? |
- | |
844 | end virtual |
- | |
845 | mov eax, [edi+ehci_pipe.Token-sizeof.ehci_pipe] |
- | |
846 | shr eax, 16 |
- | |
847 | and eax, (1 shl 11) - 1 |
- | |
848 | push ebx edi |
- | |
849 | ; 1. Compute the real interval. FS/LS devices encode the interval as |
- | |
850 | ; number of milliseconds. Use the maximal power of two that is not greater than |
- | |
851 | ; the given interval and EHCI scheduling area = 32 frames. |
- | |
852 | cmp [.interval], 1 |
- | |
853 | adc [.interval], 0 |
- | |
854 | mov ecx, 64 |
- | |
855 | mov eax, 64 * sizeof.ehci_static_ep |
- | |
856 | @@: |
- | |
857 | shr ecx, 1 |
- | |
858 | cmp [.interval], ecx |
- | |
859 | jb @b |
- | |
860 | mov [.interval], ecx |
- | |
861 | ; 2. Compute variables for further calculations. |
- | |
862 | ; 2a. [.variant_delta] is delta between two lists from the first group |
- | |
863 | ; that correspond to the same variant. |
- | |
864 | imul ecx, sizeof.ehci_static_ep |
- | |
865 | mov [.variant_delta], ecx |
- | |
866 | ; 2b. [.target_delta] is delta between the final answer from the group |
- | |
867 | ; corresponding to [.interval] and the item from the first group. |
- | |
868 | sub eax, ecx |
- | |
869 | sub eax, ecx |
- | |
870 | mov [.target_delta], eax |
- | |
871 | ; 2c. [.variant] is the first list from the first group that corresponds |
- | |
872 | ; to the current variant. |
- | |
873 | lea eax, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
- | |
874 | mov [.variant], eax |
- | |
875 | ; 2d. [.tthub] identifies TT hub for new pipe, [.new_budget] is FS budget |
- | |
876 | ; for new pipe. |
- | |
877 | mov eax, [edi+usb_pipe.DeviceData] |
- | |
878 | mov eax, [eax+usb_device_data.TTHub] |
- | |
879 | mov ebx, edi |
- | |
880 | mov [.tthub], eax |
- | |
881 | call tt_calc_budget |
- | |
882 | mov [.new_budget], ax |
- | |
883 | ; 2e. [.usb_split_info] describes bandwidth used by new pipe on HS bus. |
- | |
884 | lea edi, [.info] |
- | |
885 | call tt_fill_split_info |
- | |
886 | test eax, eax |
- | |
887 | jz .no_bandwidth |
- | |
888 | ; 2f. There is no best variant yet, put maximal possible values, |
- | |
889 | ; so any variant would be better than the "current". |
- | |
890 | or [.best_fs_bandwidth], -1 |
- | |
891 | or [.target], -1 |
- | |
892 | or [.bandwidth], -1 |
- | |
893 | or [.targetsmask], -1 |
- | |
894 | ; 3. Loop over all variants, for every variant decide whether it is acceptable, |
- | |
895 | ; select the best variant from all acceptable variants. |
- | |
896 | .check_variants: |
- | |
897 | tt_calc_statistics_for_one_variant |
- | |
898 | xor ecx, ecx |
- | |
899 | .check_microframes: |
- | |
900 | tt_check_variant_microframe |
- | |
901 | inc ecx |
- | |
902 | cmp ecx, 6 |
- | |
903 | jb .check_microframes |
- | |
904 | add [.variant], sizeof.ehci_static_ep |
- | |
905 | dec [.interval] |
- | |
906 | jnz .check_variants |
- | |
907 | ; 4. If there is no acceptable variants, return error. |
- | |
908 | mov ecx, [.targetsmask] |
- | |
909 | mov edx, [.target] |
- | |
910 | cmp ecx, -1 |
- | |
911 | jz .no_bandwidth |
- | |
912 | ; 5. Calculate the answer: edx -> selected list, eax = S-Mask and C-Mask. |
- | |
913 | mov eax, [.info.microframe_mask] |
- | |
914 | add edx, [.target_delta] |
- | |
915 | shl eax, cl |
- | |
916 | and eax, 0xFFFF |
- | |
917 | ; 6. Update HS bandwidths in the selected list. |
- | |
918 | xor ecx, ecx |
- | |
919 | mov ebx, [.info.ssplit_bandwidth] |
- | |
920 | .update_ssplit: |
- | |
921 | bt eax, ecx |
- | |
922 | jnc @f |
- | |
923 | add [edx+ehci_static_ep.Bandwidths+ecx*2], bx |
- | |
924 | @@: |
- | |
925 | inc ecx |
- | |
926 | cmp ecx, 8 |
- | |
927 | jb .update_ssplit |
- | |
928 | mov ebx, [.info.csplit_bandwidth] |
- | |
929 | .update_csplit: |
- | |
930 | bt eax, ecx |
- | |
931 | jnc @f |
- | |
932 | add [edx+ehci_static_ep.Bandwidths+(ecx-8)*2], bx |
- | |
933 | @@: |
- | |
934 | inc ecx |
- | |
935 | cmp ecx, 16 |
- | |
936 | jb .update_csplit |
- | |
937 | ; 7. Return. |
- | |
938 | add edx, ehci_static_ep.SoftwarePart |
- | |
939 | pop edi ebx |
- | |
940 | ret |
- | |
941 | .no_bandwidth: |
- | |
942 | dbgstr 'Periodic bandwidth limit reached' |
- | |
943 | xor eax, eax |
- | |
944 | xor edx, edx |
- | |
945 | pop edi ebx |
- | |
946 | ret |
- | |
947 | endp |
- | |
948 | - | ||
949 | ; Pipe is removing, update the corresponding lists. |
- | |
950 | ; We do not reorder anything, so just update book-keeping variable |
- | |
951 | ; in the list header. |
- | |
952 | proc ehci_fs_interrupt_list_unlink |
- | |
953 | ; calculate bandwidth |
- | |
954 | push edi |
- | |
955 | sub esp, sizeof.usb_split_info |
- | |
956 | mov edi, esp |
- | |
957 | call tt_fill_split_info |
- | |
958 | ; get target list |
- | |
959 | mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
- | |
960 | ; update bandwidth for Start-Split |
- | |
961 | mov eax, [edi+usb_split_info.ssplit_bandwidth] |
- | |
962 | xor ecx, ecx |
- | |
963 | .dec_bandwidth_1: |
- | |
964 | bt [ebx+ehci_pipe.Flags-sizeof.ehci_pipe], ecx |
- | |
965 | jnc @f |
- | |
966 | sub word [edx+ecx*2+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
- | |
967 | @@: |
- | |
968 | inc ecx |
- | |
969 | cmp ecx, 8 |
- | |
970 | jb .dec_bandwidth_1 |
- | |
971 | ; update bandwidth for Complete-Split |
- | |
972 | mov eax, [edi+usb_split_info.csplit_bandwidth] |
- | |
973 | .dec_bandwidth_2: |
- | |
974 | bt [ebx+ehci_pipe.Flags-sizeof.ehci_pipe], ecx |
- | |
975 | jnc @f |
- | |
976 | sub word [edx+(ecx-8)*2+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
- | |
977 | @@: |
- | |
978 | inc ecx |
- | |
979 | cmp ecx, 16 |
- | |
980 | jb .dec_bandwidth_2 |
- | |
981 | add esp, sizeof.usb_split_info |
- | |
982 | pop edi |
- | |
983 | ret |
- | |
984 | endp |
- | |
985 | - | ||
986 | ; Helper procedure for ehci_select_tt_interrupt_list. |
- | |
987 | ; Calculates "best-case budget" according to the core spec, |
- | |
988 | ; that is, number of bytes (not bits) corresponding to "optimistic" transaction |
- | |
989 | ; time, including inter-packet delays/bus turn-around time, |
- | |
990 | ; but without bit stuffing and timers drift. |
- | |
991 | ; One extra TT-specific delay is added: TT think time from the hub descriptor. |
- | |
992 | ; Similar to calc_usb1_bandwidth with corresponding changes. |
- | |
993 | ; eax -> usb_hub with TT, ebx -> usb_pipe |
- | |
994 | proc tt_calc_budget |
- | |
995 | movzx ecx, [eax+usb_hub.HubCharacteristics] |
- | |
996 | shr ecx, 5 |
- | |
997 | and ecx, 3 ; 1+ecx = TT think time in FS-bytes |
- | |
998 | mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
- | |
999 | shr eax, 16 |
- | |
1000 | and eax, (1 shl 11) - 1 ; get data length |
- | |
1001 | bt [ebx+ehci_pipe.Token-sizeof.ehci_pipe], 12 |
- | |
1002 | jc .low_speed |
- | |
1003 | ; Full-speed interrupt IN/OUT: |
- | |
1004 | ; 33 bits for Token packet (8 for SYNC, 24 for token+address, 3 for EOP), |
- | |
1005 | ; 18 bits for bus turn-around, 11 bits for SYNC+EOP in Data packet, |
- | |
1006 | ; 2 bits for inter-packet delay, 19 bits for Handshake packet, |
- | |
1007 | ; 2 bits for another inter-packet delay. 85 bits total, pad to 11 bytes. |
- | |
1008 | lea eax, [eax+11+ecx+1] |
- | |
1009 | ; 1 byte is minimal TT think time in addition to ecx. |
- | |
1010 | ret |
- | |
1011 | .low_speed: |
- | |
1012 | ; Low-speed interrupt IN/OUT: |
- | |
1013 | ; multiply by 8 for LS -> FS, |
- | |
1014 | ; add 85 bytes as in full-speed interrupt and extra 5 bytes for two PRE packets |
- | |
1015 | ; and two hub delays. |
- | |
1016 | ; 1 byte is minimal TT think time in addition to ecx. |
- | |
1017 | lea eax, [eax*8+90+ecx+1] |
- | |
1018 | ret |
- | |
1019 | endp |
- | |
1020 | - | ||
1021 | ; Helper procedure for TT scheduler. |
- | |
1022 | ; Calculates Start-Split/Complete-Split masks and HS bandwidths. |
- | |
1023 | ; ebx -> usb_pipe, edi -> usb_split_info |
- | |
1024 | proc tt_fill_split_info |
- | |
1025 | ; Interrupt endpoints. |
- | |
1026 | ; The core spec says in 5.7.3 "Interrupt Transfer Packet Size Constraints" that: |
- | |
1027 | ; The maximum allowable interrupt data payload size is 64 bytes or less for full-speed. |
- | |
1028 | ; Low-speed devices are limited to eight bytes or less maximum data payload size. |
- | |
1029 | ; This is important for scheduling, it guarantees that in any case transaction fits |
- | |
1030 | ; in two microframes (usually one, two if transaction has started too late in the first |
- | |
1031 | ; microframe), so check it. |
- | |
1032 | mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
- | |
1033 | mov ecx, 8 |
- | |
1034 | bt eax, 12 |
- | |
1035 | jc @f |
- | |
1036 | mov ecx, 64 |
- | |
1037 | @@: |
- | |
1038 | shr eax, 16 |
- | |
1039 | and eax, (1 shl 11) - 1 ; get data length |
- | |
1040 | cmp eax, ecx |
- | |
1041 | ja .error |
- | |
1042 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
- | |
1043 | ; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing; |
- | |
1044 | ; total 28/3 = 9+1/3 |
- | |
1045 | mov edx, 55555556h |
- | |
1046 | lea ecx, [eax*9] |
- | |
1047 | mul edx |
- | |
1048 | ; One start-split, three complete-splits (unless the last is too far, |
- | |
1049 | ; but this is handled by the caller). |
- | |
1050 | mov eax, [ebx+usb_pipe.LastTD] |
- | |
1051 | mov [edi+usb_split_info.microframe_mask], 0x1C01 |
- | |
1052 | ; Structure and HS bandwidth of packets depends on the direction. |
- | |
1053 | bt [eax+ehci_gtd.Token-sizeof.ehci_gtd], 8 |
- | |
1054 | jc .interrupt_in |
- | |
1055 | .interrupt_out: |
- | |
1056 | ; Start-Split phase: |
- | |
1057 | ; 77 bits for SPLIT packet (32 for SYNC, 8 for EOP, 32 for data, 5 for bit stuffing), |
- | |
1058 | ; 88 bits for inter-packet delay, 68 bits for Token packet, |
- | |
1059 | ; 88 bits for inter-packet delay, 40 bits for SYNC+EOP in Data packet, |
- | |
1060 | ; 88 bits for last inter-packet delay, total 449 bits. |
- | |
1061 | lea eax, [edx+ecx+449] |
- | |
1062 | mov [edi+usb_split_info.ssplit_bandwidth], eax |
- | |
1063 | ; Complete-Split phase: |
- | |
1064 | ; 77 bits for SPLIT packet, |
- | |
1065 | ; 88 bits for inter-packet delay, 68 bits for Token packet, |
- | |
1066 | ; 736 bits for bus turn-around, 49 bits for Handshake packet, |
- | |
1067 | ; 8 bits for inter-packet delay, total 1026 bits. |
- | |
1068 | mov [edi+usb_split_info.csplit_bandwidth], 1026 |
- | |
1069 | ret |
- | |
1070 | .interrupt_in: |
- | |
1071 | ; Start-Split phase: |
- | |
1072 | ; 77 bits for SPLIT packet, 88 bits for inter-packet delay, |
- | |
1073 | ; 68 bits for Token packet, 88 bits for another inter-packet delay, |
- | |
1074 | ; total 321 bits. |
- | |
1075 | mov [edi+usb_split_info.ssplit_bandwidth], 321 |
- | |
1076 | ; Complete-Split phase: |
- | |
1077 | ; 77 bits for SPLIT packet, 88 bits for inter-packet delay, |
- | |
1078 | ; 68 bits for Token packet, 736 bits for bus turn-around, |
- | |
1079 | ; 40 bits for SYNC+EOP in Data packet, 8 bits for inter-packet delay, |
- | |
1080 | ; total 1017 bits. |
- | |
1081 | lea eax, [edx+ecx+1017] |
- | |
1082 | mov [edi+usb_split_info.csplit_bandwidth], eax |
- | |
1083 | ret |
- | |
1084 | .error: |
- | |
1085 | xor eax, eax |
- | |
1086 | ret |
- | |
1087 | endp=>=>=>>=>>=> |
- |