calculate USB bandwidth

git-svn-id: svn://kolibrios.org@3816 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
CleverMouse 2013-07-12 10:56:43 +00:00
parent 6d879d326e
commit b9648e30e6
3 changed files with 145 additions and 30 deletions

View File

@ -924,7 +924,12 @@ endp
; esi -> usb_controller, eax -> usb_gtd for the first TD, ; esi -> usb_controller, eax -> usb_gtd for the first TD,
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type ; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
proc ohci_init_pipe proc ohci_init_pipe
virtual at ebp+8 virtual at ebp-12
.speed db ?
rb 3
.bandwidth dd ?
.target dd ?
rd 2
.config_pipe dd ? .config_pipe dd ?
.endpoint dd ? .endpoint dd ?
.maxpacket dd ? .maxpacket dd ?
@ -944,6 +949,8 @@ end virtual
shl edx, 7 shl edx, 7
or eax, edx or eax, edx
mov [edi+ohci_pipe.Flags-sizeof.ohci_pipe], eax mov [edi+ohci_pipe.Flags-sizeof.ohci_pipe], eax
bt eax, 13
setc [.speed]
mov eax, [.maxpacket] mov eax, [.maxpacket]
mov word [edi+ohci_pipe.Flags+2-sizeof.ohci_pipe], ax mov word [edi+ohci_pipe.Flags+2-sizeof.ohci_pipe], ax
cmp [.type], CONTROL_PIPE cmp [.type], CONTROL_PIPE

View File

@ -20,7 +20,9 @@ if (sizeof.ohci_static_ep=sizeof.uhci_static_ep)&(ohci_static_ep.SoftwarePart=uh
; out: edx -> usb_static_ep for the selected list or zero if failed ; out: edx -> usb_static_ep for the selected list or zero if failed
proc usb1_select_interrupt_list proc usb1_select_interrupt_list
; inherit some variables from usb_open_pipe ; inherit some variables from usb_open_pipe
virtual at ebp-8 virtual at ebp-12
.speed db ?
rb 3
.bandwidth dd ? .bandwidth dd ?
.target dd ? .target dd ?
dd ? dd ?
@ -116,20 +118,32 @@ end virtual
add edx, sizeof.ohci_static_ep add edx, sizeof.ohci_static_ep
dec ecx dec ecx
jnz .varloop jnz .varloop
; 4. Get the pointer to the best list. ; 4. Calculate bandwidth for the new pipe.
mov eax, [.maxpacket]
mov cl, [.speed]
mov ch, byte [.endpoint]
and ch, 80h
call calc_usb1_bandwidth
; 5. Get the pointer to the best list.
pop edx ; restore value from step 2 pop edx ; restore value from step 2
pop eax ; purge stack var from prolog pop ecx ; purge stack var from prolog
add edx, [.target] add edx, [.target]
; 5. Calculate bandwidth for the new pipe. ; 6. Check that bandwidth for the new pipe plus old bandwidth
mov eax, [.maxpacket] ; TODO: calculate real bandwidth ; still fits to maximum allowed by the core specification, 90% of 12000 bits.
and eax, (1 shl 11) - 1 mov ecx, eax
; 6. TODO: check that bandwidth for the new pipe plus old bandwidth add ecx, [.bandwidth]
; still fits to maximum allowed by the core specification. cmp ecx, 10800
ja .no_bandwidth
; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. ; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return.
add edx, ohci_static_ep.SoftwarePart add edx, ohci_static_ep.SoftwarePart
add [edx+usb_static_ep.Bandwidth], eax add [edx+usb_static_ep.Bandwidth], eax
pop edi ebx ; restore used registers to be stdcall pop edi ebx ; restore used registers to be stdcall
ret ret
.no_bandwidth:
dbgstr 'Periodic bandwidth limit reached'
xor edx, edx
pop edi ebx
ret
endp endp
; sanity check, part 2 ; sanity check, part 2
else else
@ -147,6 +161,10 @@ virtual at esp
.direction db ? .direction db ?
rb 2 rb 2
end virtual end virtual
; calculate bandwidth on the bus
mov eax, [.maxpacket]
mov ecx, dword [.lowspeed]
call calc_usb1_bandwidth
; find list header ; find list header
mov edx, ebx mov edx, ebx
@@: @@:
@ -154,13 +172,63 @@ end virtual
cmp [edx+usb_pipe.Controller], esi cmp [edx+usb_pipe.Controller], esi
jz @b jz @b
; subtract pipe bandwidth ; subtract pipe bandwidth
; TODO: calculate real bandwidth
mov eax, [.maxpacket]
and eax, (1 shl 11) - 1
sub [edx+usb_static_ep.Bandwidth], eax sub [edx+usb_static_ep.Bandwidth], eax
ret 8 ret 8
endp endp
; Helper procedure for USB1 scheduler: calculate bandwidth on the bus.
; in: low 11 bits of eax = payload size in bytes
; in: cl = 0 - full-speed, nonzero - high-speed
; in: ch = 0 - OUT, nonzero - IN
; out: eax = maximal bandwidth in FS-bits
proc calc_usb1_bandwidth
and eax, (1 shl 11) - 1 ; get payload for one transaction
add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16
test cl, cl
jnz .low_speed
; Multiply by 8 for bytes -> bits, by 7/6 to accomodate bit stuffing
; and by 401/400 for IN transfers to accomodate timers difference
; 9+107/300 for IN transfers, 9+1/3 for OUT transfers
; For 0 <= eax < 09249355h, floor(eax * 107/300) = floor(eax * 5B4E81B5h / 2^32).
; For 0 <= eax < 80000000h, floor(eax / 3) = floor(eax * 55555556h / 2^32).
mov edx, 55555556h
test ch, ch
jz @f
mov edx, 5B4E81B5h
@@:
lea ecx, [eax*9]
mul edx
; Add 93 extra bits: 39 bits for Token packet (8 for SYNC, 24 for token+address,
; 4 extra bits for possible bit stuffing in token+address, 3 for EOP),
; 18 bits for bus turn-around, 11 bits for SYNC+EOP in Data packet plus 1 bit
; for possible timers difference, 2 bits for inter-packet delay, 20 bits for
; Handshake packet, 2 bits for another inter-packet delay.
lea eax, [ecx+edx+93]
ret
.low_speed:
; Multiply by 8 for bytes -> bits, by 7/6 to accomodate bit stuffing,
; by 8 for LS -> FS and by 406/50 for IN transfers to accomodate timers difference.
; 75+59/75 for IN transfers, 74+2/3 for OUT transfers.
mov edx, 0AAAAAABh
test ch, ch
mov ecx, 74
jz @f
mov edx, 0C962FC97h
inc ecx
@@:
imul ecx, eax
mul edx
; Add 778 extra bits:
; 16 bits for PRE packet, 4 bits for hub delay, 8*39 bits for Token packet
; 8*18 bits for bus turn-around
; (406/50)*11 bits for SYNC+EOP in Data packet,
; 8*2 bits for inter-packet delay,
; 16 bits for PRE packet, 4 bits for hub delay, 8*20 bits for Handshake packet,
; 8*2 bits for another inter-packet delay.
lea eax, [ecx+edx+778]
ret
endp
; USB2 scheduler. ; USB2 scheduler.
; There are two parts: high-speed pipes and split-transaction pipes. ; There are two parts: high-speed pipes and split-transaction pipes.
; Split-transaction scheduler is currently a stub. ; Split-transaction scheduler is currently a stub.
@ -292,23 +360,26 @@ end virtual
add edx, sizeof.ehci_static_ep add edx, sizeof.ehci_static_ep
dec ebx dec ebx
jnz .varloop0 jnz .varloop0
; 5. Get the pointer to the best list. ; 5. Calculate bandwidth for the new pipe.
pop edx ; restore value from step 3
pop edx ; get delta calculated in step 3
add edx, [.target]
; 6. Calculate bandwidth for the new pipe.
; TODO1: calculate real bandwidth
mov eax, [.maxpacket] mov eax, [.maxpacket]
mov ecx, eax call calc_hs_bandwidth
and eax, (1 shl 11) - 1 mov ecx, [.maxpacket]
shr ecx, 11 shr ecx, 11
inc ecx inc ecx
and ecx, 3 and ecx, 3
imul eax, ecx imul eax, ecx
; 7. TODO2: check that bandwidth for the new pipe plus old bandwidth ; 6. Get the pointer to the best list.
pop edx ; restore value from step 3
pop edx ; get delta calculated in step 3
add edx, [.target]
; 7. Check that bandwidth for the new pipe plus old bandwidth
; still fits to maximum allowed by the core specification ; still fits to maximum allowed by the core specification
; current [.bandwidth] + new bandwidth <= limit; ; current [.bandwidth] + new bandwidth <= limit;
; USB2 specification allows maximum 60000*80% bit times for periodic microframe ; USB2 specification allows maximum 60000*80% bit times for periodic microframe
mov ecx, [.bandwidth]
add ecx, eax
cmp ecx, 48000
ja .no_bandwidth
; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. ; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return.
mov ecx, [.targetsmask] mov ecx, [.targetsmask]
add [edx+ehci_static_ep.Bandwidths+ecx*2], ax add [edx+ehci_static_ep.Bandwidths+ecx*2], ax
@ -317,6 +388,12 @@ end virtual
shl eax, cl shl eax, cl
pop edi ebx ; restore used registers to be stdcall pop edi ebx ; restore used registers to be stdcall
ret ret
.no_bandwidth:
dbgstr 'Periodic bandwidth limit reached'
xor eax, eax
xor edx, edx
pop edi ebx
ret
.every_frame: .every_frame:
; The pipe should be scheduled every frame in two or more microframes. ; The pipe should be scheduled every frame in two or more microframes.
; 9. Calculate maximal bandwidth for every microframe: three nested loops. ; 9. Calculate maximal bandwidth for every microframe: three nested loops.
@ -400,17 +477,21 @@ end virtual
add esp, 8*4 add esp, 8*4
; 12. Get the pointer to the target list (responsible for every microframe). ; 12. Get the pointer to the target list (responsible for every microframe).
lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller] lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller]
; 13. TODO1: calculate real bandwidth. ; 13. Calculate bandwidth on the bus.
mov eax, [.maxpacket] mov eax, [.maxpacket]
mov ecx, eax call calc_hs_bandwidth
and eax, (1 shl 11) - 1 mov ecx, [.maxpacket]
shr ecx, 11 shr ecx, 11
inc ecx inc ecx
and ecx, 3 and ecx, 3
imul eax, ecx imul eax, ecx
; 14. TODO2: check that current [.bandwidth] + new bandwidth <= limit; ; 14. Check that current [.bandwidth] + new bandwidth <= limit;
; USB2 specification allows maximum 60000*80% bit times for periodic microframe. ; USB2 specification allows maximum 60000*80% bit times for periodic microframe.
; Update bandwidths including the new pipe. mov ecx, [.bandwidth]
add ecx, eax
cmp ecx, 48000
ja .no_bandwidth
; 15. Update bandwidths including the new pipe.
mov ecx, [.targetsmask] mov ecx, [.targetsmask]
lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart] lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart]
.update_bandwidths: .update_bandwidths:
@ -421,7 +502,7 @@ end virtual
add edi, 2 add edi, 2
test ecx, ecx test ecx, ecx
jnz .update_bandwidths jnz .update_bandwidths
; 15. Return target list and target S-Mask. ; 16. Return target list and target S-Mask.
mov eax, [.targetsmask] mov eax, [.targetsmask]
pop edi ebx ; restore used registers to be stdcall pop edi ebx ; restore used registers to be stdcall
ret ret
@ -433,10 +514,10 @@ endp
proc ehci_hs_interrupt_list_unlink proc ehci_hs_interrupt_list_unlink
; get target list ; get target list
mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe]
; TODO: calculate real bandwidth
movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2]
; calculate bandwidth
call calc_hs_bandwidth
mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe]
and eax, (1 shl 11) - 1
shr ecx, 30 shr ecx, 30
imul eax, ecx imul eax, ecx
movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe]
@ -454,6 +535,26 @@ proc ehci_hs_interrupt_list_unlink
ret ret
endp endp
; Helper procedure for USB2 scheduler: calculate bandwidth on the bus.
; in: low 11 bits of eax = payload size in bytes
; out: eax = maximal bandwidth in HS-bits
proc calc_hs_bandwidth
and eax, (1 shl 11) - 1 ; get payload for one transaction
add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16
; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing;
; total 28/3 = 9+1/3
mov edx, 55555556h
lea ecx, [eax*9]
mul edx
; Add 989 extra bits: 68 bits for Token packet (32 for SYNC, 24 for token+address,
; 4 extra bits for possible bit stuffing in token+address, 8 for EOP),
; 736 bits for bus turn-around, 40 bits for SYNC+EOP in Data packet,
; 8 bits for inter-packet delay, 49 bits for Handshake packet,
; 88 bits for another inter-packet delay.
lea eax, [ecx+edx+989]
ret
endp
uglobal uglobal
ehci_last_fs_alloc dd ? ehci_last_fs_alloc dd ?
endg endg

View File

@ -1375,7 +1375,12 @@ endp
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type ; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
proc uhci_init_pipe proc uhci_init_pipe
; inherit some variables from the parent usb_open_pipe ; inherit some variables from the parent usb_open_pipe
virtual at ebp+8 virtual at ebp-12
.speed db ?
rb 3
.bandwidth dd ?
.target dd ?
rd 2
.config_pipe dd ? .config_pipe dd ?
.endpoint dd ? .endpoint dd ?
.maxpacket dd ? .maxpacket dd ?
@ -1413,6 +1418,8 @@ end virtual
mov al, USB_PID_IN mov al, USB_PID_IN
@@: @@:
mov [edi+uhci_pipe.Token-sizeof.uhci_pipe], eax mov [edi+uhci_pipe.Token-sizeof.uhci_pipe], eax
bt eax, 20
setc [.speed]
; 4. Initialize the first TD: ; 4. Initialize the first TD:
; copy Token from uhci_pipe.Token zeroing reserved bit 20, ; copy Token from uhci_pipe.Token zeroing reserved bit 20,
; set ControlStatus for future transfers, bit make it inactive, ; set ControlStatus for future transfers, bit make it inactive,