|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.