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#include <IOKit/firewire/IOFWAddressSpace.h> 24#include <IOKit/firewire/IOFireWireController.h> 25 26#include "FWDebugging.h" 27 28#include <IOKit/IOKitKeysPrivate.h> 29#include <IOKit/IODMACommand.h> 30 31/* 32 * Direct physical memory <-> FireWire address. 33 * Accesses to these addresses will be handled automatically by the 34 * hardware without notification. 35 * 36 * The following is currently true, though the code no longer makes such assumptions : 37 * The 64 bit FireWire address of (32 bit) physical addr xxxx:xxxx is hostNode:0000:xxxx:xxxx 38 */ 39 40OSDefineMetaClassAndStructors(IOFWPhysicalAddressSpaceAux, IOFWAddressSpaceAux); 41 42OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 0); 43OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 1); 44OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 2); 45OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 3); 46OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 4); 47OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 5); 48OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 6); 49OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 7); 50OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 8); 51OSMetaClassDefineReservedUnused(IOFWPhysicalAddressSpaceAux, 9); 52 53#pragma mark - 54 55OSDefineMetaClassAndStructors(IOFWPhysicalAddressSpace, IOFWAddressSpace) 56 57// init 58// 59// 60 61bool IOFWPhysicalAddressSpace::init( IOFireWireBus * bus ) 62{ 63 bool success = true; // assume success 64 65 // init super 66 67 if( !IOFWAddressSpace::init( bus ) ) 68 success = false; 69 70 return success; 71} 72 73// createAuxiliary 74// 75// virtual method for creating auxiliary object. subclasses needing to subclass 76// the auxiliary object can override this. 77 78IOFWAddressSpaceAux * IOFWPhysicalAddressSpace::createAuxiliary( void ) 79{ 80 IOFWPhysicalAddressSpaceAux * auxiliary; 81 82 auxiliary = OSTypeAlloc( IOFWPhysicalAddressSpaceAux ); 83 84 if( auxiliary != NULL && !auxiliary->init(this) ) 85 { 86 auxiliary->release(); 87 auxiliary = NULL; 88 } 89 90 return (IOFWAddressSpaceAux*)auxiliary; 91} 92 93// checkMemoryInRange 94// 95// 96 97IOReturn IOFWPhysicalAddressSpace::checkMemoryInRange( IOMemoryDescriptor * memory ) 98{ 99 IOReturn status = kIOReturnSuccess; 100 101 if( memory == NULL ) 102 { 103 status = kIOReturnBadArgument; 104 } 105 106 // 107 // setup 108 // 109 110 bool memory_prepared = false; 111 if( status == kIOReturnSuccess ) 112 { 113 status = memory->prepare( kIODirectionInOut ); 114 } 115 116 if( status == kIOReturnSuccess ) 117 { 118 memory_prepared = true; 119 } 120 121 UInt64 length = 0; 122 if( status == kIOReturnSuccess ) 123 { 124 length = memory->getLength(); 125 if( length == 0 ) 126 { 127 status = kIOReturnError; 128 } 129 } 130 131 // 132 // create IODMACommand 133 // 134 135 IODMACommand * dma_command = NULL; 136 if( status == kIOReturnSuccess ) 137 { 138 dma_command = IODMACommand::withSpecification( 139 kIODMACommandOutputHost64, // segment function 140 64, // max address bits 141 length, // max segment size 142 (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly), // IO mapped & don't bounce buffer 143 length, // max transfer size 144 0, // page alignment 145 NULL, // mapper 146 NULL ); // refcon 147 if( dma_command == NULL ) 148 status = kIOReturnError; 149 150 } 151 152 if( status == kIOReturnSuccess ) 153 { 154 // set memory descriptor and don't prepare it 155 status = dma_command->setMemoryDescriptor( memory, false ); 156 } 157 158 bool dma_command_prepared = false; 159 if( status == kIOReturnSuccess ) 160 { 161 status = dma_command->prepare( 0, length, true ); 162 } 163 164 if( status == kIOReturnSuccess ) 165 { 166 dma_command_prepared = true; 167 } 168 169 // 170 // check ranges 171 // 172 173 if( status == kIOReturnSuccess ) 174 { 175 UInt64 offset = 0; 176 UInt64 mask = fControl->getFireWirePhysicalAddressMask(); 177 while( (offset < length) && (status == kIOReturnSuccess) ) 178 { 179 IODMACommand::Segment64 segments[10]; 180 UInt32 num_segments = 10; 181 status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments ); 182 if( status == kIOReturnSuccess ) 183 { 184 for( UInt32 i = 0; i < num_segments; i++ ) 185 { 186 // IOLog( "checkSegments - segments[%d].fIOVMAddr = 0x%016llx, fLength = %d\n", i, segments[i].fIOVMAddr, segments[i].fLength ); 187 188 if( (segments[i].fIOVMAddr & (~mask)) ) 189 { 190 // IOLog( "checkSegmentsFailed - 0x%016llx & 0x%016llx\n", segments[i].fIOVMAddr, mask ); 191 status = kIOReturnNotPermitted; 192 break; 193 } 194 } 195 } 196 } 197 } 198 199 // 200 // clean up 201 // 202 203 if( dma_command_prepared ) 204 { 205 dma_command->complete(); 206 dma_command_prepared = false; 207 } 208 209 if( dma_command ) 210 { 211 dma_command->clearMemoryDescriptor(); 212 dma_command->release(); 213 dma_command = NULL; 214 } 215 216 if( memory_prepared ) 217 { 218 memory->complete(); 219 memory_prepared = false; 220 } 221 222 return status; 223 224} 225 226// initWithDesc 227// 228// 229 230bool IOFWPhysicalAddressSpace::initWithDesc( IOFireWireBus *control, 231 IOMemoryDescriptor * mem ) 232{ 233 if(!IOFWAddressSpace::init(control)) 234 return false; 235 236// IOLog( "IOFWPhysicalAddressSpace::initWithDesc\n" ); 237 238 IOReturn status = kIOReturnSuccess; 239 240 if( status == kIOReturnSuccess ) 241 { 242 if( mem != NULL ) 243 { 244 status = checkMemoryInRange( mem ); 245 } 246 } 247 248// IOLog( "IOFWPhysicalAddressSpace::initWithDesc (1) - status = 0x%08lx\n", status ); 249 250 IODMACommand * dma_command = NULL; 251 if( status == kIOReturnSuccess ) 252 { 253 UInt32 address_bits = fControl->getFireWirePhysicalAddressBits(); 254 dma_command = IODMACommand::withSpecification( 255 kIODMACommandOutputHost64, // segment function 256 address_bits, // max address bits 257 0, // max segment size 258 IODMACommand::kMapped, // I/O mapped 259 0, // max transfer size 260 0, // no alignment 261 NULL, // mapper 262 NULL ); // refcon 263 if( dma_command == NULL ) 264 status = kIOReturnError; 265 266 } 267 268 if( status == kIOReturnSuccess ) 269 { 270 setDMACommand( dma_command ); 271 dma_command->release(); 272 status = setMemoryDescriptor( mem ); 273 } 274 275// IOLog( "IOFWPhysicalAddressSpace::initWithDesc (2) - status = 0x%08lx\n", status ); 276 277 return (status == kIOReturnSuccess); 278} 279 280// initWithDesc 281// 282// 283 284bool IOFWPhysicalAddressSpace::initWithDMACommand( IOFireWireBus * control, 285 IODMACommand * command ) 286{ 287 if( !IOFWAddressSpace::init(control) ) 288 return false; 289 290 setDMACommand( command ); 291 292 return true; 293} 294 295// free 296// 297// 298 299void IOFWPhysicalAddressSpace::free() 300{ 301// IOLog( "IOFWPhysicalAddressSpace::free\n" ); 302 303 IOFWAddressSpace::free(); 304} 305 306// doRead 307// 308// 309 310UInt32 IOFWPhysicalAddressSpace::doRead(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len, 311 IOMemoryDescriptor **buf, IOByteCount * offset, IOFWRequestRefCon refcon) 312{ 313 UInt32 res = kFWResponseAddressError; 314 UInt64 pos; 315 UInt64 phys; 316 317 if( !isTrustedNode( nodeID ) ) 318 return kFWResponseAddressError; 319 320 if( !isPrepared() ) 321 return kFWResponseAddressError; 322 323 UInt64 address = ((UInt64)addr.addressHi << 32) | (UInt64)addr.addressLo; 324 UInt64 desc_length = getLength(); 325 326 pos = 0; 327 while( pos < desc_length ) 328 { 329 bool found = false; 330 UInt64 lengthOfSegment; 331 phys = getPhysicalSegment( pos, &lengthOfSegment ); 332 333 if( (address >= phys) && (address < (phys+lengthOfSegment)) ) 334 { 335 UInt32 union_length = (lengthOfSegment - (address - phys)); 336 337 // check if the request extends beyond this physical segment 338 if( len <= union_length ) 339 { 340 found = true; 341 } 342 else 343 { 344 // look ahead for contiguous ranges 345 346 UInt64 contiguous_address = (phys + lengthOfSegment); 347 UInt64 contiguous_pos = (pos + lengthOfSegment); 348 UInt64 contiguous_length = len - union_length; 349 UInt64 contig_phys; 350 351 while( contiguous_pos < desc_length ) 352 { 353 contig_phys = getPhysicalSegment( contiguous_pos, &lengthOfSegment ); 354 if( contiguous_address != contig_phys ) 355 { 356 // not contiguous, bail 357 break; 358 } 359 360 if( contiguous_length <= lengthOfSegment ) 361 { 362 // fits in this segment - success 363 found = true; 364 break; 365 } 366 367 contiguous_length -= lengthOfSegment; 368 contiguous_pos += lengthOfSegment; 369 contiguous_address += lengthOfSegment; 370 } 371 372 } 373 } 374 375 if( found ) 376 { 377 // OK, block is in space 378 // Set position to exact start 379 *offset = (pos + address - phys); 380 *buf = getMemoryDescriptor(); 381 res = kFWResponseComplete; 382 break; 383 } 384 385 pos += lengthOfSegment; 386 } 387 388 return res; 389} 390 391// doWrite 392// 393// 394 395UInt32 IOFWPhysicalAddressSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len, 396 const void *buf, IOFWRequestRefCon refcon) 397{ 398 UInt32 res = kFWResponseAddressError; 399 UInt64 pos; 400 UInt64 phys; 401 402// IOLog( "IOFWPhysicalAddressSpace::doWrite\n" ); 403 404 if( !isTrustedNode( nodeID ) ) 405 return kFWResponseAddressError; 406 407 if( !isPrepared() ) 408 { 409 return kFWResponseAddressError; 410 } 411 412 UInt64 address = ((UInt64)addr.addressHi << 32) | (UInt64)addr.addressLo; 413 414 UInt64 desc_length = getLength(); 415 416 pos = 0; 417 while(pos < desc_length) 418 { 419 bool found = false; 420 UInt64 lengthOfSegment; 421 phys = getPhysicalSegment(pos, &lengthOfSegment); 422 423// IOLog( "IOFWPhysicalAddressSpace::doWrite - address = 0x%016llx phys = 0x%016llx\n", address, phys ); 424 425 if( (address >= phys) && (address < (phys+lengthOfSegment)) ) 426 { 427 UInt32 union_length = (lengthOfSegment - (address - phys)); 428 429 // check if the request extends beyond this physical segment 430 if( len <= union_length ) 431 { 432 found = true; 433 } 434 else 435 { 436 // look ahead for contiguous ranges 437 438 UInt64 contiguous_address = (phys + lengthOfSegment); 439 UInt64 contiguous_pos = (pos + lengthOfSegment); 440 UInt64 contiguous_length = len - union_length; 441 UInt64 contig_phys; 442 443 while( contiguous_pos < desc_length ) 444 { 445 contig_phys = getPhysicalSegment( contiguous_pos, &lengthOfSegment ); 446 if( contiguous_address != contig_phys ) 447 { 448 // not contiguous, bail 449 break; 450 } 451 452 if( contiguous_length <= lengthOfSegment ) 453 { 454 // fits in this segment - success 455 found = true; 456 break; 457 } 458 459 contiguous_length -= lengthOfSegment; 460 contiguous_pos += lengthOfSegment; 461 contiguous_address += lengthOfSegment; 462 } 463 464 } 465 } 466 467 if( found ) 468 { 469 // OK, block is in space 470 471 getMemoryDescriptor()->writeBytes( pos + (address - phys), buf, len); 472 getDMACommand()->writeBytes( pos + (address - phys), buf, len ); 473 474 // make sure any bounce buffers have the new data 475 // synchronize( kIODirectionOut ); 476 477 res = kFWResponseComplete; 478 break; 479 } 480 481 pos += lengthOfSegment; 482 } 483 484 return res; 485} 486 487// getMemoryDescriptor 488// 489// 490 491IOMemoryDescriptor * IOFWPhysicalAddressSpace::getMemoryDescriptor( void ) 492{ 493 IOMemoryDescriptor * desc = NULL; 494 495 IODMACommand * dma_command = getDMACommand(); 496 if( dma_command ) 497 { 498 desc = (IOMemoryDescriptor*)dma_command->getMemoryDescriptor(); 499 } 500 501 return desc; 502} 503 504// setMemoryDescriptor 505// 506// 507 508IOReturn IOFWPhysicalAddressSpace::setMemoryDescriptor( IOMemoryDescriptor * descriptor ) 509{ 510 IOReturn status = kIOReturnSuccess; 511 512 if( isPrepared() ) 513 { 514 complete(); 515 } 516 517 IODMACommand * dma_command = getDMACommand(); 518 if( dma_command == NULL ) 519 status = kIOReturnError; 520 521 if( status == kIOReturnSuccess ) 522 { 523 if( descriptor == NULL ) 524 { 525 dma_command->clearMemoryDescriptor(); 526 } 527 else 528 { 529 dma_command->clearMemoryDescriptor(); 530 status = dma_command->setMemoryDescriptor( descriptor, false ); 531 if( status == kIOReturnSuccess ) 532 { 533 prepare(); 534 } 535 } 536 } 537 538 return status; 539} 540 541// getLength 542// 543// 544 545UInt64 IOFWPhysicalAddressSpace::getLength( void ) 546{ 547 UInt64 length = 0; 548 549 IOMemoryDescriptor * desc = getMemoryDescriptor(); 550 if( desc ) 551 { 552 length = desc->getLength(); 553 } 554 555 return length; 556} 557 558///////////////////////////////////////////////////////////////////////////////////// 559#pragma mark - 560 561// init 562// 563// 564 565bool IOFWPhysicalAddressSpaceAux::init( IOFWAddressSpace * primary ) 566{ 567 bool success = true; // assume success 568 569 // init super 570 571 if( !IOFWAddressSpaceAux::init( primary ) ) 572 success = false; 573 574// IOLog( "IOFWPhysicalAddressSpaceAux::init\n" ); 575 576 if( success ) 577 { 578 fDMACommand = NULL; 579 } 580 581 if( !success ) 582 { 583 } 584 585 return success; 586} 587 588// free 589// 590// 591 592void IOFWPhysicalAddressSpaceAux::free() 593{ 594// IOLog( "IOFWPhysicalAddressSpaceAux::free\n" ); 595 596 if( isPrepared() ) 597 { 598 complete(); 599 } 600 601 if( fDMACommand ) 602 { 603 fDMACommand->clearMemoryDescriptor(); 604 fDMACommand->release(); 605 fDMACommand = NULL; 606 } 607 608 IOFWAddressSpaceAux::free(); 609} 610 611// setDMACommand 612// 613// 614 615void IOFWPhysicalAddressSpaceAux::setDMACommand( IODMACommand * dma_command ) 616{ 617 if( fDMACommandPrepared ) 618 { 619 complete(); 620 } 621 622 IODMACommand * old = fDMACommand; 623 fDMACommand = dma_command; 624 625 if( fDMACommand ) 626 { 627 fDMACommand->retain(); 628 } 629 630 if( old ) 631 { 632 old->release(); 633 } 634} 635 636// setDMACommand 637// 638// 639 640IODMACommand * IOFWPhysicalAddressSpaceAux::getDMACommand( void ) 641{ 642 return fDMACommand; 643} 644 645// isPrepared 646// 647// 648 649bool IOFWPhysicalAddressSpaceAux::isPrepared( void ) 650{ 651 return fDMACommandPrepared; 652} 653 654// getPhysicalSegment 655// 656// 657 658UInt64 IOFWPhysicalAddressSpaceAux::getPhysicalSegment( UInt64 offset, UInt64 * length ) 659{ 660 IOReturn status = kIOReturnSuccess; 661 662 UInt64 phys = 0; 663 664 IODMACommand::Segment64 segment; 665 UInt32 numSegments = 1; 666 UInt64 pos = offset; 667 if( status == kIOReturnSuccess ) 668 { 669 status = fDMACommand->gen64IOVMSegments( &pos, &segment, &numSegments ); 670 } 671 672 if( status == kIOReturnSuccess ) 673 { 674 if( numSegments != 1 ) 675 { 676 status = kIOReturnNoMemory; 677 } 678 } 679 680 if( status == kIOReturnSuccess ) 681 { 682 phys = segment.fIOVMAddr; 683 *length = segment.fLength; 684 } 685 686 return phys; 687} 688 689// prepare 690// 691// 692 693IOReturn IOFWPhysicalAddressSpaceAux::prepare( void ) 694{ 695 IOReturn status = kIOReturnSuccess; 696 697// IOLog( "IOFWPhysicalAddressSpaceAux::prepare\n" ); 698 699 if( !fDMACommandPrepared ) 700 { 701 UInt64 desc_length = ((IOFWPhysicalAddressSpace*)fPrimary)->getLength(); 702 status = fDMACommand->prepare( 0, desc_length ); 703 if( status == kIOReturnSuccess ) 704 { 705 fDMACommandPrepared = true; 706 } 707 } 708 709 return status; 710} 711 712// complete 713// 714// 715 716IOReturn IOFWPhysicalAddressSpaceAux::complete( void ) 717{ 718 IOReturn status = kIOReturnSuccess; 719 720// IOLog( "IOFWPhysicalAddressSpaceAux::complete\n" ); 721 722 if( !fDMACommandPrepared ) 723 { 724 status = kIOReturnNotReady; 725 } 726 727 if( status == kIOReturnSuccess ) 728 { 729 status = fDMACommand->complete(); 730 if( status == kIOReturnSuccess ) 731 { 732 fDMACommandPrepared = false; 733 } 734 } 735 736 return status; 737} 738 739// synchronize 740// 741// 742 743IOReturn IOFWPhysicalAddressSpaceAux::synchronize( IOOptionBits options ) 744{ 745 IOReturn status = kIOReturnSuccess; 746 747// IOLog( "IOFWPhysicalAddressSpaceAux::synchronize - direction = %d\n", direction ); 748 749 if( !fDMACommandPrepared ) 750 { 751 status = kIOReturnNotReady; 752 } 753 754 if( status == kIOReturnSuccess ) 755 { 756 status = fDMACommand->synchronize( options ); 757 } 758 759 return status; 760} 761 762// getSegments 763// 764// 765 766IOReturn IOFWPhysicalAddressSpaceAux::getSegments( UInt64 * offset, FWSegment * fw_segments, UInt32 * num_segments ) 767{ 768 IOReturn status = kIOReturnSuccess; 769 770 IODMACommand::Segment64 * vm_segments = NULL; 771 UInt32 vm_segments_size = 0; 772 773 if( (offset == NULL) || (fw_segments == NULL) || (num_segments == NULL) ) 774 { 775 status = kIOReturnBadArgument; 776 } 777 778 if( status == kIOReturnSuccess ) 779 { 780 vm_segments_size = sizeof(IODMACommand::Segment64) * (*num_segments); 781 vm_segments = (IODMACommand::Segment64*)IOMalloc( vm_segments_size ); 782 if( vm_segments == NULL ) 783 status = kIOReturnNoMemory; 784 } 785 786 if( status == kIOReturnSuccess ) 787 { 788 IODMACommand * dma_command = getDMACommand(); 789 status = dma_command->gen64IOVMSegments( offset, vm_segments, num_segments ); 790 } 791 792 if( status == kIOReturnSuccess ) 793 { 794 for( UInt32 i = 0; i < *num_segments; i++ ) 795 { 796 fw_segments[i].length = vm_segments[i].fLength; 797 fw_segments[i].address.nodeID = 0x0000; // invalid node id 798 fw_segments[i].address.addressHi = (vm_segments[i].fIOVMAddr >> 32) & 0x000000000000ffffULL; 799 fw_segments[i].address.addressLo = vm_segments[i].fIOVMAddr & 0x00000000ffffffffULL; 800 } 801 } 802 803 if( fw_segments != NULL ) 804 { 805 IOFree( vm_segments, vm_segments_size ); 806 vm_segments = NULL; 807 } 808 809 return status; 810} 811