\ ========== 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.