Branch
Hash :
1a08f436
Author :
Date :
2010-08-25T09:23:17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
\ ========== Copyright Header Begin ==========================================
\
\ Hypervisor Software File: distributor.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: @(#)distributor.fth 1.11 02/03/12
purpose:
copyright: Copyright 1997-2000, 2002 Sun Microsystems, Inc. All Rights Reserved
copyright: Use is subject to license terms.
: end-of-line ( first-transfer -- last-transfer )
begin
dup next-transfer le-l@
while
next-transfer le-l@ dev>virt
repeat
;
: add-to-line ( transfer-d last-transfer -- )
swap virt>dev swap next-transfer le-l!
;
\ Put on done q in the same order as they show up on the controller done-q.
\ Stored on the endpoint done-q's as dev addresses, little endian, because
\ we reuse next-transfer to tie the q together, just as the other q's.
\ Could change to use a different field and virt addresses.
\ Don't need to sync this because the controller never accesses this field.
: t>end-done ( transfer-d -- )
0 over next-transfer l! \ at least for now, this will be the last one
\ "should" be le-l!, but the result is the same
dup my-endpoint @
dup ping-done-q
swap for-controller @ + ( transfer-d endp-q-pointer )
dup @ if \ go to the end of the line
@ end-of-line add-to-line
else !
then
;
: distribute-replies ( dev-done-head -- )
begin
dev>virt dup sync-transfer
dup next-transfer le-l@ swap ( dev-next curr-transfer-d )
t>end-done ( dev-next )
?dup 0= \ 0 marks end of q
until
;
variable done-mutex \ must be global
\ This mutex code is a little cleverer, it will release the mutex if
\ the caller is the current owner.
\ Stolen from the keyboard code.
\ XXX may not need this cleverness.
\ XXX heavily dependent on 32 bit execution tokens, as it gets something
\ from the return stack and saves it in a 32 bit variable.
\ XXX doesn't look like it really works here. mutex-enter is only called by take-done-q,
\ so the done-owner is always the same (once the open is done). open always unlocks
\ the mutex, so how does this protect the distributor?
\ variable done-owner \ XXX global?
\ : mutex-enter ( -- locked? )
\ done-mutex dup @ swap on ( locked? )
\ r@ done-owner rot if ( req var )
\ 2dup @ <> if ( req var )
\ 2drop true exit ( true )
\ then ( var req )
\ then ( req var )
\ ! false ( false )
\ ;
\ : mutex-exit ( -- ) done-mutex off ;
\ Used by done-waiting?
: take-done-q ( -- )
new-done? if
sync-hcca
hcca done-head le-l@
\ toss interrupt-on bit which un-aligns the done-head:
1 invert and
clear-done-head
distribute-replies
then
;
\ Really should take off the alarm list when quit level runs, then put back on alarm
\ list. Redman says that triggers an alarm list bug, so can't do it now.
: alarm-take-done-q ( -- ) \ use on alarm level with 10 ms tick timer
done-mutex @ 0= if \ XXX diff from use in mutex-enter, -exit
take-done-q
then
;
: quit-take-done-q ( -- ) \ use on quit loop level
true done-mutex ! \ XXX diff from use in mutex-enter, -exit
take-done-q
0 done-mutex !
;
\ Replies are distributed by children, but the distributor is protected by
\ the mutex so that replies go in order.
\ XXX Check this code to make sure it's re-entrant.
\ XXX Check this code to make sure it has no race conditions with the code
\ running at the normal level which is editing the q's to install new stuff
\ or disable-int-transactions.
\ XXX Problem: 10 ms timer ticking for the keyboard and disk being booted
\ from. each can see the other's transfer descriptors on the done q.
\ Keep old done-q's until descriptors are all claimed? Or timed out somehow?
\ **attach a done-q to each endpoint descriptor and distribute them from the
\ chip's done-q?
\ Still a problem if the keyboard is looking at 10ms timer intervals,
\ essentially interrupting, while the boot device is looking at the regular
\ execution intervals. There's a race condition over who looks at the
\ done q of the chip to distribute the transfer descriptors.
\ In practice there will be 1 set of transactions running off the 10ms timer
\ for the keyboard and 1 running as usual for a boot device. There may be
\ more instances of usb devices open, but only these will be running.
\ Even if there is a usb output device that runs interrupt transfers, that
\ will probably be run as a normal device, rather than hung off the 10 ms
\ timer.
\ The normal code looks to see if there are transfers to distribute. There
\ are. Just then, the interrupt code runs, finds and distributes the
\ transfers. It finishes, and the normal code thinks there are transfers
\ to distribute, so it tries to do so -- but they have already been
\ distributed before the normal code could grab the done q.
\ One possible solution:
\ Put the done-q transfer distribution code at the 10 ms interrupt as well.
\ Another one:
\ The normal instance looks again after grabbing the done q to find out if
\ there are really any transfers to distribute (by looking at the bit in the
\ register?). If there are it distributes them, because it really has the
\ done q now, having set the control. If the ones that were there before
\ have already been distributed, but new ones arrived (so the bit is true),
\ that's ok. Just go ahead and distribute them.
\ **Better variation:
\ Grab the done q before finding out whether there are any entries. Then
\ look at the done q and distribute. Then give up the q, and look at the
\ endpoint done q.
\ Is there another race condition? The normal code looks at its endpoint
\ done q, and while fiddling with it, a new transfer is distributed to it
\ by the 10ms timer instance. What happens? Does grabbing the done q
\ extend to grabbing all the done q's at once?
\ Note, once the chip done-q is turned over to the software, the chip
\ essentially stalls until it is returned to the chip. The chip doesn't
\ re-use the old done-q, but rather starts a new one. So all the transfers
\ on the done-q must be distributed before the done-q is lost track of. So
\ can't have the situation where the normal code grabbed its own done q and
\ locked out the 10 ms timer code from distributing a transfer onto the normal
\ done q, as the 10 ms timer code has a problem knowing what to do with the
\ leftover transfers, and can't sit waiting for the normal code to release
\ its done q.
\ **use two endpoint done q's. one being emptied by the code, one being filled
\ by the distributor. while the code is emptying one, it does not touch the
\ other. also, the distributor only puts them on the other and does not touch
\ the one being emptied. when 1st is empty, code switches to the other.
\ switch is ok, as if distributor puts some more on just as code is switching,
\ that's ok.
\ what about a pipe between the distributor and the code? don't see it.
\ could also use a ring of transfer addresses without links. could work,
\ but it seems more cumbersome than just ping-ponging the q's.
\ must be the kind of thing that the normal code doesn't need to lock, since
\ the distributor code can't block, since it might be running as part of
\ the 10ms timer instance.