Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / dev / usb / usb.fth
CommitLineData
920dae64
AT
1\ ========== Copyright Header Begin ==========================================
2\
3\ Hypervisor Software File: usb.fth
4\
5\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6\
7\ - Do no alter or remove copyright notices
8\
9\ - Redistribution and use of this software in source and binary forms, with
10\ or without modification, are permitted provided that the following
11\ conditions are met:
12\
13\ - Redistribution of source code must retain the above copyright notice,
14\ this list of conditions and the following disclaimer.
15\
16\ - Redistribution in binary form must reproduce the above copyright notice,
17\ this list of conditions and the following disclaimer in the
18\ documentation and/or other materials provided with the distribution.
19\
20\ Neither the name of Sun Microsystems, Inc. or the names of contributors
21\ may be used to endorse or promote products derived from this software
22\ without specific prior written permission.
23\
24\ This software is provided "AS IS," without a warranty of any kind.
25\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
26\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
27\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
28\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
29\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
30\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
31\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
32\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
33\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
34\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
35\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
36\
37\ You acknowledge that this software is not designed, licensed or
38\ intended for use in the design, construction, operation or maintenance of
39\ any nuclear facility.
40\
41\ ========== Copyright Header End ============================================
42id: @(#)usb.fth 1.16 03/05/12
43purpose:
44copyright: Copyright 1997-2000, 2003 Sun Microsystems, Inc. All Rights Reserved
45copyright: Use is subject to license terms.
46
47external
48
49
50\ Code for the request looks at the done-q for the endpoint. When no more
51\ transfers to go out, and both done-q's dealt with, endpoint gets torn
52\ down. Or if error recovery dumps the remaining transfers and deals with
53\ done-q's. But how does the code know whether all the replies have been
54\ received, and that there aren't more on the controller done-q waiting to
55\ be distributed? Can there be any in a transition -- processed by the
56\ controller, but not yet put on the done-q because the controller already
57\ turned the done-q over to the code, but the code has not yet acknowledged
58\ it? What do such transfer-d's look like?
59
60\ OS folks avoid the problem by running a second list structure through
61\ the transfer d's in addition to the one the chip uses, together with a
62\ re-claim mark on the transfer d's. When code decides to dump an endpoint,
63\ it marks each of the transfer d's to be re-claimed, using the non-controller
64\ list links. Then it dumps the endpoint. When transfer d's show up on the
65\ controller done q with the reclaim mark, the done-q code dumps them
66\ immediately, before attempting to assign them to an endpoint.
67
68\ Instead of double threading, try putting a count of outstanding transfer
69\ d's in the endpoint. When one is added, increment the count. When one
70\ is taken from one of the ping-pong done q's, decrement the count. Don't
71\ include the dummy transfer d in the count. If the total of the number left
72\ to do plus those on the done q's is less than the transfer d count, there
73\ are some in process (or on the controller done q).
74
75
76\ OHCI control transfers always start with setup stage and always end with
77\ a 0 len transfer status stage. There may be a data transfer stage in
78\ between.
79
80\ req-adr req-len is the control request to be sent. endpoint usb-addr is
81\ the target address. buf-adr buf-len is where accompanying data is to be
82\ sent from, or return data to be put. buf-adr = 0 and/or buf-len = 0 imply
83\ no data to be transferred. max-pkt is maximum packet to be transferred in
84\ one transfer.
85\ dir is the direction that data will flow: 0 is from target to host, 1 is
86\ from host to target. If no data transfer, dir is 1. low-speed? is true for
87\ low-speed target, false for normal speed.
88
89: execute-control ( low-speed? dir max-pkt buf-adr buf-len req-adr req-len
90 endpoint usb-addr -- hw-err? | stat 0 )
91 2swap >r >r 2swap >r >r
92 2swap swap >r -rot
93 make-endpoint ( endpoint-d ) ( R: r-len r-adr b-len b-adr dir )
94 r> r> r> r> r> ( endpoint-d dir b-adr b-len r-adr r-len )
95 2swap >r >r
96 2swap >r >r r@ ( r-adr r-len endp-d ) ( R: blen badr dir endp-d )
97 add-setup-transfer ( R: b-len b-adr dir endp-d )
98 r> r> swap r> r>
99 2swap 2dup >r >r ( b-adr b-len dir endp-d ) ( R: endp-d dir )
100 add-data-transfer ( R: endp-d dir )
101 r> r@ add-ack-transfer ( R: endp-d )
102 r> dup enque-control ( endp-d )
103 dup wait-for-last-reply ( endp-d code )
104 dup if over wipe-endpoint then
105 swap deque-control ( code )
106 translate-code
107 ?.error
108;
109
110headers
111
112\ Must set skip if dir is out, as there is no data to transfer yet.
113: set-endp-dir ( dir endp-adr -- )
114 over if dup skip-endp then
115 endpoint-control tuck le-l@
116 h# ffff.e7ff and
117 swap if out-bits else in-bits then
118 d# 11 lshift or
119 swap le-l!
120;
121
122\ XXX hack1 to set the toggle for the starting transfer-d in the endp-d
123: set-endp-toggle ( toggle endp-adr -- )
124 td-head tuck le-l@
125 swap 1+ 2 and or swap
126 le-l!
127;
128
129: set-trans-toggle ( toggle transfer-d -- )
130 transfer-control tuck le-l@
131 h# fcff.ffff and swap d# 24 lshift or
132 swap le-l!
133;
134
135: (use-endp-toggle) ( endp-d -- )
136 dup td-tail@
137 swap td-head@ dev>virt
138 begin ( tail-adr next-adr )
139 0 over set-trans-toggle
140 2dup next-transfer le-l@ <>
141 while
142 next-transfer le-l@ dev>virt
143 repeat
144 2drop
145;
146
147\ XXX hack2 to set the transfer-d's to use the toggle in the endpoint-d
148: use-endp-toggle ( endp-d -- )
149 dup td-head@ if (use-endp-toggle)
150 else drop
151 then
152;
153
154external
155
156\ Data toggles are synchronized via a separate control endpoint transaction.
157\ OHCI setup clearing an endpoint stall sets data toggle to 0.
158\ Use set-feature to set an endpoint stall. Use clear-feature to clear an
159\ endpoint stall.
160
161\ Want to execute this one as quickly as possible, so attach it to the
162\ every-ms interrupt q.
163\ toggle1 (0 or 1) is to be used first. toggle2 is last-used.
164\ mark the toggle in the endpoint-d.
165\ XXX not good enough -- nak doesn't cause the transfer-d to be
166\ retired. need to wait only for 1 frame (nominally) rather than until reply.
167: execute-1-interrupt
168 ( toggle1 low-speed? dir max-pkt buf-addr buf-len endpoint usb-adr
169 -- toggle2 hw-err? | toggle2 stat 0 )
170 2swap >r >r 2swap swap >r -rot
171 ( toggle1 low-spd? max-pkt endp u-adr) ( R: blen badr dir )
172 make-endpoint ( toggle1 endp-adr ) ( R: blen badr dir )
173 tuck set-endp-toggle
174 r> r> r> rot 3 pick add-data-transfer
175 dup use-endp-toggle ( endp-adr )
176 dup d# 62 enque-interrupt
177 dup 1-try-wait
178 over end-toggle -rot
179 dup if over wipe-endpoint then
180 swap deque-interrupt ( toggle2 code )
181 translate-code
182 ?.error
183;
184
185
186\ for now, token will be the endpoint descriptor address
187\ token = 0 means it can't be scheduled -- possibly the interval is
188\ too great or too small.
189\ ms is the maximum gap between successive polls.
190\ use the toggle in the endpoint-d. use the dir in the endpoint-d.
191\ This uses a local buffer for data transfer. Then the report is copied into
192\ the caller's buffer by int-transaction-status, and the buffer can be re-used.
193\ disable-int-transactions throws away the local buffer.
194\ XXX buf-adr moved to int-transaction-status implies that if dir is out,
195\ there is no data to move when enable-int-transactions is executed. So the
196\ transaction should be skipped until int-transaction-status is called.
197\ So if dir is out, the endpoint descriptor must be marked SKIP, and
198\ int-transaction-status must unmark it.
199\ set dir in endpoint descriptor, mark transfer to use endpoint dir.
200: enable-int-transactions ( ms toggle low-speed? dir max-pkt buf-len
201 endpoint usb-adr -- token )
202 rot >r 2swap swap >r -rot
203 ( ms toggle speed max-pkt endp usb-addr ) ( R: blen dir )
204 make-endpoint ( ms toggle endp-adr ) ( R: blen dir )
205
206 tuck set-endp-toggle ( ms endp-adr ) ( R: blen dir )
207 r> over set-endp-dir \ may need to skip endpoint
208 r> over caller-len !
209 dup caller-len @ get-chunk over interrupt-buf !
210 dup dup interrupt-buf @ over caller-len @
211 rot 0 swap add-data-transfer \ use target to host -- really use endp for dir
212 dup use-endp-toggle ( ms endp-adr )
213 tuck swap pick-q if ( endp endp q# )
214 enque-interrupt
215 else ( endp endp ) \ couldn't pick a q
216\ dump data-transfer interrupt-buf if caller-len <>0
217\ dump ack-transfer, data-transfer
218\ clear-endpoint
219\ ( endp ) toss-endpoint
220\ XXX just to get going, since there is always a q:
221 cr ." no q found -- error " cr
222 2drop \ XXX wrong
223 0
224 then
225;
226
227\ token is the address of the endpoint for the interrupt. The endpoint is
228\ placed in one spot on the interrupt tree.
229\ toggle is the last one used.
230
231: disable-int-transactions ( token -- toggle )
232 dup skip-endp
233 d# 10 ms \ XXX crude; wait for the distributor to have a chance
234 \ to catch up with any transfers. Could check if
235 \ any are outstanding via transfer-count.
236 \ XXX needed if stuff happens on 10 ms tick timer level.
237 dup dump-done-q
238 dup ping-pong
239 dup dump-done-q
240 dup end-toggle swap
241 dup wipe-endpoint
242 dup interrupt-buf @ over caller-len @ give-chunk
243 deque-interrupt
244;
245
246headers
247
248\ Possible optimization: Re-use the transfer descriptor, since it is
249\ already allocated and partially ready for re-use.
250\ For now, brute force: dump transfer-d and get a new one.
251
252: re-arm-receive ( endp-d -- )
253 dup skip-endp next-frame \ make sure endpoint is not active
254\ >r r@ take-transfer-d's \ re-use transfer-d's
255 dup dump-done-q
256 dup ping-pong
257 dup dump-done-q ( endp-d )
258 dup dup interrupt-buf @ over caller-len @
259\ XXX use (add-data-transfer) to force a 0 len transfer??
260 rot 0 swap add-data-transfer \ dir is fake; take from endpoint
261 dup use-endp-toggle
262 unskip-endp
263;
264
265: forward-data ( buf-addr endp-d -- )
266 sync-mem
267 >r r@ interrupt-buf @ swap r> caller-len @ move
268;
269
270\ Copy data from internal buffer to buf-addr
271: receive-int ( buf-addr token -- hw-err? | stat 0 )
272 dup done-waiting? if
273 dup code-done-q @ dup condition-code if \ reply had error
274 nip nip
275 condition-code translate-code
276 else \ reply ok
277 drop
278 dup re-arm-receive forward-data
279 usb-ack 0
280 then
281 else 2drop usb-nak 0
282 then
283;
284
285\ XXX wrong; but we have no devices needing out interrupt transactions yet
286\ from memory to device.
287\ Copy data from buf-addr to internal buffer. UnSKIP the endpoint.
288: send-int ( buf-addr token -- hw-err? | stat 0 )
289 2drop 2 0
290;
291
292: receive-int? ( token -- in? )
293 endpoint-control le-l@
294 h# 0000.1800 and
295 h# 0000.1000 =
296;
297
298external
299
300\ token is the address of the endpoint for the interrupt. The endpoint is
301\ placed in one spot on the interrupt tree.
302\ stat is ACK if interrupt fired, NACK if not, STALL if stalled.
303\ Re-arms the endpoint. Use its own buffers. Copy to/from the provided buffer
304\ when int-transaction-status is called. The client can copy out/in the
305\ provided buffer in between calls to int-transaction-status.
306\ Must be cognizant of dir in enable-int-transactions, in order to know
307\ which way to copy the data -- to or from the provided buffer. Must also
308\ unSKIP the endpoint if dir is out.
309
310: int-transaction-status ( buf-addr token -- hw-err? | stat 0 )
311 dup receive-int? if receive-int else send-int then
312 ?.error
313;
314
315
316\ OHCI bulk transfers use IN or OUT token stages. Sometimes can be followed
317\ directly by a status stage with no data. Otherwise data transfer stage.
318\ IN finishes with 0 len transfer (or no transfer if problem with data).
319\ OUT finishes with no extra transfer from host to target. The data toggles
320\ are synchronized via a separate control endpoint transaction.
321: execute-bulk ( toggle1 dir max-pkt buf-adr buf-len endpoint usb-addr
322 -- toggle2 hw-err? | toggle2 stat 0 )
323 2swap >r >r >r 0 -rot r> \ always full speed
324 make-endpoint ( toggle dir endp-adr ) ( R: blen badr )
325 rot over set-endp-toggle
326 tuck r> r> ( endp-adr dir endp-adr badr blen )
327 2swap add-data-transfer
328 dup use-endp-toggle ( endp-adr )
329 dup enque-bulk
330 dup wait-for-last-reply
331 over end-toggle -rot
332 dup if over wipe-endpoint then
333 swap deque-bulk ( toggle2 code )
334 translate-code
335 ?.error
336;
337
338
339: set-isoc-endpoint ( endp-d -- )
340 endpoint-control dup le-l@
341 h# 8000 or
342 swap le-l!
343;
344
345: set-isoc-direction ( dir endp-d -- )
346 endpoint-control tuck
347 le-l@ h# 1800 not and
348 swap if h# 800 else h# 1000 then or
349 swap le-l!
350;
351
352\ OHCI isoc transfers have IN or OUT token stages. Then data stage.
353\ No extra status stage. No data toggles.
354\ XXX not really correct, as the various packets can have their own error
355\ codes.
356\ XXX must be able to do 0 len transfers. Really need to be given a transfer
357\ schedule. probably should have both absolute and relative schedules.
358\ XXX new stack -- schedule added
359\ : execute-isochronous ( buf-adrn cntn ... buf-adr1 cnt1 n absolute? frame#
360\ dir max-pkt endpoint usb-addr -- hw-err? )
361: execute-isochronous ( frame# dir max-pkt buf-adr buf-len endpoint usb-addr
362 -- hw-err? )
363\ XXX static allocation implies
364\ XXX need to copy the buffer to our buffer in order to get dev-addr
365 2swap >r >r >r 0 -rot r> \ always full speed
366 make-endpoint ( frame# dir endp-d ) ( R: blen badr )
367 dup set-isoc-endpoint
368 tuck set-isoc-direction ( f# endp-d ) ( R: blen badr )
369 r> r> ( f# endp-d badr blen )
370 rot dup >r ( f# badr blen endp-d ) ( R: endp-d )
371 add-isoc-transfer ( R: badr endp )
372 r@ enque-isoc
373 r> dup wait-for-last-isoc-reply ( endp-d code )
374 swap deque-isoc ( code )
375 translate-code
376 ?.error
377;
378
379headers
380
3812 value usb-address-counter
382
383external
384
385\ hub code needs to call up to get the next usb address to assign it
386\ to a device it finds when it executes its own probe stuff at power on.
387\ " next-usb-address" $call-parent.
388
389\ Only addresses 2 thru 127 are valid to be assigned. 1 is reserved for the
390\ root hub node.
391
392: next-usb-address ( -- n )
393 usb-address-counter d# 127 > if
394 0
395 else
396 usb-address-counter
397 dup 1+ is usb-address-counter
398 then
399;
400
401: current-frame ( -- n )
402 hcca frame# le-w@
403;
404
405headers
406
407\ Clear stall from endpoint via endpoint 0:
408: clear-stall ( speed endpoint usb-adr -- hw-err? | stat 0 )
409 >r
410 request-blank >r ( R: usb-adr buf-adr )
411 clear-feature-req h# 200 or r@ request-type w!
412 endpoint-stall r@ req-value le-w!
413 r@ req-index le-w! ( speed ) ( R: usb-adr buf-adr )
414 1 max-packet 0 0
415 r> /request
416 0 r> 2over >r >r \ goes to endpoint 0
417 execute-control
418 r> r> give-chunk
419;
420
421\ clean up errors: endpoint should be halted. all transfer-d's should
422\ be accounted for, either on the endpoint q or on one of its done-q's;
423\ the controller shouldn't be fiddling with any. they should really be
424\ on the endpoint q. dump all remaining transfer-d's. halt the control
425\ q, dump the endpoint, restart the control q.
426
427
428\ XXX Need to instancify the code.
429
430\ XXX Need to check the size of transfers to make sure it fits in one
431\ transfer-d, or else make more of them.