Rev 3725 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3725 | Rev 3908 | ||
---|---|---|---|
Line 18... | Line 18... | ||
18 | ; in: edx -> {u|o}hci_static_ep for the first list |
18 | ; in: edx -> {u|o}hci_static_ep for the first list |
19 | ; in: eax -> byte past {u|o}hci_static_ep for the last list in the first group |
19 | ; in: eax -> byte past {u|o}hci_static_ep for the last list in the first group |
20 | ; out: edx -> usb_static_ep for the selected list or zero if failed |
20 | ; out: edx -> usb_static_ep for the selected list or zero if failed |
21 | proc usb1_select_interrupt_list |
21 | proc usb1_select_interrupt_list |
22 | ; inherit some variables from usb_open_pipe |
22 | ; inherit some variables from usb_open_pipe |
23 | virtual at ebp-8 |
23 | virtual at ebp-12 |
- | 24 | .speed db ? |
|
- | 25 | rb 3 |
|
24 | .bandwidth dd ? |
26 | .bandwidth dd ? |
25 | .target dd ? |
27 | .target dd ? |
26 | dd ? |
28 | dd ? |
27 | dd ? |
29 | dd ? |
28 | .config_pipe dd ? |
30 | .config_pipe dd ? |
Line 114... | Line 116... | ||
114 | @@: |
116 | @@: |
115 | ; 3g. The outermost loop continued: advance counter. |
117 | ; 3g. The outermost loop continued: advance counter. |
116 | add edx, sizeof.ohci_static_ep |
118 | add edx, sizeof.ohci_static_ep |
117 | dec ecx |
119 | dec ecx |
118 | jnz .varloop |
120 | jnz .varloop |
- | 121 | ; 4. Calculate bandwidth for the new pipe. |
|
- | 122 | mov eax, [.maxpacket] |
|
- | 123 | mov cl, [.speed] |
|
- | 124 | mov ch, byte [.endpoint] |
|
- | 125 | and ch, 80h |
|
- | 126 | call calc_usb1_bandwidth |
|
119 | ; 4. Get the pointer to the best list. |
127 | ; 5. Get the pointer to the best list. |
120 | pop edx ; restore value from step 2 |
128 | pop edx ; restore value from step 2 |
121 | pop eax ; purge stack var from prolog |
129 | pop ecx ; purge stack var from prolog |
122 | add edx, [.target] |
130 | add edx, [.target] |
123 | ; 5. Calculate bandwidth for the new pipe. |
131 | ; 6. Check that bandwidth for the new pipe plus old bandwidth |
124 | mov eax, [.maxpacket] ; TODO: calculate real bandwidth |
132 | ; still fits to maximum allowed by the core specification, 90% of 12000 bits. |
125 | and eax, (1 shl 11) - 1 |
133 | mov ecx, eax |
126 | ; 6. TODO: check that bandwidth for the new pipe plus old bandwidth |
134 | add ecx, [.bandwidth] |
- | 135 | cmp ecx, 10800 |
|
127 | ; still fits to maximum allowed by the core specification. |
136 | ja .no_bandwidth |
128 | ; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
137 | ; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
129 | add edx, ohci_static_ep.SoftwarePart |
138 | add edx, ohci_static_ep.SoftwarePart |
130 | add [edx+usb_static_ep.Bandwidth], eax |
139 | add [edx+usb_static_ep.Bandwidth], eax |
131 | pop edi ebx ; restore used registers to be stdcall |
140 | pop edi ebx ; restore used registers to be stdcall |
132 | ret |
141 | ret |
- | 142 | .no_bandwidth: |
|
- | 143 | dbgstr 'Periodic bandwidth limit reached' |
|
- | 144 | xor edx, edx |
|
- | 145 | pop edi ebx |
|
- | 146 | ret |
|
133 | endp |
147 | endp |
134 | ; sanity check, part 2 |
148 | ; sanity check, part 2 |
135 | else |
149 | else |
136 | .err select_interrupt_list must be different for UHCI and OHCI |
150 | .err select_interrupt_list must be different for UHCI and OHCI |
137 | end if |
151 | end if |
Line 145... | Line 159... | ||
145 | .maxpacket dd ? |
159 | .maxpacket dd ? |
146 | .lowspeed db ? |
160 | .lowspeed db ? |
147 | .direction db ? |
161 | .direction db ? |
148 | rb 2 |
162 | rb 2 |
149 | end virtual |
163 | end virtual |
- | 164 | ; calculate bandwidth on the bus |
|
- | 165 | mov eax, [.maxpacket] |
|
- | 166 | mov ecx, dword [.lowspeed] |
|
- | 167 | call calc_usb1_bandwidth |
|
150 | ; find list header |
168 | ; find list header |
151 | mov edx, ebx |
169 | mov edx, ebx |
152 | @@: |
170 | @@: |
153 | mov edx, [edx+usb_pipe.NextVirt] |
171 | mov edx, [edx+usb_pipe.NextVirt] |
154 | cmp [edx+usb_pipe.Controller], esi |
172 | cmp [edx+usb_pipe.Controller], esi |
155 | jnz @b |
173 | jz @b |
156 | ; subtract pipe bandwidth |
174 | ; subtract pipe bandwidth |
157 | ; TODO: calculate real bandwidth |
- | |
158 | mov eax, [.maxpacket] |
- | |
159 | and eax, (1 shl 11) - 1 |
- | |
160 | sub [edx+usb_static_ep.Bandwidth], eax |
175 | sub [edx+usb_static_ep.Bandwidth], eax |
161 | ret 8 |
176 | ret 8 |
162 | endp |
177 | endp |
Line -... | Line 178... | ||
- | 178 | ||
- | 179 | ; Helper procedure for USB1 scheduler: calculate bandwidth on the bus. |
|
- | 180 | ; in: low 11 bits of eax = payload size in bytes |
|
- | 181 | ; in: cl = 0 - full-speed, nonzero - high-speed |
|
- | 182 | ; in: ch = 0 - OUT, nonzero - IN |
|
- | 183 | ; out: eax = maximal bandwidth in FS-bits |
|
- | 184 | proc calc_usb1_bandwidth |
|
- | 185 | and eax, (1 shl 11) - 1 ; get payload for one transaction |
|
- | 186 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
|
- | 187 | test cl, cl |
|
- | 188 | jnz .low_speed |
|
- | 189 | ; Multiply by 8 for bytes -> bits, by 7/6 to accomodate bit stuffing |
|
- | 190 | ; and by 401/400 for IN transfers to accomodate timers difference |
|
- | 191 | ; 9+107/300 for IN transfers, 9+1/3 for OUT transfers |
|
- | 192 | ; For 0 <= eax < 09249355h, floor(eax * 107/300) = floor(eax * 5B4E81B5h / 2^32). |
|
- | 193 | ; For 0 <= eax < 80000000h, floor(eax / 3) = floor(eax * 55555556h / 2^32). |
|
- | 194 | mov edx, 55555556h |
|
- | 195 | test ch, ch |
|
- | 196 | jz @f |
|
- | 197 | mov edx, 5B4E81B5h |
|
- | 198 | @@: |
|
- | 199 | lea ecx, [eax*9] |
|
- | 200 | mul edx |
|
- | 201 | ; Add 93 extra bits: 39 bits for Token packet (8 for SYNC, 24 for token+address, |
|
- | 202 | ; 4 extra bits for possible bit stuffing in token+address, 3 for EOP), |
|
- | 203 | ; 18 bits for bus turn-around, 11 bits for SYNC+EOP in Data packet plus 1 bit |
|
- | 204 | ; for possible timers difference, 2 bits for inter-packet delay, 20 bits for |
|
- | 205 | ; Handshake packet, 2 bits for another inter-packet delay. |
|
- | 206 | lea eax, [ecx+edx+93] |
|
- | 207 | ret |
|
- | 208 | .low_speed: |
|
- | 209 | ; Multiply by 8 for bytes -> bits, by 7/6 to accomodate bit stuffing, |
|
- | 210 | ; by 8 for LS -> FS and by 406/50 for IN transfers to accomodate timers difference. |
|
- | 211 | ; 75+59/75 for IN transfers, 74+2/3 for OUT transfers. |
|
- | 212 | mov edx, 0AAAAAABh |
|
- | 213 | test ch, ch |
|
- | 214 | mov ecx, 74 |
|
- | 215 | jz @f |
|
- | 216 | mov edx, 0C962FC97h |
|
- | 217 | inc ecx |
|
- | 218 | @@: |
|
- | 219 | imul ecx, eax |
|
- | 220 | mul edx |
|
- | 221 | ; Add 778 extra bits: |
|
- | 222 | ; 16 bits for PRE packet, 4 bits for hub delay, 8*39 bits for Token packet |
|
- | 223 | ; 8*18 bits for bus turn-around |
|
- | 224 | ; (406/50)*11 bits for SYNC+EOP in Data packet, |
|
- | 225 | ; 8*2 bits for inter-packet delay, |
|
- | 226 | ; 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. |
|
- | 228 | lea eax, [ecx+edx+778] |
|
- | 229 | ret |
|
- | 230 | endp |
|
163 | 231 | ||
164 | ; USB2 scheduler. |
232 | ; USB2 scheduler. |
165 | ; There are two parts: high-speed pipes and split-transaction pipes. |
- | |
- | 233 | ; There are two parts: high-speed pipes and split-transaction pipes. |
|
166 | ; Split-transaction scheduler is currently a stub. |
234 | ; |
167 | ; High-speed scheduler uses the same algorithm as USB1 scheduler: |
235 | ; High-speed scheduler uses the same algorithm as USB1 scheduler: |
168 | ; when adding a pipe, optimize the following quantity: |
236 | ; when adding a pipe, optimize the following quantity: |
169 | ; * for every microframe, take all bandwidth scheduled to periodic transfers, |
237 | ; * for every microframe, take all bandwidth scheduled to periodic transfers, |
170 | ; * calculate maximum over all microframe, |
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 |
|
171 | ; * select a variant which minimizes that maximum; |
242 | ; to minimize collisions with split transactions; |
172 | ; when removing a pipe, do nothing (except for bookkeeping). |
243 | ; when removing a pipe, do nothing (except for bookkeeping). |
173 | ; in: esi -> usb_controller |
244 | ; in: esi -> usb_controller |
174 | ; out: edx -> usb_static_ep, eax = S-Mask |
245 | ; out: edx -> usb_static_ep, eax = S-Mask |
175 | proc ehci_select_hs_interrupt_list |
246 | proc ehci_select_hs_interrupt_list |
Line 275... | Line 346... | ||
275 | pop edx |
346 | pop edx |
276 | ; 4j. Loop #2: if the current variant is better (maybe not strictly) |
347 | ; 4j. Loop #2: if the current variant is better (maybe not strictly) |
277 | ; then the previous optimum, update the optimal bandwidth and the target. |
348 | ; then the previous optimum, update the optimal bandwidth and the target. |
278 | cmp edi, [.bandwidth] |
349 | cmp edi, [.bandwidth] |
279 | ja @f |
350 | ja @f |
- | 351 | jb .update |
|
- | 352 | cmp ecx, [.targetsmask] |
|
- | 353 | jb @f |
|
- | 354 | .update: |
|
280 | mov [.bandwidth], edi |
355 | mov [.bandwidth], edi |
281 | mov [.target], edx |
356 | mov [.target], edx |
282 | movi eax, 1 |
- | |
283 | shl eax, cl |
- | |
284 | mov [.targetsmask], eax |
357 | mov [.targetsmask], ecx |
285 | @@: |
358 | @@: |
286 | ; 4k. Loop #2: continue 8 times for every microframe. |
359 | ; 4k. Loop #2: continue 8 times for every microframe. |
287 | inc ecx |
360 | inc ecx |
288 | cmp ecx, 8 |
361 | cmp ecx, 8 |
289 | jb .varloop |
362 | jb .varloop |
290 | ; 4l. Loop #1: advance counter and repeat ebx times, |
363 | ; 4l. Loop #1: advance counter and repeat ebx times, |
291 | ; ebx was calculated in step 3. |
364 | ; ebx was calculated in step 3. |
292 | add edx, sizeof.ehci_static_ep |
365 | add edx, sizeof.ehci_static_ep |
293 | dec ebx |
366 | dec ebx |
294 | jnz .varloop0 |
367 | jnz .varloop0 |
295 | ; 5. Get the pointer to the best list. |
- | |
296 | pop edx ; restore value from step 3 |
- | |
297 | pop edx ; get delta calculated in step 3 |
- | |
298 | add edx, [.target] |
- | |
299 | ; 6. Calculate bandwidth for the new pipe. |
368 | ; 5. Calculate bandwidth for the new pipe. |
300 | ; TODO1: calculate real bandwidth |
- | |
301 | mov eax, [.maxpacket] |
369 | mov eax, [.maxpacket] |
302 | mov ecx, eax |
370 | call calc_hs_bandwidth |
303 | and eax, (1 shl 11) - 1 |
371 | mov ecx, [.maxpacket] |
304 | shr ecx, 11 |
372 | shr ecx, 11 |
305 | inc ecx |
373 | inc ecx |
306 | and ecx, 3 |
374 | and ecx, 3 |
307 | imul eax, ecx |
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] |
|
308 | ; 7. TODO2: check that bandwidth for the new pipe plus old bandwidth |
380 | ; 7. Check that bandwidth for the new pipe plus old bandwidth |
309 | ; still fits to maximum allowed by the core specification |
381 | ; still fits to maximum allowed by the core specification |
310 | ; current [.bandwidth] + new bandwidth <= limit; |
382 | ; current [.bandwidth] + new bandwidth <= limit; |
311 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe |
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 |
|
312 | ; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
388 | ; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
313 | mov ecx, [.targetsmask] |
389 | mov ecx, [.targetsmask] |
314 | add [edx+ehci_static_ep.Bandwidths+ecx*2], ax |
390 | add [edx+ehci_static_ep.Bandwidths+ecx*2], ax |
315 | add edx, ehci_static_ep.SoftwarePart |
391 | add edx, ehci_static_ep.SoftwarePart |
316 | movi eax, 1 |
392 | movi eax, 1 |
317 | shl eax, cl |
393 | shl eax, cl |
318 | pop edi ebx ; restore used registers to be stdcall |
394 | pop edi ebx ; restore used registers to be stdcall |
319 | ret |
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 |
|
320 | .every_frame: |
402 | .every_frame: |
321 | ; The pipe should be scheduled every frame in two or more microframes. |
403 | ; The pipe should be scheduled every frame in two or more microframes. |
322 | ; 9. Calculate maximal bandwidth for every microframe: three nested loops. |
404 | ; 9. Calculate maximal bandwidth for every microframe: three nested loops. |
323 | ; 9a. The outermost loop: ebx = microframe to calculate. |
405 | ; 9a. The outermost loop: ebx = microframe to calculate. |
324 | xor ebx, ebx |
406 | xor ebx, ebx |
Line 372... | Line 454... | ||
372 | mov dl, 0x55 |
454 | mov dl, 0x55 |
373 | jz @f |
455 | jz @f |
374 | mov dl, 0xFF |
456 | mov dl, 0xFF |
375 | @@: |
457 | @@: |
376 | ; try all variants edx, edx shl 1, edx shl 2, ... |
458 | ; try all variants edx, edx shl 1, edx shl 2, ... |
377 | ; until they fit in the lower byte (8 microframes per frame) |
459 | ; while they fit in the lower byte (8 microframes per frame) |
378 | .select_best_mframe: |
460 | .select_best_mframe: |
379 | xor edi, edi |
461 | xor edi, edi |
380 | mov ecx, edx |
462 | mov ecx, edx |
381 | mov eax, esp |
463 | mov eax, esp |
382 | .calc_mframe: |
464 | .calc_mframe: |
Line 398... | Line 480... | ||
398 | jnc .select_best_mframe |
480 | jnc .select_best_mframe |
399 | ; 11. Restore stack after step 9. |
481 | ; 11. Restore stack after step 9. |
400 | add esp, 8*4 |
482 | add esp, 8*4 |
401 | ; 12. Get the pointer to the target list (responsible for every microframe). |
483 | ; 12. Get the pointer to the target list (responsible for every microframe). |
402 | lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller] |
484 | lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller] |
403 | ; 13. TODO1: calculate real bandwidth. |
485 | ; 13. Calculate bandwidth on the bus. |
404 | mov eax, [.maxpacket] |
486 | mov eax, [.maxpacket] |
405 | mov ecx, eax |
487 | call calc_hs_bandwidth |
406 | and eax, (1 shl 11) - 1 |
488 | mov ecx, [.maxpacket] |
407 | shr ecx, 11 |
489 | shr ecx, 11 |
408 | inc ecx |
490 | inc ecx |
409 | and ecx, 3 |
491 | and ecx, 3 |
410 | imul eax, ecx |
492 | imul eax, ecx |
411 | ; 14. TODO2: check that current [.bandwidth] + new bandwidth <= limit; |
493 | ; 14. Check that current [.bandwidth] + new bandwidth <= limit; |
412 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
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 |
|
413 | ; Update bandwidths including the new pipe. |
499 | ; 15. Update bandwidths including the new pipe. |
414 | mov ecx, [.targetsmask] |
500 | mov ecx, [.targetsmask] |
415 | lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart] |
501 | lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart] |
416 | .update_bandwidths: |
502 | .update_bandwidths: |
417 | shr ecx, 1 |
503 | shr ecx, 1 |
418 | jnc @f |
504 | jnc @f |
419 | add [edi], ax |
505 | add [edi], ax |
420 | @@: |
506 | @@: |
421 | add edi, 2 |
507 | add edi, 2 |
422 | test ecx, ecx |
508 | test ecx, ecx |
423 | jnz .update_bandwidths |
509 | jnz .update_bandwidths |
424 | ; 15. Return target list and target S-Mask. |
510 | ; 16. Return target list and target S-Mask. |
425 | mov eax, [.targetsmask] |
511 | mov eax, [.targetsmask] |
426 | pop edi ebx ; restore used registers to be stdcall |
512 | pop edi ebx ; restore used registers to be stdcall |
427 | ret |
513 | ret |
428 | endp |
514 | endp |
Line 429... | Line 515... | ||
429 | 515 | ||
430 | ; Pipe is removing, update the corresponding lists. |
516 | ; Pipe is removing, update the corresponding lists. |
431 | ; We do not reorder anything, so just update book-keeping variable |
517 | ; We do not reorder anything, so just update book-keeping variable |
432 | ; in the list header. |
518 | ; in the list header. |
433 | proc ehci_hs_interrupt_list_unlink |
- | |
434 | ; get target list |
- | |
435 | mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
- | |
436 | ; TODO: calculate real bandwidth |
519 | proc ehci_hs_interrupt_list_unlink |
- | 520 | movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] |
|
- | 521 | ; calculate bandwidth |
|
437 | movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] |
522 | call calc_hs_bandwidth |
438 | mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
- | |
439 | and eax, (1 shl 11) - 1 |
523 | mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
440 | shr ecx, 30 |
524 | shr ecx, 30 |
441 | imul eax, ecx |
525 | imul eax, ecx |
- | 526 | movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
|
442 | movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
527 | ; get target list |
443 | add edx, ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart |
528 | mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
444 | ; update bandwidth |
529 | ; update bandwidth |
445 | .dec_bandwidth: |
530 | .dec_bandwidth: |
446 | shr ecx, 1 |
531 | shr ecx, 1 |
447 | jnc @f |
532 | jnc @f |
448 | sub [edx], ax |
533 | sub word [edx+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
449 | @@: |
534 | @@: |
450 | add edx, 2 |
535 | add edx, 2 |
451 | test ecx, ecx |
536 | test ecx, ecx |
452 | jnz .dec_bandwidth |
537 | jnz .dec_bandwidth |
453 | ; return |
538 | ; return |
454 | ret |
539 | ret |
Line -... | Line 540... | ||
- | 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 |
|
455 | endp |
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 |
|
456 | 734 | microframe_mask dd ? ; lower byte is S-mask, second byte is C-mask |
|
457 | uglobal |
735 | ssplit_bandwidth dd ? |
458 | ehci_last_fs_alloc dd ? |
736 | csplit_bandwidth dd ? |
- | 737 | ends |
|
- | 738 | ||
- | 739 | ; Check whether the current variant and the current microframe are allowed |
|
459 | endg |
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 |
|
460 | 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 |
|
461 | ; This needs to be rewritten. Seriously. |
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 |
|
462 | ; It schedules everything to the first microframe of some frame, |
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] |
|
463 | ; frame is spinned out of thin air. |
793 | ja .nothing |
- | 794 | jb .update |
|
- | 795 | ; 4b. The secondary criteria: prefer microframes which are closer to start of frame. |
|
464 | ; This works while you have one keyboard and one mouse... |
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. |
|
465 | ; maybe even ten keyboards and ten mice... but give any serious stress, |
814 | ; in: esi -> usb_controller, edi -> usb_pipe |
466 | ; and this would break. |
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 ? |
|
467 | proc ehci_select_fs_interrupt_list |
832 | .local_vars_size = $ - .local_vars_start |
468 | virtual at ebp-12 |
833 | |
469 | .targetsmask dd ? |
834 | .targetsmask dd ? |
470 | .bandwidth dd ? |
835 | .bandwidth dd ? |
471 | .target dd ? |
836 | .target dd ? |
Line 475... | Line 840... | ||
475 | .endpoint dd ? |
840 | .endpoint dd ? |
476 | .maxpacket dd ? |
841 | .maxpacket dd ? |
477 | .type dd ? |
842 | .type dd ? |
478 | .interval dd ? |
843 | .interval dd ? |
479 | end virtual |
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. |
|
480 | cmp [.interval], 1 |
852 | cmp [.interval], 1 |
481 | adc [.interval], 0 |
853 | adc [.interval], 0 |
482 | mov ecx, 64 |
854 | mov ecx, 64 |
483 | mov eax, ecx |
855 | mov eax, 64 * sizeof.ehci_static_ep |
484 | @@: |
856 | @@: |
485 | shr ecx, 1 |
857 | shr ecx, 1 |
486 | cmp [.interval], ecx |
858 | cmp [.interval], ecx |
487 | jb @b |
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. |
|
488 | sub eax, ecx |
868 | sub eax, ecx |
489 | 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 |
|
490 | dec ecx |
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. |
|
491 | and ecx, [ehci_last_fs_alloc] |
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] |
|
492 | inc [ehci_last_fs_alloc] |
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: |
|
493 | add eax, ecx |
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 |
|
494 | imul eax, sizeof.ehci_static_ep |
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. |
|
495 | lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+eax-sizeof.ehci_controller] |
938 | add edx, ehci_static_ep.SoftwarePart |
- | 939 | pop edi ebx |
|
- | 940 | ret |
|
- | 941 | .no_bandwidth: |
|
- | 942 | dbgstr 'Periodic bandwidth limit reached' |
|
496 | mov ax, 1C01h |
943 | xor eax, eax |
- | 944 | xor edx, edx |
|
- | 945 | pop edi ebx |
|
497 | ret |
946 | ret |
498 | endp |
947 | endp |
Line -... | Line 948... | ||
- | 948 | ||
- | 949 | ; Pipe is removing, update the corresponding lists. |
|
- | 950 | ; We do not reorder anything, so just update book-keeping variable |
|
499 | 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: |
|
500 | proc ehci_fs_interrupt_list_unlink |
1085 | xor eax, eax |
501 | ret |
1086 | ret |