Annotation of XNU/iokit/Families/IOFireWire/IOFWIsochChannel.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved.
                     24:  *
                     25:  * HISTORY
                     26:  *
                     27:  */
                     28: 
                     29: #include <IOKit/assert.h>
                     30: #include <IOKit/firewire/IOFireWireController.h>
                     31: #include <IOKit/firewire/IOFWIsochChannel.h>
                     32: #include <IOKit/firewire/IOFWIsochPort.h>
                     33: #include <libkern/c++/OSSet.h>
                     34: #include <libkern/c++/OSCollectionIterator.h>
                     35: #include <IOKit/firewire/IOFWCommand.h>
                     36: #include <IOKit/firewire/IOFireWireDevice.h>
                     37: 
                     38: OSDefineMetaClassAndStructors(IOFWIsochChannel, OSObject)
                     39: 
                     40: void IOFWIsochChannel::threadFunc(thread_call_param_t arg, thread_call_param_t)
                     41: {
                     42:     ((IOFWIsochChannel *)arg)->reallocBandwidth();
                     43: }
                     44: 
                     45: bool IOFWIsochChannel::init(IOFireWireController *control, bool doIRM,
                     46:        UInt32 bandwidth, IOFWSpeed prefSpeed,
                     47:        FWIsochChannelForceStopNotificationProcPtr stopProc, void *stopRefCon)
                     48: {
                     49:     if(!OSObject::init())
                     50:        return false;
                     51:     fControl = control;
                     52:     fDoIRM = doIRM;
                     53:     fMBitSec = bandwidth;
                     54:     fPrefSpeed = prefSpeed;
                     55:     fStopProc = stopProc;
                     56:     fStopRefCon = stopRefCon;
                     57:     fTalker = NULL;
                     58:     fListeners = OSSet::withCapacity(1);
                     59:     fChannel = 64;     // Illegal channel
                     60:     return fListeners != NULL;
                     61: }
                     62: 
                     63: void IOFWIsochChannel::free()
                     64: {
                     65:     if(fListeners)
                     66:         fListeners->release();
                     67:     OSObject::free();
                     68: }
                     69: 
                     70: IOReturn IOFWIsochChannel::setTalker(IOFWIsochPort *talker)
                     71: {
                     72:     fTalker = talker;
                     73:     return kIOReturnSuccess;
                     74: }
                     75: 
                     76: IOReturn IOFWIsochChannel::addListener(IOFWIsochPort *listener)
                     77: {
                     78:     if(fListeners->setObject(listener))
                     79:         return kIOReturnSuccess;
                     80:     else
                     81:         return kIOReturnNoMemory;
                     82: }
                     83: 
                     84: IOReturn IOFWIsochChannel::updateBandwidth(bool claim)
                     85: {
                     86:     FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable);
                     87:     IOFireWireDevice *irm;     // The Isochronous Resource Manager, if there is one
                     88:     IOFWReadQuadCommand *readCmd = NULL;
                     89:     IOFWCompareAndSwapCommand *lockCmd = NULL;
                     90:     UInt32 newVal;
                     91:     UInt32 oldVal;
                     92:     IOReturn result;
                     93:     bool tryAgain;
                     94: 
                     95:     do {
                     96:         irm = fControl->getIRMDevice();
                     97:         if(fBandwidth != 0) {
                     98:             if(irm != NULL) {
                     99:                 readCmd = irm->createReadQuadCommand(addr, &oldVal, 1);
                    100:                 if(!readCmd) {
                    101:                     result = kIOReturnNoMemory;
                    102:                     break;
                    103:                 }
                    104:                 readCmd->submit();
                    105:                 result = readCmd->fStatus;
                    106:                 readCmd->release();
                    107:                 readCmd = NULL;
                    108:                 if(kIOReturnSuccess != result) {
                    109:                     kprintf("read result 0x%x\n", result);
                    110:                     break;
                    111:                 }
                    112:             }
                    113:             do {
                    114:                if(claim)
                    115:                     newVal = oldVal - fBandwidth;
                    116:                else
                    117:                     newVal = oldVal + fBandwidth;
                    118:                if(irm) {
                    119:                     lockCmd = fControl->getIRMDevice()->createCompareAndSwapCommand(addr, &oldVal, &newVal, 1);
                    120:                     if(!lockCmd) {
                    121:                         result = kIOReturnNoMemory;
                    122:                         break;
                    123:                     }
                    124:                     lockCmd->submit();
                    125:                     if(kIOReturnSuccess != lockCmd->fStatus)
                    126:                         kprintf("bandwidth update result 0x%x\n", lockCmd->fStatus);
                    127:                     tryAgain = !lockCmd->locked(&oldVal);
                    128:                     lockCmd->release();
                    129:                     lockCmd = NULL;
                    130:                     if(tryAgain) {
                    131:                         kprintf("bandwidth update failed, newval 0x%x\n", oldVal);
                    132:                     }
                    133:                }
                    134:                else
                    135:                     tryAgain = false;
                    136:             } while (tryAgain);
                    137:             if(!claim)
                    138:                 fBandwidth = 0;
                    139:         }
                    140:         if(fChannel != 64 && (irm != NULL)) {
                    141:             UInt32 mask;
                    142:             if(fChannel <= 31) {
                    143:                 addr.addressLo = kCSRChannelsAvailable31_0;
                    144:                 mask = 1 << (31-fChannel);
                    145:             }
                    146:             else {
                    147:                 addr.addressLo = kCSRChannelsAvailable63_32;
                    148:                 mask = 1 << (63-fChannel);
                    149:             }
                    150:             readCmd = irm->createReadQuadCommand(addr, &oldVal, 1);
                    151:             if(!readCmd) {
                    152:                 result = kIOReturnNoMemory;
                    153:                 break;
                    154:             }
                    155:             readCmd->submit();
                    156:             result = readCmd->fStatus;
                    157:             if(kIOReturnSuccess != result) {
                    158:                 kprintf("read result 0x%x\n", result);
                    159:                 break;
                    160:             }
                    161:             do {
                    162:                 if(claim)
                    163:                     newVal = oldVal & ~mask;
                    164:                else
                    165:                     newVal = oldVal | mask;
                    166:                 lockCmd = irm->createCompareAndSwapCommand(addr, &oldVal, &newVal, 1);
                    167:                 if(!lockCmd) {
                    168:                     result = kIOReturnNoMemory;
                    169:                     break;
                    170:                 }
                    171:                 lockCmd->submit();
                    172:                 if(kIOReturnSuccess != lockCmd->fStatus)
                    173:                     kprintf("channel update result 0x%x\n", lockCmd->fStatus);
                    174:                 tryAgain = !lockCmd->locked(&oldVal);
                    175:                 lockCmd->release();
                    176:                 lockCmd = NULL;
                    177:                 if(tryAgain) {
                    178:                     kprintf("channel update failed, newval 0x%x\n", oldVal);
                    179:                 }
                    180:             } while (tryAgain);
                    181:             if(!claim)
                    182:                 fChannel = 64;
                    183:         }
                    184:     } while (false);
                    185:     if(readCmd)
                    186:         readCmd->release();
                    187:     if(lockCmd)
                    188:         lockCmd->release();
                    189:     return result;
                    190: }
                    191: 
                    192: IOReturn IOFWIsochChannel::allocateChannel()
                    193: {
                    194:     UInt64 portChans;
                    195:     UInt64 allowedChans, savedChans;
                    196:     IOFireWireDevice *irm;     // The Isochronous Resource Manager, if there is one
                    197:     IOFWReadQuadCommand *readCmd = NULL;
                    198:     IOFWCompareAndSwapCommand *lockCmd = NULL;
                    199:     UInt32 newVal;
                    200:     FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable);
                    201:     OSIterator *listenIterator;
                    202:     IOFWIsochPort *listen;
                    203:     IOFWSpeed portSpeed;
                    204:     UInt32 old[3];
                    205:     UInt32 bandwidth;
                    206:     UInt32 channel;
                    207:     bool tryAgain;     // For locks.
                    208:     IOReturn result = kIOReturnSuccess;
                    209: 
                    210:     // Get best speed, minimum of requested speed and paths from talker to each listener
                    211:     fSpeed = fPrefSpeed;
                    212: 
                    213:     do {
                    214:         // reduce speed to minimum of so far and what all ports can do,
                    215:         // and find valid channels
                    216:         allowedChans = (UInt64)-1;
                    217:         if(fTalker) {
                    218:             fTalker->getSupported(portSpeed, portChans);
                    219:             if(portSpeed < fSpeed)
                    220:                 fSpeed = portSpeed;
                    221:             allowedChans &= portChans;
                    222:         }
                    223:         listenIterator = OSCollectionIterator::withCollection(fListeners);
                    224:         if(listenIterator) {
                    225:             while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
                    226:                 listen->getSupported(portSpeed, portChans);
                    227:                 if(portSpeed < fSpeed)
                    228:                     fSpeed = portSpeed;
                    229:                 allowedChans &= portChans;
                    230:             }
                    231:         }
                    232: 
                    233:         // reserve bandwidth, allocate a channel
                    234:         if(fDoIRM && (irm = fControl->getIRMDevice())) {
                    235:             savedChans = allowedChans; // In case we have to try a few times
                    236:             // Careful of 32 bit overflow!
                    237:             bandwidth = fMBitSec / (1000 * (1 << fSpeed));
                    238:             bandwidth *= 6144;
                    239:             bandwidth /= 100000;
                    240:     //kprintf("Bandwidth is %d\n", bandwidth);
                    241:             readCmd = irm->createReadQuadCommand(addr, old, 3);
                    242:             if(!readCmd) {
                    243:                 result = kIOReturnNoMemory;
                    244:                 break;
                    245:             }
                    246:             readCmd->submit();
                    247:             result = readCmd->fStatus;
                    248:             if(kIOReturnSuccess != result) {
                    249:                kprintf("read result 0x%x\n", readCmd->fStatus);
                    250:                break;
                    251:             }
                    252:     //kprintf("Allocated Bandwidth is %d, channels are 0x%x 0x%x\n", old[0], old[1], old[2]);
                    253:             allowedChans &= old[1] | ((UInt64)old[2] << 32);
                    254: 
                    255:             // Claim bandwidth
                    256:             tryAgain = false;
                    257:             do {
                    258:                 if(old[0] < bandwidth) {
                    259:                     result = kIOReturnNoSpace;
                    260:                     break;
                    261:                 }
                    262:                 newVal = old[0] - bandwidth;
                    263:                 lockCmd = irm->createCompareAndSwapCommand(addr, &old[0], &newVal, 1);
                    264:                 if(!lockCmd) {
                    265:                     result = kIOReturnNoMemory;
                    266:                     break;
                    267:                 }
                    268:                 lockCmd->submit();
                    269:                 if(kIOReturnSuccess != lockCmd->fStatus)
                    270:                     kprintf("bandwith update result 0x%x\n", lockCmd->fStatus);
                    271:                 tryAgain = !lockCmd->locked(&old[0]);
                    272:                 lockCmd->release();
                    273:                 lockCmd = NULL;
                    274:                 if(tryAgain) {
                    275:                     kprintf("Bandwith lock failed, newval 0x%x\n", old[0]);
                    276:                }
                    277:             } while (tryAgain);
                    278:             if(kIOReturnSuccess != result)
                    279:                break;
                    280:             fBandwidth = bandwidth;
                    281:         }
                    282: 
                    283:         tryAgain = false;
                    284:         do {
                    285:             for(channel=0; channel<64; channel++) {
                    286:                 if(allowedChans & (1<<(63-channel))) {
                    287:                      break;
                    288:                 }
                    289:             }
                    290:             kprintf("using channel %d\n", channel);
                    291:             if(channel == 64) {
                    292:                 result = kIOReturnNoResources;
                    293:                 break;
                    294:             }
                    295: 
                    296:             // Allocate a channel
                    297:             if(fDoIRM && irm) {
                    298:                 UInt32 *oldPtr;
                    299:                 // Claim channel
                    300:                 if(channel < 32) {
                    301:                     addr.addressLo = kCSRChannelsAvailable31_0;
                    302:                     oldPtr = &old[1];
                    303:                     newVal = *oldPtr & ~(1<<(31-channel));
                    304:                }
                    305:                else {
                    306:                     addr.addressLo = kCSRChannelsAvailable63_32;
                    307:                     oldPtr = &old[2];
                    308:                     newVal = *oldPtr & ~(1<<(63-channel));
                    309:                }
                    310:                 lockCmd = irm->createCompareAndSwapCommand(addr, oldPtr, &newVal, 1);
                    311:                 if(!lockCmd) {
                    312:                     result = kIOReturnNoMemory;
                    313:                     break;
                    314:                 }
                    315:                 lockCmd->submit();
                    316:                 if(kIOReturnSuccess != lockCmd->fStatus)
                    317:                     kprintf("channel update result 0x%x\n", lockCmd->fStatus);
                    318:                 tryAgain = !lockCmd->locked(oldPtr);
                    319:                 lockCmd->release();
                    320:                 lockCmd = NULL;
                    321:                 if(tryAgain) {
                    322:                     kprintf("channel update failed, newval 0x%x\n", old[0]);
                    323:                 }
                    324:             }
                    325:             else
                    326:                tryAgain = false;
                    327:         } while (tryAgain);
                    328:         if(kIOReturnSuccess != result)
                    329:             break;
                    330:         fChannel = channel;
                    331:         if(fDoIRM)
                    332:             fControl->addAllocatedChannel(this);
                    333: 
                    334:         // allocate hardware resources for each port
                    335:         if(listenIterator) {
                    336:             listenIterator->reset();
                    337:             while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
                    338:                 listen->allocatePort(fSpeed, fChannel);
                    339:             }
                    340:             listenIterator->release();
                    341:         }
                    342:         if(fTalker)
                    343:             fTalker->allocatePort(fSpeed, fChannel);
                    344:     } while (false);
                    345: 
                    346:     if(readCmd)
                    347:        readCmd->release();
                    348:     if(lockCmd)
                    349:         lockCmd->release();
                    350: 
                    351:     return result;
                    352: }
                    353: 
                    354: 
                    355: IOReturn IOFWIsochChannel::releaseChannel()
                    356: {
                    357:     OSIterator *listenIterator;
                    358:     IOFWIsochPort *listen;
                    359:     IOReturn result;
                    360: 
                    361:     if(fTalker) {
                    362:         fTalker->releasePort();
                    363:     }
                    364:     listenIterator = OSCollectionIterator::withCollection(fListeners);
                    365:     if(listenIterator) {
                    366:         while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
                    367:             listen->releasePort();
                    368:         }
                    369:         listenIterator->release();
                    370:     }
                    371: 
                    372:     // release bandwidth and channel
                    373:     if(fDoIRM) {
                    374:         /*
                    375:          * Tell the controller that we don't need to know about
                    376:          * bus resets bedore doing anything else, since a bus reset
                    377:          * sets us into the state we want (no allocated bandwidth).
                    378:          */
                    379:         fControl->removeAllocatedChannel(this);
                    380:        updateBandwidth(false);
                    381:     }
                    382:     return kIOReturnSuccess;
                    383: }
                    384: 
                    385: void IOFWIsochChannel::reallocBandwidth()
                    386: {
                    387:     kprintf("reallocBandwidth\n");
                    388:     updateBandwidth(true);
                    389: }
                    390: 
                    391: void IOFWIsochChannel::handleBusReset()
                    392: {
                    393:     kprintf("handleBusReset\n");
                    394:     thread_call_func(threadFunc, this, true);
                    395: }
                    396: 
                    397: IOReturn IOFWIsochChannel::start()
                    398: {
                    399:     OSIterator *listenIterator;
                    400:     IOFWIsochPort *listen;
                    401: 
                    402:     // Start all listeners, then start the talker
                    403:     listenIterator = OSCollectionIterator::withCollection(fListeners);
                    404:     if(listenIterator) {
                    405:         listenIterator->reset();
                    406:         while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
                    407:             listen->start();
                    408:         }
                    409:         listenIterator->release();
                    410:     }
                    411:     if(fTalker)
                    412:        fTalker->start();
                    413: 
                    414:     return kIOReturnSuccess;
                    415: }
                    416: 
                    417: IOReturn IOFWIsochChannel::stop()
                    418: {
                    419:     OSIterator *listenIterator;
                    420:     IOFWIsochPort *listen;
                    421: 
                    422:     // Stop all listeners, then stop the talker
                    423:     listenIterator = OSCollectionIterator::withCollection(fListeners);
                    424:     if(listenIterator) {
                    425:          while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
                    426:             listen->stop();
                    427:         }
                    428:         listenIterator->release();
                    429:     }
                    430:     if(fTalker)
                    431:        fTalker->stop();
                    432: 
                    433:     return kIOReturnSuccess;
                    434: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.