1/* 2 * Copyright (c) 1998-2002 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-2002 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/IOFWLocalIsochPort.h> 33#include <IOKit/firewire/IOFWCommand.h> 34#include <IOKit/firewire/IOFireWireDevice.h> 35#import <IOKit/firewire/IOFWDCLProgram.h> 36#import <IOKit/firewire/IOFireWireLink.h> 37 38#include <libkern/c++/OSSet.h> 39#include <libkern/c++/OSCollectionIterator.h> 40#include "FWDebugging.h" 41 42#include <IOKit/firewire/IOFWUtils.h> 43 44OSDefineMetaClassAndStructors(IOFWIsochChannel, OSObject) 45OSMetaClassDefineReservedUnused(IOFWIsochChannel, 0); 46OSMetaClassDefineReservedUnused(IOFWIsochChannel, 1); 47OSMetaClassDefineReservedUnused(IOFWIsochChannel, 2); 48OSMetaClassDefineReservedUnused(IOFWIsochChannel, 3); 49 50#pragma mark - 51////////////////////////////////////////////////////////////////////////////////////////// 52 53// init 54// 55// 56 57bool IOFWIsochChannel::init( IOFireWireController * control, 58 bool doIRM, 59 UInt32 packetSize, 60 IOFWSpeed prefSpeed, 61 ForceStopNotificationProc * stopProc, 62 void * stopRefCon ) 63{ 64 bool success = true; 65 66 FWKLOG(( "IOFWIsochChannel::init - doIRM = %d\n", doIRM )); 67 68 DebugLog("fPacketSize = %d\n", (uint32_t)packetSize) ; 69 70 success = OSObject::init(); 71 72 if( success ) 73 { 74 fControl = control; 75 fDoIRM = doIRM; 76 fPacketSize = packetSize; 77 fPrefSpeed = prefSpeed; 78 fStopProc = stopProc; 79 fStopRefCon = stopRefCon; 80 fTalker = NULL; 81 82 fChannel = 64; // no channel allocated, 64 is an illegal channel 83 fBandwidth = 0; // no bandwidth allocated 84 85 // Bandwidth allocation is not done on the main FireWire workloop so 86 // we need to allocate a lock for synchronizing access to the resources 87 // used in bandwidth allocation 88 89 fLock = IOLockAlloc(); 90 if( fLock == NULL ) 91 { 92 success = false; 93 } 94 } 95 96 if( success ) 97 { 98 fListeners = OSSet::withCapacity( 1 ); 99 if( fListeners == NULL ) 100 { 101 success = false; 102 } 103 } 104 105 // 106 // create command for reading bandwidth available and channel available register 107 // 108 109 if( success ) 110 { 111 fReadCmd = OSTypeAlloc( IOFWReadQuadCommand ); 112 if( fReadCmd == NULL ) 113 { 114 success = false; 115 } 116 } 117 118 if( success ) 119 { 120 fReadCmd->initAll( fControl, 0, FWAddress(), NULL, 0, NULL, NULL ); 121 } 122 123 // 124 // create lock cmd for updating the bandwidth available and channel available registers 125 // 126 127 if( success ) 128 { 129 fLockCmd = OSTypeAlloc( IOFWCompareAndSwapCommand ); 130 if( fLockCmd == NULL ) 131 { 132 success = false; 133 } 134 } 135 136 if( success ) 137 { 138 fLockCmd->initAll( fControl, 0, FWAddress(), NULL, NULL, 0, NULL, NULL ); 139 } 140 141 return success; 142} 143 144// free 145// 146// 147 148void IOFWIsochChannel::free() 149{ 150 if( fListeners ) 151 { 152 fListeners->release(); 153 fListeners = NULL; 154 } 155 156 if( fReadCmd ) 157 { 158 fReadCmd->release(); 159 fReadCmd = NULL; 160 } 161 162 if( fLockCmd ) 163 { 164 fLockCmd->release(); 165 fLockCmd = NULL; 166 } 167 168 if( fLock ) 169 { 170 IOLockFree( fLock ); 171 fLock = NULL; 172 } 173 174 OSObject::free(); 175} 176 177#pragma mark - 178////////////////////////////////////////////////////////////////////////////////////////// 179 180// checkMemoryInRange 181// 182// 183 184IOReturn IOFWIsochChannel::checkMemoryInRange( IOMemoryDescriptor * memory ) 185{ 186 IOReturn status = kIOReturnSuccess; 187 188 if( memory == NULL ) 189 { 190 status = kIOReturnBadArgument; 191 } 192 193 // 194 // setup 195 // 196 197 bool memory_prepared = false; 198 if( status == kIOReturnSuccess ) 199 { 200 status = memory->prepare( kIODirectionInOut ); 201 } 202 203 if( status == kIOReturnSuccess ) 204 { 205 memory_prepared = true; 206 } 207 208 UInt64 length = 0; 209 if( status == kIOReturnSuccess ) 210 { 211 length = memory->getLength(); 212 if( length == 0 ) 213 { 214 status = kIOReturnError; 215 } 216 } 217 218 // 219 // create IODMACommand 220 // 221 222 IODMACommand * dma_command = NULL; 223 if( status == kIOReturnSuccess ) 224 { 225 dma_command = IODMACommand::withSpecification( 226 kIODMACommandOutputHost64, // segment function 227 64, // max address bits 228 length, // max segment size 229 (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly), // IO mapped & don't bounce buffer 230 length, // max transfer size 231 0, // page alignment 232 NULL, // mapper 233 NULL ); // refcon 234 if( dma_command == NULL ) 235 status = kIOReturnError; 236 237 } 238 239 if( status == kIOReturnSuccess ) 240 { 241 // set memory descriptor and don't prepare it 242 status = dma_command->setMemoryDescriptor( memory, false ); 243 } 244 245 bool dma_command_prepared = false; 246 if( status == kIOReturnSuccess ) 247 { 248 status = dma_command->prepare( 0, length, true ); 249 } 250 251 if( status == kIOReturnSuccess ) 252 { 253 dma_command_prepared = true; 254 } 255 256 // 257 // check ranges 258 // 259 260 if( status == kIOReturnSuccess ) 261 { 262 UInt64 offset = 0; 263 UInt64 mask = fControl->getFireWirePhysicalAddressMask(); 264 while( (offset < length) && (status == kIOReturnSuccess) ) 265 { 266 IODMACommand::Segment64 segments[10]; 267 UInt32 num_segments = 10; 268 status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments ); 269 if( status == kIOReturnSuccess ) 270 { 271 for( UInt32 i = 0; i < num_segments; i++ ) 272 { 273 // IOLog( "checkSegments - segments[%d].fIOVMAddr = 0x%016llx, fLength = %d\n", i, segments[i].fIOVMAddr, segments[i].fLength ); 274 275 if( (segments[i].fIOVMAddr & (~mask)) ) 276 { 277 // IOLog( "checkSegmentsFailed - 0x%016llx & 0x%016llx\n", segments[i].fIOVMAddr, mask ); 278 status = kIOReturnNotPermitted; 279 break; 280 } 281 } 282 } 283 } 284 } 285 286 // 287 // clean up 288 // 289 290 if( dma_command_prepared ) 291 { 292 dma_command->complete(); 293 dma_command_prepared = false; 294 } 295 296 if( dma_command ) 297 { 298 dma_command->clearMemoryDescriptor(); 299 dma_command->release(); 300 dma_command = NULL; 301 } 302 303 if( memory_prepared ) 304 { 305 memory->complete(); 306 memory_prepared = false; 307 } 308 309 return status; 310 311} 312 313// setTalker 314// 315// 316 317IOReturn IOFWIsochChannel::setTalker( IOFWIsochPort *talker ) 318{ 319 IOReturn error = kIOReturnSuccess; 320 fTalker = talker; 321 322 IOFWLocalIsochPort * localIsochPort = OSDynamicCast( IOFWLocalIsochPort, talker ); 323 if ( localIsochPort ) 324 { 325 IODCLProgram * program = localIsochPort->getProgramRef(); 326 IOMemoryMap * map = program->getBufferMap(); 327 if( map == NULL ) 328 { 329 error = kIOReturnNoMemory; 330 } 331 332 IOMemoryDescriptor * memory = NULL; 333 if( error == kIOReturnSuccess ) 334 { 335 memory = map->getMemoryDescriptor(); 336 if( memory == NULL ) 337 { 338 error = kIOReturnNoMemory; 339 } 340 } 341 342#if 0 343 if( error == kIOReturnSuccess ) 344 { 345 error = checkMemoryInRange( memory ); 346 } 347#endif 348 349 if( error == kIOReturnSuccess ) 350 { 351 352 program->setForceStopProc( fStopProc, fStopRefCon, this ); 353 program->release(); 354 } 355 } 356 357 return error; 358} 359 360// addListener 361// 362// 363 364IOReturn IOFWIsochChannel::addListener( IOFWIsochPort *listener ) 365{ 366 IOReturn error = kIOReturnSuccess; 367 368 if( !fListeners->setObject( listener ) ) 369 { 370 error = kIOReturnNoMemory; 371 } 372 373 if ( !error ) 374 { 375 IOFWLocalIsochPort * localIsochPort = OSDynamicCast( IOFWLocalIsochPort, listener ) ; 376 if ( localIsochPort ) 377 { 378 IODCLProgram * program = localIsochPort->getProgramRef(); 379 IOMemoryMap * map = program->getBufferMap(); 380 if( map == NULL ) 381 { 382 error = kIOReturnNoMemory; 383 } 384 385 IOMemoryDescriptor * memory = NULL; 386 if( error == kIOReturnSuccess ) 387 { 388 memory = map->getMemoryDescriptor(); 389 if( memory == NULL ) 390 { 391 error = kIOReturnNoMemory; 392 } 393 } 394 395 if( error == kIOReturnSuccess ) 396 { 397 error = checkMemoryInRange( memory ); 398 } 399 400 if( error == kIOReturnSuccess ) 401 { 402 program->setForceStopProc( fStopProc, fStopRefCon, this ) ; 403 program->release() ; 404 } 405 } 406 } 407 408 return error ; 409} 410 411// start 412// 413// 414 415IOReturn IOFWIsochChannel::start() 416{ 417 DebugLog("channel %p start\n", this ) ; 418 419 OSIterator *listenIterator; 420 IOFWIsochPort *listen; 421 IOReturn error = kIOReturnSuccess ; 422 423 // <rdar://problem/4033119> 424 // the user requested doIRM, but we don't have an allocation.. 425 // they should have called allocateChannel()... 426 if ( fDoIRM && fChannel == 64 ) 427 { 428 return kIOReturnNotReady ; 429 } 430 431 // 432 // start all listeners 433 // 434 435 listenIterator = OSCollectionIterator::withCollection( fListeners ); 436 if( listenIterator ) 437 { 438 listenIterator->reset(); 439 while( !error && (listen = (IOFWIsochPort *)listenIterator->getNextObject()) ) 440 { 441 error = listen->start(); 442 } 443 listenIterator->release(); 444 } 445 446 // 447 // start the talker 448 // 449 450 if( !error && fTalker ) 451 { 452 error = fTalker->start(); 453 } 454 455 if (error) 456 { 457 DebugLog("channel %p start - error=%x\n", this, error ) ; 458 459 } 460 else 461 { 462 DebugLog("channel %p start - started on isoch channel %d\n", this, (uint32_t)fChannel ) ; 463 } 464 465 return error ; 466} 467 468// stop 469// 470// 471 472IOReturn IOFWIsochChannel::stop() 473{ 474 DebugLog("channel %p stop\n", this ) ; 475 476 OSIterator *listenIterator; 477 IOFWIsochPort *listen; 478 479 // 480 // stop all listeners 481 // 482 483 listenIterator = OSCollectionIterator::withCollection( fListeners ); 484 if( listenIterator ) 485 { 486 listenIterator->reset(); 487 while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) ) 488 { 489 listen->stop(); 490 } 491 listenIterator->release(); 492 } 493 494 // 495 // stop talker 496 // 497 498 if( fTalker ) 499 { 500 fTalker->stop(); 501 } 502 503 return kIOReturnSuccess; 504} 505 506#pragma mark - 507////////////////////////////////////////////////////////////////////////////////////////// 508 509// allocateChannel 510// 511// cannot be called on the workloop 512 513IOReturn IOFWIsochChannel::allocateChannel() 514{ 515 DebugLog("channel %p allocateChannel\n", this ) ; 516 517 IOReturn status = kIOReturnSuccess; 518 519 IOFWIsochPort * listen = NULL; 520 OSIterator * listenIterator = NULL; 521 522 // 523 // get best speed and find supported channels 524 // 525 526 if( status == kIOReturnSuccess ) 527 { 528 UInt64 portChans; 529 IOFWSpeed portSpeed; 530 UInt64 allowedChans; 531 IOFWSpeed speed; 532 533 // Find minimum of requested speed and paths from talker to each listener 534 // Reduce speed to minimum of what all ports can do, find supported channels 535 536 speed = fPrefSpeed; 537 538 // 539 // get supported channels and max speed from talker 540 // 541 542 allowedChans = ~(UInt64)0; 543 if( fTalker ) 544 { 545 fTalker->getSupported( portSpeed, portChans ); 546 if( portSpeed < speed ) 547 { 548 speed = portSpeed; 549 } 550 allowedChans &= portChans; 551 } 552 553 // 554 // get supported channels and max speed from all listeners 555 // 556 557 listenIterator = OSCollectionIterator::withCollection( fListeners ); 558 if( listenIterator ) 559 { 560 while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) ) 561 { 562 listen->getSupported( portSpeed, portChans ); 563 if( portSpeed < speed ) 564 { 565 speed = portSpeed; 566 } 567 allowedChans &= portChans; 568 } 569 } 570 571 // 572 // do bandwidth and channel allocation 573 // 574 575 // allocateChannelBegin sets up fSpeed, fGeneration, fBandwidth, and fChannel 576 577 status = allocateChannelBegin( speed, allowedChans ); 578 } 579 580 // 581 // allocate hardware resources for all listeners 582 // 583 584 if( status == kIOReturnSuccess ) 585 { 586 if( listenIterator ) 587 { 588 listenIterator->reset(); 589 while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) && 590 (status == kIOReturnSuccess) ) 591 { 592 status = listen->allocatePort( fSpeed, fChannel ); 593 } 594 } 595 } 596 597 // 598 // allocate hardware resources for talker 599 // 600 601 if( status == kIOReturnSuccess ) 602 { 603 if( fTalker ) 604 { 605 status = fTalker->allocatePort( fSpeed, fChannel ); 606 } 607 } 608 609 // 610 // clean up 611 // 612 613 if( listenIterator ) 614 { 615 listenIterator->release(); 616 } 617 618 if( status != kIOReturnSuccess ) 619 { 620 // on error release anything we may have allocated 621 622 releaseChannel(); 623 } 624 625 return status; 626} 627 628// allocateChannelBegin 629// 630// cannot be called on the workloop 631 632IOReturn IOFWIsochChannel::allocateChannelBegin( IOFWSpeed inSpeed, 633 UInt64 inAllowedChans, 634 UInt32 * outChannel ) 635{ 636 DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - entered, inSpeed = %d, fDoIRM = %d, inAllowedChans = 0x%016llx, fChannel=%d, fBandwidth=%d\n", this, inSpeed, fDoIRM, inAllowedChans, (uint32_t)fChannel, (uint32_t)fBandwidth ); 637 638 IOReturn status = kIOReturnSuccess; 639 640 IOLockLock( fLock ); 641 642 fSpeed = ( inSpeed == kFWSpeedMaximum ) ? fControl->getLink()->getPhySpeed() : inSpeed ; 643 644 if( fDoIRM ) 645 { 646 UInt32 oldIRM[3]; 647 648 // reserve bandwidth: 649 // bandwidth is in units of quads at 1600 Mbs 650 UInt32 bandwidth = 0; 651 if( fPacketSize != 0 ) 652 { 653 bandwidth = (fPacketSize/4 + 3) * 16 / (1 << inSpeed); 654 } 655 656 do 657 { 658 FWAddress addr ; 659 UInt32 generation ; 660 661 status = kIOReturnSuccess ; 662 663 // 664 // get IRM nodeID into addr.nodeID 665 // 666 667 fControl->getIRMNodeID( generation, addr.nodeID ); 668 669 DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - generation %d\n", this, (uint32_t)generation ); 670 671 // 672 // Make sure we're at least one second from the last bus-reset 673 // 674 675 { 676 unsigned delayRetries = 15; 677 while (delayRetries > 0) 678 { 679 UInt32 currentGeneration; 680 AbsoluteTime currentUpTime; 681 UInt64 nanos; 682 UInt32 delayInMSec; 683 684 IOFWGetAbsoluteTime( & currentUpTime ); 685 SUB_ABSOLUTETIME( & currentUpTime, fControl->getResetTime() ) ; 686 absolutetime_to_nanoseconds( currentUpTime, & nanos ) ; 687 if (nanos < 1000000000LL) 688 { 689 delayInMSec = (UInt32) ((1000000000LL - nanos)/1000000LL); 690 691 DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - delaying for %d msec\n", this, (uint32_t)delayInMSec); 692 693 // Delay until it's been one second from last bus-reset 694 IOSleep(delayInMSec); 695 696 // get generation 697 fControl->getIRMNodeID( currentGeneration, addr.nodeID ); 698 if (currentGeneration == generation) 699 { 700 break; 701 } 702 else 703 { 704 generation = currentGeneration; // Another bus-reset occurred, do the delay check again 705 } 706 } 707 else 708 { 709 break; 710 } 711 712 delayRetries--; 713 } 714 715 // Make sure we didn't use all the delay retries 716 if (delayRetries == 0) 717 { 718 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - timed out waiting for bus resets to end\n", this) ; 719 status = kIOReturnTimeout; 720 } 721 } 722 723 if( status == kIOReturnSuccess ) 724 { 725 // read IRM into oldIRM[3] (up to 5 retries) ; 726 727 addr.addressHi = kCSRRegisterSpaceBaseAddressHi ; 728 addr.addressLo = kCSRBandwidthAvailable ; 729 730 fReadCmd->reinit( generation, addr, oldIRM, 3 ); 731 fReadCmd->setMaxPacket( 4 ); // many cameras don't like block reads to IRM registers, eg. Canon GL-1 732 733 status = fReadCmd->submit(); 734 735 DebugLogCond( status, "IOFWIsochChannel<%p>::allocateChannelBegin() line %u - read command got error 0x%x\n", this, __LINE__, status ) ; 736 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - oldIRM set to %08x %08x %08x\n", this, 737 OSSwapBigToHostInt32(oldIRM[0]), OSSwapBigToHostInt32(oldIRM[1]), OSSwapBigToHostInt32(oldIRM[2]) ) ; 738 } 739 740 // 741 // Claim bandwidth from IRM 742 // 743 744 if ( fBandwidth == 0 ) 745 { 746 UInt32 old_bandwidth = OSSwapBigToHostInt32( oldIRM[0] ); 747 if( ( status == kIOReturnSuccess ) && ( old_bandwidth < bandwidth ) ) 748 { 749 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - no bandwidth left\n", this) ; 750 status = kIOReturnNoSpace; 751 } 752 753 if( status == kIOReturnSuccess ) 754 { 755 UInt32 newVal = OSSwapHostToBigInt32(old_bandwidth - bandwidth); 756 757 fLockCmd->reinit( generation, addr, &oldIRM[0], &newVal, 1 ); 758 759 status = fLockCmd->submit(); 760 761 if ( status ) 762 { 763 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() line %u - lock command got error 0x%x\n", this, __LINE__, status ) ; 764 } 765 else 766 { 767 if ( !fLockCmd->locked( &oldIRM[0] ) ) 768 { 769 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - lock for bandwidth failed\n", this) ; 770 status = kIOReturnCannotLock; 771 } 772 } 773 774 if( status == kIOReturnSuccess ) 775 { 776 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - allocated bandwidth %u\n", this, (uint32_t)bandwidth) ; 777 778 fBandwidth = bandwidth; 779 } 780 } 781 } 782 783 // 784 // claim channel from IRM 785 // 786 787 // (if we have an error here, the bandwidth wasn't allocated) 788 if ( status == kIOReturnSuccess && fChannel == 64 ) 789 { 790 unsigned channel ; 791 792 UInt32 old_channel_hi = OSSwapBigToHostInt32( oldIRM[1] ); 793 UInt32 old_channel_lo = OSSwapBigToHostInt32( oldIRM[2] ); 794 795 // mask inAllowedChans by channels IRM has available 796 inAllowedChans &= (UInt64)(old_channel_lo) | ((UInt64)old_channel_hi << 32); 797 798 for( channel = 0; channel < 64; ++channel ) 799 { 800 if( inAllowedChans & ((UInt64)1 << (63 - channel)) ) 801 { 802 break; 803 } 804 } 805 806 if( channel == 64 ) 807 { 808 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - no acceptable free channels\n", this) ; 809 status = kIOReturnNoResources; 810 } 811 812 if( status == kIOReturnSuccess ) 813 { 814 UInt32 * oldPtr; 815 UInt32 newVal ; 816 817 // Claim channel 818 if( channel < 32 ) 819 { 820 addr.addressLo = kCSRChannelsAvailable31_0; 821 oldPtr = &oldIRM[1]; 822 newVal = OSSwapHostToBigInt32( old_channel_hi & ~(1<<(31 - channel)) ); 823 } 824 else 825 { 826 addr.addressLo = kCSRChannelsAvailable63_32; 827 oldPtr = &oldIRM[2]; 828 newVal = OSSwapHostToBigInt32( old_channel_lo & ~(1 << (63 - channel)) ); 829 } 830 831 fLockCmd->reinit( generation, addr, oldPtr, &newVal, 1 ); 832 status = fLockCmd->submit(); 833 834 if ( status ) 835 { 836 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - lock command got error 0x%x\n", this, status ) ; 837 } 838 else 839 { 840 if( !fLockCmd->locked(oldPtr) ) 841 { 842 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - couldn't claim channel %u\n", this, channel) ; 843 status = kIOReturnCannotLock; 844 } 845 } 846 } 847 848 if( status == kIOReturnSuccess ) 849 { 850 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - allocated channel %u\n", this, channel) ; 851 852 fChannel = channel; 853 if( outChannel != NULL ) 854 { 855 *outChannel = channel; 856 } 857 } 858 else if ( fBandwidth != 0 ) 859 { 860 // Release the bandwidth we allocated, since we did not get the channel 861 fControl->releaseIRMBandwidthInGeneration(fBandwidth, generation); 862 } 863 } 864 865 if( status == kIOReturnSuccess ) 866 { 867 fGeneration = generation; 868 869 // tell controller we would like to hear about bus resets 870 fControl->addAllocatedChannel(this); 871 } 872 873 if( status == kIOFireWireBusReset ) 874 { 875 // we lost any allocations if there was a bus reset 876 fBandwidth = 0; 877 fChannel = 64; 878 } 879 880 } while( (status == kIOFireWireBusReset) || (status == kIOReturnCannotLock) ); 881 } 882 else 883 { 884 // 885 // return a channel even if we aren't doing the IRM management 886 // 887 888 unsigned channel ; 889 890 { 891 for( channel = 0; channel < 64; channel++ ) 892 { 893 if( inAllowedChans & ((UInt64)1 << (63 - channel)) ) 894 { 895 break; 896 } 897 } 898 899 if( channel == 64 ) 900 { 901 DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - couldn't find acceptable channel\n", this) ; 902 status = kIOReturnNoResources; 903 } 904 } 905 906 if( status == kIOReturnSuccess ) 907 { 908 DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - allocated channel = %d\n", this, channel ); 909 910 fChannel = channel; 911 if( outChannel != NULL ) 912 { 913 *outChannel = channel; 914 } 915 } 916 } 917 918 IOLockUnlock( fLock ); 919 920 FWTrace( kFWTIsoch, kTPIsochAllocateChannelBegin, (uintptr_t)(fControl->getLink()), fChannel, fBandwidth, status ); 921 DebugLogCond( status, "IOFWIsochChannel<%p>::allocateChannelBegin() - exited with status = 0x%x\n", this, status ); 922 923 return status; 924} 925 926// ChannelThreadInfo 927// 928// A little struct for keeping track of our this pointer and generation 929// when transitioning to a second thread during bandwidth reallocation. 930 931struct ChannelThreadInfo 932{ 933 IOFWIsochChannel * fChannel; 934 UInt32 fGeneration; 935}; 936 937// handleBusReset 938// 939// 940 941void IOFWIsochChannel::handleBusReset() 942{ 943 // 944 // setup thread info and spawn a thread 945 // 946 947 ChannelThreadInfo * threadInfo = (ChannelThreadInfo *)IOMalloc( sizeof(ChannelThreadInfo) ); 948 if( threadInfo ) 949 { 950 threadInfo->fGeneration = fControl->getGeneration(); 951 threadInfo->fChannel = this; 952 retain(); // retain ourself for the thread to use 953 954 thread_t thread; 955 if( kernel_thread_start((thread_continue_t)threadFunc, threadInfo, &thread ) == KERN_SUCCESS ) 956 { 957 thread_deallocate(thread); 958 } 959 } 960} 961 962// threadFunc 963// 964// 965 966void IOFWIsochChannel::threadFunc( void * arg ) 967{ 968 // 969 // extract info from thread info 970 // 971 972 ChannelThreadInfo * threadInfo = (ChannelThreadInfo *)arg; 973 IOFWIsochChannel * channel = threadInfo->fChannel; 974 UInt32 generation = threadInfo->fGeneration; 975 976 // 977 // realloc bandwidth 978 // 979 980 channel->reallocBandwidth( generation ); 981 982 // 983 // clean up thread info 984 // 985 986 IOFree( threadInfo, sizeof(threadInfo) ); 987 channel->release(); // retain occurred in handleBusReset 988} 989 990// reallocBandwidth 991// 992// cannot be called on the workloop 993 994void IOFWIsochChannel::reallocBandwidth( UInt32 generation ) 995{ 996 IOReturn result = kIOReturnSuccess; 997 998 FWAddress addr( kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable ); 999 1000 IOLockLock( fLock ); 1001 1002 InfoLog( "IOFWIsochChannel<%p>::reallocBandwidth() - bandwidth %ld, channel = %ld\n", this, fBandwidth, fChannel ); 1003 1004 if( result == kIOReturnSuccess ) 1005 { 1006 UInt32 current_generation; 1007 UInt16 irm; 1008 fControl->getIRMNodeID( current_generation, irm ); 1009 addr.nodeID = irm; 1010 if( current_generation != generation ) 1011 { 1012 result = kIOFireWireBusReset; 1013 } 1014 1015// FWKLOG(( "IOFWIsochChannel::reallocBandwidth - realloc generation %d, current generation = %d\n", generation, current_generation )); 1016 } 1017 1018 if( result == kIOReturnSuccess ) 1019 { 1020 // check to make sure we don't allocate twice on a generation 1021 1022 if( fGeneration == generation ) 1023 { 1024 result = kIOReturnError; 1025 } 1026 } 1027 1028 // 1029 // reallocate bandwidth 1030 // 1031 1032 if( fBandwidth != 0 ) 1033 { 1034 UInt32 oldVal = 0; 1035 1036 // 1037 // read the bandwidth available register 1038 // 1039 1040 if( result == kIOReturnSuccess ) 1041 { 1042 fReadCmd->reinit( generation, addr, &oldVal, 1 ); 1043 result = fReadCmd->submit(); 1044 } 1045 1046 // 1047 // compare swap loop 1048 // 1049 1050 bool done = false; 1051 while( (result == kIOReturnSuccess) && !done ) 1052 { 1053 UInt32 newVal = 0; 1054 UInt32 old_bandwidth = OSSwapBigToHostInt32( oldVal ); 1055 1056 // make sure there's space 1057 if( old_bandwidth < fBandwidth ) 1058 { 1059 result = kIOReturnNoSpace; 1060 } 1061 1062 if( result == kIOReturnSuccess ) 1063 { 1064 newVal = OSSwapHostToBigInt32(old_bandwidth - fBandwidth); 1065 1066 fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 ); 1067 result = fLockCmd->submit(); 1068 } 1069 1070 if( result == kIOReturnSuccess ) 1071 { 1072 done = fLockCmd->locked(&oldVal); 1073 } 1074 } 1075 1076 if( result == kIOReturnNoSpace ) 1077 { 1078 DebugLog( "IOFWIsochChannel<%p>::reallocBandwidth() - failed to reallocate bandwidth = %d, channel = %d\n", this, (uint32_t)fBandwidth, (uint32_t)fChannel ); 1079 1080 // Couldn't reallocate bandwidth! 1081 fBandwidth = 0; 1082 fChannel = 64; // this will keep us from reallocating the channel 1083 } 1084 else 1085 { 1086 InfoLog( "IOFWIsochChannel<%p>::reallocBandwidth() - reallocated bandwidth = %ld\n", this, fBandwidth ); 1087 } 1088 } 1089 1090 // 1091 // reallocate channel 1092 // 1093 1094 if( fChannel != 64 ) 1095 { 1096 UInt32 mask = 0; 1097 UInt32 oldVal = 0; 1098 1099 // 1100 // read the channels available register 1101 // 1102 1103 if( result == kIOReturnSuccess ) 1104 { 1105 if( fChannel <= 31 ) 1106 { 1107 addr.addressLo = kCSRChannelsAvailable31_0; 1108 mask = 1 << (31-fChannel); 1109 } 1110 else 1111 { 1112 addr.addressLo = kCSRChannelsAvailable63_32; 1113 mask = 1 << (63-fChannel); 1114 } 1115 1116 fReadCmd->reinit( generation, addr, &oldVal, 1 ); 1117 result = fReadCmd->submit(); 1118 } 1119 1120 // 1121 // compare swap loop 1122 // 1123 1124 bool done = false; 1125 while( (result == kIOReturnSuccess) && !done ) 1126 { 1127 UInt32 old_channels_avail = OSSwapBigToHostInt32( oldVal ); 1128 UInt32 newVal = OSSwapHostToBigInt32( old_channels_avail & ~mask ); 1129 if( newVal == oldVal ) 1130 { 1131 // Channel already allocated! 1132 result = kIOFireWireChannelNotAvailable ; 1133 } 1134 1135 if( result == kIOReturnSuccess ) 1136 { 1137 fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 ); 1138 result = fLockCmd->submit(); 1139 } 1140 1141 if( result == kIOReturnSuccess ) 1142 { 1143 done = fLockCmd->locked( &oldVal ); 1144 } 1145 } 1146 1147 if( result == kIOFireWireChannelNotAvailable ) 1148 { 1149 DebugLog( "IOFWIsochChannel<%p>::reallocBandwidth() - failed to reallocate channel = %d\n", this, (uint32_t)fChannel ); 1150 1151 // Couldn't reallocate the channel 1152 fChannel = 64; 1153 // fBandwidth will be set to 0 once it is released in the call to releaseChannel below 1154 } 1155 else 1156 { 1157 InfoLog( "IOFWIsochChannel<%p>::reallocBandwidth() - reallocated channel = %ld\n", this, fChannel ); 1158 } 1159 } 1160 1161 fGeneration = generation; 1162 1163 FWTrace( kFWTIsoch, kTPIsochReallocBandwidth, (uintptr_t)(fControl->getLink()), fChannel, fBandwidth, result ); 1164 DebugLogCond( result, "IOFWIsochChannel<%p>::reallocBandwidth() - exited with result = 0x%x\n", this, result ); 1165 1166 IOLockUnlock( fLock ); 1167 1168 if( result == kIOReturnNoSpace || result == kIOFireWireChannelNotAvailable ) 1169 { 1170 // Couldn't reallocate bandwidth or channel 1171 1172 stop(); 1173 1174 // fChannel and fBandwidth have been left in such a way that releaseChannel() 1175 // will know to release both, one, or none 1176 1177 releaseChannel(); 1178 1179 if ( fStopProc ) 1180 { 1181 (*fStopProc)( fStopRefCon, this, kIOFireWireChannelNotAvailable ); 1182 } 1183 } 1184 1185} 1186 1187// releaseChannel 1188// 1189// 1190 1191IOReturn IOFWIsochChannel::releaseChannel() 1192{ 1193 DebugLog("IOFWIsochChannel<%p>::releaseChannel()\n", this ) ; 1194 1195 OSIterator *listenIterator; 1196 IOFWIsochPort *listen; 1197 1198 if( fTalker ) 1199 { 1200 fTalker->releasePort(); 1201 } 1202 1203 listenIterator = OSCollectionIterator::withCollection(fListeners); 1204 if( listenIterator ) 1205 { 1206 while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) ) 1207 { 1208 listen->releasePort(); 1209 } 1210 listenIterator->release(); 1211 } 1212 1213 return releaseChannelComplete(); 1214} 1215 1216// releaseChannelComplete 1217// 1218// 1219 1220IOReturn IOFWIsochChannel::releaseChannelComplete() 1221{ 1222 IOReturn result = kIOReturnSuccess; 1223 1224 // release bandwidth and channel 1225 1226 FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - entered, fDoIRM = %d\n", fDoIRM )); 1227 1228 if( fDoIRM ) 1229 { 1230 FWAddress addr( kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable ); 1231 UInt32 generation = 0; 1232 1233 IOLockLock( fLock ); 1234 1235 // 1236 // Tell the controller that we don't need to know about 1237 // bus resets before doing anything else, since a bus reset 1238 // sets us into the state we want (no allocated bandwidth). 1239 // 1240 1241 if( result == kIOReturnSuccess ) 1242 { 1243 fControl->removeAllocatedChannel( this ); 1244 } 1245 1246 if( result == kIOReturnSuccess ) 1247 { 1248 UInt16 irm; 1249 fControl->getIRMNodeID( generation, irm ); 1250 addr.nodeID = irm; 1251 1252 FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - generation = %d allocated generation = %d\n", generation, fGeneration )); 1253 1254 if( generation != fGeneration ) 1255 { 1256 result = kIOFireWireBusReset; 1257 fBandwidth = 0; 1258 fChannel = 64; 1259 } 1260 } 1261 1262 // 1263 // release bandwidth 1264 // 1265 1266 if( fBandwidth != 0 ) 1267 { 1268 UInt32 oldVal = 0; 1269 1270 // 1271 // read the bandwidth available register 1272 // 1273 1274 if( result == kIOReturnSuccess ) 1275 { 1276 fReadCmd->reinit( generation, addr, &oldVal, 1 ); 1277 result = fReadCmd->submit(); 1278 } 1279 1280 // 1281 // compare swap loop 1282 // 1283 1284 bool done = false; 1285 while( (result == kIOReturnSuccess) && !done ) 1286 { 1287 UInt32 old_bandwidth = OSSwapBigToHostInt32( oldVal ); 1288 UInt32 newVal = OSSwapHostToBigInt32( old_bandwidth + fBandwidth ); 1289 1290 fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 ); 1291 result = fLockCmd->submit(); 1292 1293 if( result == kIOReturnSuccess ) 1294 { 1295 done = fLockCmd->locked(&oldVal); 1296 } 1297 } 1298 1299 // error or not, we've released our bandwidth 1300 fBandwidth = 0; 1301 1302 FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - released bandwidth\n" )); 1303 1304 if( result != kIOFireWireBusReset ) 1305 { 1306 // as long as we didn't get a bus reset error, let's pretend 1307 // this was successful so we can give channel deallocation a try 1308 1309 result = kIOReturnSuccess; 1310 } 1311 } 1312 1313 // 1314 // release channel 1315 // 1316 1317 if( fChannel != 64 ) 1318 { 1319 UInt32 mask = 0; 1320 UInt32 oldVal = 0; 1321 1322 // 1323 // read the channels available register 1324 // 1325 1326 if( result == kIOReturnSuccess ) 1327 { 1328 if( fChannel <= 31 ) 1329 { 1330 addr.addressLo = kCSRChannelsAvailable31_0; 1331 mask = 1 << (31-fChannel); 1332 } 1333 else 1334 { 1335 addr.addressLo = kCSRChannelsAvailable63_32; 1336 mask = 1 << (63-fChannel); 1337 } 1338 1339 fReadCmd->reinit( generation, addr, &oldVal, 1 ); 1340 result = fReadCmd->submit(); 1341 } 1342 1343 // 1344 // compare swap loop 1345 // 1346 1347 bool done = false; 1348 while( (result == kIOReturnSuccess) && !done ) 1349 { 1350 UInt32 old_channels_avail = OSSwapBigToHostInt32( oldVal ); 1351 UInt32 newVal = OSSwapHostToBigInt32( old_channels_avail | mask ); 1352 1353 fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 ); 1354 result = fLockCmd->submit(); 1355 1356 if( result == kIOReturnSuccess ) 1357 { 1358 done = fLockCmd->locked( &oldVal ); 1359 } 1360 } 1361 1362 FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - released channel\n" )); 1363 1364 // error or not, we've released the channel 1365 fChannel = 64; 1366 } 1367 1368 // error or not we've released our channel and bandwidth 1369 1370 fBandwidth = 0; 1371 fChannel = 64; 1372 1373 fGeneration = generation; 1374 1375 IOLockUnlock( fLock ); 1376 } 1377 1378 return kIOReturnSuccess; 1379} 1380 1381// updateBandwidth 1382// 1383// deprecated 1384 1385IOReturn IOFWIsochChannel::updateBandwidth( bool /* claim */ ) 1386{ 1387 DebugLog("driver calling deprecated IOFWIsochChannel::updateBandwidth on channel %p\n", this ) ; 1388 1389 return kIOReturnUnsupported; 1390} 1391 1392