Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / dev / usb / endpointmap.fth
\ ========== Copyright Header Begin ==========================================
\
\ Hypervisor Software File: endpointmap.fth
\
\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
\
\ - Do no alter or remove copyright notices
\
\ - Redistribution and use of this software in source and binary forms, with
\ or without modification, are permitted provided that the following
\ conditions are met:
\
\ - Redistribution of source code must retain the above copyright notice,
\ this list of conditions and the following disclaimer.
\
\ - Redistribution in binary form must reproduce the above copyright notice,
\ this list of conditions and the following disclaimer in the
\ documentation and/or other materials provided with the distribution.
\
\ Neither the name of Sun Microsystems, Inc. or the names of contributors
\ may be used to endorse or promote products derived from this software
\ without specific prior written permission.
\
\ This software is provided "AS IS," without a warranty of any kind.
\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
\
\ You acknowledge that this software is not designed, licensed or
\ intended for use in the design, construction, operation or maintenance of
\ any nuclear facility.
\
\ ========== Copyright Header End ============================================
id: @(#)endpointmap.fth 1.9 98/03/17
purpose:
copyright: Copyright 1997 Sun Microsystems, Inc. All Rights Reserved
\ XXX need to re-do this, as the fields may not line up correctly for
\ @ and ! especially for-controller, ping- and pong-
struct
4 field endpoint-control
4 field td-tail
4 field td-head
4 field next-endpoint
/n field prev-endpoint \ used by software only, virt
\ 0 means first on q
/n field q-id \ this endpoint is on the q q-id
4 field dummy? \ false if this is a real endpoint
\ These next 3 fields are dependent on being in this order and together:
/n field for-controller \ 0 if reply distributor puts
\ transfer descriptors on ping-q,
\ /n if distributor puts onto pong-q.
/n field ping-done-q \ 0 if no transfer-d's here, virt
/n field pong-done-q \ ditto
\ /n field caller-buf
/n field caller-len
/n field interrupt-buf \ used for interrupt transfers, virt
/n field transfer-count \ number of real transfer d's outstanding
h# 10 over h# 10 mod - \ pad to next 16 byte boundary
field endpad
( endpoint descrip. size ) constant /endpoint
\ XXX The above allocation wastes a dictionary entry for endpad and 16 bytes
\ of space if the other fields add up to 0 mod 16. Can save the dict. space
\ by pushing calculation into the size of transfer-count
\ q-id above is needed so that if a transfer descriptor on the done q shows
\ an error which requires flushing other descriptors for its endpoint, and
\ the endpoint has no transfer descriptors left after flushing, and hence
\ the endpoint should be pulled off the q, the software can figure out
\ which code should be used to pull the endpoint off the q.
\ dummy? above is needed to help figuring out the ends of the interrupt q's
\ more easily, instead of checking whether a particular address of an
\ endpoint is actually the start of the next q.
\ ping-done-q and pong-done-q, with for-controller, are used as done q's for
\ this endpoint. The reply distributor code moves transfer descriptors from
\ the done q of the controller to (only) one of these endpoint done q's.
\ The endpoint reply processing code takes transfer descriptors from the
\ other ping-pong done q. This avoids a race condition between the distributor
\ code and the processing code.
\ ping- and pong-done-q hold virtual addresses. The transfer descriptors
\ themselves are linked via the next-transfer field, which holds dev addresses,
\ little endian.
\ transfer-count does not include the dummy transfer-d.
\ 0-3e (0-62) are interrupt q id's.
d# 63 constant isoc-id
d# 64 constant control-id
d# 65 constant bulk-id
d# 66 constant #dummy-qs
: isoc-endpoint? ( e-addr -- isoc? )
endpoint-control le-l@ h# 8000 and
;
: dummy-endpoint? ( e-addr -- dummy? ) dummy? l@ ;
: halted? ( e-addr -- halted? ) td-head le-l@ 1 and ;
: end-toggle ( e-addr -- toggle ) td-head le-l@ 2 and 1 rshift ;
: skip-endp ( e-addr -- )
endpoint-control dup le-l@
h# 4000 or
swap le-l!
;
: unskip-endp ( e-addr -- )
endpoint-control dup le-l@
h# 4000 invert and
swap le-l!
;
\ Need to leave some td-tail bits alone:
: td-tail@ ( e-addr -- td-tail ) td-tail le-l@ h# f invert and ;
: td-tail! ( n e-addr -- )
td-tail tuck le-l@ h# f and or
swap le-l!
;
\ Need to leave some td-head bits alone:
: td-head@ ( e-addr -- n ) td-head le-l@ h# f invert and ;
: td-head! ( n e-addr -- )
td-head tuck le-l@ h# f and or
swap le-l!
;
\ Need to leave some next-endpoint bits alone:
: next-endpoint@ ( e-addr -- n ) next-endpoint le-l@ h# f invert and ;
: next-endpoint! ( n e-addr -- )
next-endpoint tuck le-l@ h# f and or
swap le-l!
;
: empty-endp? ( e-addr -- empty? )
dup td-tail@ swap td-head@ =
;
: stopped? ( e-addr -- empty?-or-halted? )
dup empty-endp?
swap halted? or
;
: code-done-q ( endpoint -- q-head )
dup ping-done-q swap for-controller @ /n - abs +
;
: ping-pong ( endpoint -- )
dup for-controller @
/n - abs
swap for-controller !
;
\ XXX the endpoints/transfers can't have a device address of 0, or the
\ chip won't function correctly when traversing the q's. The code to detect
\ q ends won't work either.
\ XXX the various queued descriptors have alignment restrictions
\ 63 dummy interrupt endpoint descriptors are arranged so that the
\ next-endpoint fields hook them together in a tree. See ohci 3.3.2,
\ figure 3-4. These are marked SKIP. There are no transfer descriptors,
\ since they will never be activated. When a real interrupt endpoint is
\ desired, it is hooked into the interrupt tree after the dummy endpoint at
\ a spot for its interrupt interval. The dummies remain on the tree. They
\ use q-ids 0 through 62. They are each considered to be head of q, so
\ prev-endpoint is 0 for each of them.
\ Level 1 of the tree is directly connected to the interrupt slots in hcca,
\ dummies 0 thru 31. Level 2 of the tree (dummies 32 thru 47) is connected
\ to level 1 dummies. Level 3 (dummies 48 thru 55) is connected to level 2.
\ Level 4 (dummies 56 thru 59) is connected to level 3. Level 5 (dummies 60
\ thru 61) is connected to level 4, and level 6 (dummy 62) is connected to
\ level 5. The dummies are connected so as to space the times for each
\ entry of each level evenly through the 32 millisecond round robin cycle
\ of periodic frame processing.
\ Interrupt endpoints on level 1 are processed once per 32 msec. Level 2
\ endpoints are processed once per 16 msec. Level 3 endpoints are processed
\ once per 8 msec. Level 4 endpoints go once per 4 msec. Level 5 endpoints
\ run once per 2 msec, and level 6 endpoints run every msec.
\ Connection algorithm:
\ Start with level 1 -- dummies 0 thru 31. Each is connected to the same
\ number slot in the interrupt table as its q-id.
\ Each is connected to a dummy in level 2 whose q-id is determined thus:
\ 1. change bit 4 of its q-id to 0.
\ 2. change bit 5 of its q-id to 1.
\ Each level 2 dummy is connected to a level 3 dummy whose q-id is determined:
\ 1. change bit 3 of its q-id to 0.
\ 2. change bit 4 of its q-id to 1.
\ Connect all level 3 dummies to level 4 dummies:
\ 1. change bit 2 of the q-id to 0.
\ 2. change bit 3 of the q-id to 1.
\ Level 4 dummies connect to level 5 dummies:
\ 1. change bit 1 of the q-id to 0.
\ 2. change bit 2 of the q-id to 1.
\ Connect both level 5 dummies to level 6:
\ 1. change bit 0 of the q-id to 0.
\ 2. change bit 1 of the q-id to 1.
\ 0\
\ 32\
\ 16/ \
\ 48\
\ 8\ / \
\ 40/ \
\ 24/ \
\ 56\
\ 4\ / \
\ 36\ / \
\ 20/ \ / |
\ 52/ |
\ 12\ / |
\ 44/ |
\ 28/ |
\ 60\
\ 2\ | \
\ 34\ | \
\ 18/ \ | |
\ 50\ | |
\ 10\ / \ | |
\ 42/ \ / |
\ 26/ \ / |
\ 58/ |
\ 6\ / |
\ 38\ / |
\ 22/ \ / |
\ 54/ |
\ 14\ / |
\ 46/ |
\ 30/ |
\ 62
\ 1\ |
\ 33\ |
\ 17/ \ |
\ 49\ |
\ 9\ / \ |
\ 41/ \ |
\ 25/ \ |
\ 57\ |
\ 5\ / \ |
\ 37\ / \ |
\ 21/ \ / | |
\ 53/ | |
\ 13\ / | |
\ 45/ | /
\ 29/ | /
\ 61/
\ 3\ |
\ 35\ |
\ 19/ \ |
\ 51\ |
\ 11\ / \ |
\ 43/ \ /
\ 27/ \ /
\ 59/
\ 7\ /
\ 39\ /
\ 23/ \ /
\ 55/
\ 15\ /
\ 47/
\ 31/
\ XXX code to balance the tree is desired.
\ The control, bulk, and isochronous q's each have one dummy start endpoint
\ descriptor that has no transfer descriptors. Each dummy is marked with
\ SKIP. Each is considered to be head of q, so prev-endpoint is 0.
\ The isoc q dummy hooks onto the end of interrupt q 62. It is marked as
\ isochronous endpoint format.
\ XXX Bandwidth problems or chip problems may require going back to the
\ earlier q style, with no dummy q heads.
0 value dummy-endpoints
0 value dev-dummy-endpoints
/endpoint #dummy-qs * constant /dummies
: sync-dummies ( -- ) sync-mem ;
\ The interrupt dummies come first:
: interrupt-dummy ( q-id -- addr ) /endpoint * dummy-endpoints + ;
: dev-interrupt-dummy ( q-id -- devaddr )
/endpoint * dev-dummy-endpoints +
;
: isoc-dummy ( -- addr ) isoc-id interrupt-dummy ;
: dev-isoc-dummy ( -- devaddr ) isoc-id dev-interrupt-dummy ;
: control-dummy ( -- addr ) control-id interrupt-dummy ;
: dev-control-dummy ( -- devaddr ) control-id dev-interrupt-dummy ;
: bulk-dummy ( -- addr ) bulk-id interrupt-dummy ;
: dev-bulk-dummy ( -- devaddr ) bulk-id dev-interrupt-dummy ;
: plugdummy ( devaddr q-id -- )
interrupt-dummy next-endpoint le-l!
;
\ XXX could use two nested loops, passing in the level to a common routine:
: getnext1 ( q-id -- devaddr ) \ devaddr of next for level 1 of int dummies
h# 10 invert and h# 20 or dev-interrupt-dummy
;
: getnext2 ( q-id -- devaddr )
8 invert and h# 10 or dev-interrupt-dummy
;
: getnext3 ( q-id -- devaddr )
4 invert and 8 or dev-interrupt-dummy
;
: getnext4 ( q-id -- devaddr )
2 invert and 4 or dev-interrupt-dummy
;
: getnext5 ( q-id -- devaddr )
1 invert and 2 or dev-interrupt-dummy
;
: connect-dummies ( -- ) \ connect the interrupt dummies into a tree
d# 32 0 do \ connect 1st to 2nd level
i getnext1 i plugdummy
loop
d# 48 d# 32 do \ connect 2nd to 3rd level
i getnext2 i plugdummy
loop
d# 56 d# 48 do \ connect 3rd to 4th level
i getnext3 i plugdummy
loop
d# 60 d# 56 do \ connect 4th to 5th level
i getnext4 i plugdummy
loop
d# 62 d# 60 do \ connect 5th to 6th level
i getnext5 i plugdummy
loop
dev-isoc-dummy d# 62 plugdummy \ connect isoc dummy to int 62
;
: skip-dummies ( -- ) \ mark dummies to be skipped
dummy-endpoints dummy? \ mark as dummies
#dummy-qs 0 do
true over l! /endpoint +
loop drop
dummy-endpoints endpoint-control \ mark to be skipped
#dummy-qs 0 do
h# 4000 over le-l! /endpoint +
loop drop
h# c000 isoc-dummy endpoint-control le-l! \ mark isoc q head format
;
: name-dummies ( -- ) \ set q-ids
dummy-endpoints q-id
#dummy-qs 0 do
i over ! /endpoint +
loop drop
;
: make-dummies ( -- )
/dummies get-chunk to dummy-endpoints
dummy-endpoints virt>dev to dev-dummy-endpoints
skip-dummies
connect-dummies
name-dummies
sync-dummies
;
: dump-dummies ( -- )
-1 to dev-dummy-endpoints
dummy-endpoints /dummies give-chunk
-1 to dummy-endpoints
;
\ : dev-dummy? ( dev-addr -- dev-dummy? ) \ true if a dummy dev addr.
\ dev-dummy-endpoints /dummies bounds swap between
\ ;
: dummydev>virt ( dev-addr -- virt ) \ for dummies
dev>virt
;