Annotation of XNU/iokit/Families/IOFireWire/IOFWIsochChannel.cpp, revision 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.