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 * $Log: IOFWDCLProgram.cpp,v $ 28 * Revision 1.33 2012/06/06 01:51:16 collin 29 * DCL program changes for vt-d 30 * 31 * Revision 1.32 2008/05/06 03:26:57 collin 32 * more K64 33 * 34 * Revision 1.31 2007/03/14 01:01:12 collin 35 * *** empty log message *** 36 * 37 * Revision 1.30 2007/02/15 19:42:07 ayanowit 38 * For 4369537, eliminated support for legacy DCL SendPacketWithHeader, since it didn't work anyway, and NuDCL does support it. 39 * 40 * Revision 1.29 2006/02/09 00:21:50 niels 41 * merge chardonnay branch to tot 42 * 43 * Revision 1.28 2005/03/12 03:27:51 collin 44 * *** empty log message *** 45 * 46 * Revision 1.27 2004/06/19 01:05:50 niels 47 * turn on prebinding for IOFireWireLib.plugin 48 * 49 * Revision 1.26 2004/06/10 20:57:36 niels 50 * *** empty log message *** 51 * 52 * Revision 1.25 2004/04/22 23:34:11 niels 53 * *** empty log message *** 54 * 55 * Revision 1.24 2003/12/19 22:07:46 niels 56 * send force stop when channel dies/system sleeps 57 * 58 * Revision 1.23 2003/08/30 00:16:44 collin 59 * *** empty log message *** 60 * 61 * Revision 1.22 2003/08/25 09:24:24 niels 62 * *** empty log message *** 63 * 64 * Revision 1.20 2003/08/25 08:39:15 niels 65 * *** empty log message *** 66 * 67 * Revision 1.19 2003/08/15 04:36:55 niels 68 * *** empty log message *** 69 * 70 * Revision 1.18 2003/08/12 00:55:03 niels 71 * *** empty log message *** 72 * 73 * Revision 1.17 2003/07/29 23:36:29 niels 74 * *** empty log message *** 75 * 76 * Revision 1.16 2003/07/29 22:49:22 niels 77 * *** empty log message *** 78 * 79 * Revision 1.15 2003/07/21 06:52:58 niels 80 * merge isoch to TOT 81 * 82 * Revision 1.14.4.1 2003/07/01 20:54:06 niels 83 * isoch merge 84 * 85 * 86 */ 87 88#import <IOKit/firewire/IOFWDCLProgram.h> 89#import "FWDebugging.h" 90 91OSDefineMetaClass( IODCLProgram, OSObject ) 92OSDefineAbstractStructors ( IODCLProgram, OSObject ) 93OSMetaClassDefineReservedUsed ( IODCLProgram, 0 ) ; 94OSMetaClassDefineReservedUsed ( IODCLProgram, 1 ) ; 95OSMetaClassDefineReservedUnused ( IODCLProgram, 2 ) ; 96OSMetaClassDefineReservedUnused ( IODCLProgram, 3 ) ; 97OSMetaClassDefineReservedUnused ( IODCLProgram, 4 ) ; 98 99#undef super 100#define super OSObject 101 102static bool 103getDCLDataBuffer( 104 const DCLCommand * dcl, 105 IOVirtualRange & outRange) 106{ 107 bool result = false ; 108 109 switch( dcl->opcode & ~kFWDCLOpFlagMask) 110 { 111 case kDCLSendPacketStartOp: 112 //case kDCLSendPacketWithHeaderStartOp: 113 case kDCLSendPacketOp: 114 case kDCLReceivePacketStartOp: 115 case kDCLReceivePacketOp: 116 outRange.address = (IOVirtualAddress)((DCLTransferPacket*)dcl)->buffer ; 117 outRange.length = ((DCLTransferPacket*)dcl)->size ; 118 result = true ; 119 break ; 120 121 case kDCLPtrTimeStampOp: 122 outRange.address = (IOVirtualAddress)((DCLPtrTimeStamp*)dcl)->timeStampPtr ; 123 outRange.length = sizeof( *( ((DCLPtrTimeStamp*)dcl)->timeStampPtr) ) ; 124 result = true ; 125 break ; 126 127 default: 128 break ; 129 } 130 131 return result ; 132} 133 134void 135IODCLProgram::generateBufferMap( DCLCommand * program ) 136{ 137 138 IOVirtualAddress lowAddress = (IOVirtualAddress)-1 ; 139 IOVirtualAddress highAddress = 0 ; 140 141 for( DCLCommand * dcl = program; dcl != NULL; dcl = dcl->pNextDCLCommand ) 142 { 143 IOVirtualRange tempRange ; 144 if ( getDCLDataBuffer( dcl, tempRange ) ) 145 { 146// DebugLog( "see range %p +0x%x\n", (void*)(tempRange.address), (unsigned)(tempRange.length) ) ; 147 148 lowAddress = MIN( lowAddress, trunc_page( tempRange.address ) ) ; 149 highAddress = MAX( highAddress, round_page( tempRange.address + tempRange.length ) ) ; 150 } 151 } 152 153#ifdef __LP64__ 154 DebugLog("IODCLProgram::generateBufferMap lowAddress=%llx highAddress=%llx\n", lowAddress, highAddress ) ; 155#else 156 DebugLog("IODCLProgram::generateBufferMap lowAddress=%x highAddress=%x\n", lowAddress, highAddress ) ; 157#endif 158 159 if ( lowAddress == 0 ) 160 { 161 return ; 162 } 163 164 IOByteCount length = highAddress - lowAddress; 165 IOMemoryDescriptor * desc = IOMemoryDescriptor::withAddress( (void*)lowAddress, length, kIODirectionOutIn ) ; 166 167 DebugLogCond(!desc, "couldn't make memory descriptor!\n") ; 168 169 if ( desc && kIOReturnSuccess != desc->prepare() ) 170 { 171 ErrorLog("couldn't prepare memory descriptor\n") ; 172 173 desc->release() ; 174 desc = NULL ; 175 } 176 177 IODMACommand * dma_command = NULL; 178 if ( desc ) 179 { 180 IOReturn status = kIOReturnSuccess; 181 182 dma_command = IODMACommand::withSpecification( kIODMACommandOutputHost32, // segment function 183 32, // max address bits 184 length, // max segment size 185 (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly), // IO mapped & don't bounce buffer 186 length, // max transfer size 187 0, // page alignment 188 NULL, // mapper 189 NULL ); // refcon 190 if( dma_command == NULL ) 191 { 192 status = kIOReturnError; 193 } 194 195 if( status == kIOReturnSuccess ) 196 { 197 status = dma_command->setMemoryDescriptor( desc ); 198 } 199 200 if( status != kIOReturnSuccess ) 201 { 202 ErrorLog("couldn't prepare memory DMA command\n") ; 203 204 if( dma_command ) 205 { 206 dma_command->release(); 207 } 208 209 desc->release() ; 210 desc = NULL ; 211 } 212 } 213 214 if ( desc ) 215 { 216 fExpansionData->fDMACommand = dma_command; 217 fBufferMem = desc->map() ; 218 desc->release() ; 219 220 DebugLogCond(!fBufferMem, "couldn't make mapping\n") ; 221 } 222} 223 224IOReturn 225IODCLProgram::virtualToPhysical( 226 IOVirtualRange ranges[], 227 unsigned rangeCount, 228 IOMemoryCursor::IOPhysicalSegment outSegments[], 229 unsigned & outPhysicalSegmentCount, 230 unsigned maxSegments ) 231{ 232 // nnn this assumes that subtracting an address of one of the DCL program's buffers in the memory map 233 // from the base address of the map will produce the correct offset into the memory map despite 234 // any gaps in the ranges used to build the memory descriptor 235 // should be okay, since memory descriptors from user space have been allocated from a 236 // single call to vm_allocate() 237 238 outPhysicalSegmentCount = 0 ; 239 if ( rangeCount == 0 ) 240 return kIOReturnSuccess ; 241 242 IOVirtualAddress bufferMemBaseAddress = fBufferMem->getVirtualAddress() ; 243 244 unsigned rangeIndex=0; 245 do 246 { 247 if ( outPhysicalSegmentCount >= maxSegments ) 248 return kIOReturnDMAError ; 249 250 IOByteCount transferBytes = ranges[ rangeIndex ].length ; 251 IOVirtualAddress offset = ranges[ rangeIndex ].address - bufferMemBaseAddress ; 252 253 while( transferBytes > 0 ) 254 { 255 outSegments[ outPhysicalSegmentCount ].location = fBufferMem->getPhysicalSegment( offset, & outSegments[ outPhysicalSegmentCount ].length ) ; 256 outSegments[ outPhysicalSegmentCount ].length = min( outSegments[ outPhysicalSegmentCount ].length, transferBytes ) ; 257 258 transferBytes -= outSegments[ outPhysicalSegmentCount ].length ; 259 offset += outSegments[ outPhysicalSegmentCount ].length ; 260 261 ++outPhysicalSegmentCount ; 262 } 263 264 } while ( ++rangeIndex < rangeCount ) ; 265 266 return kIOReturnSuccess ; 267} 268 269bool 270IODCLProgram::init ( IOFireWireBus::DCLTaskInfo * info) 271{ 272 if ( ! super::init () ) 273 return false ; 274 275 fExpansionData = new ExpansionData ; 276 if ( !fExpansionData ) 277 { 278 return false ; 279 } 280 281 fExpansionData->resourceFlags = kFWDefaultIsochResourceFlags ; 282 283 bool success = true ; 284 285 if ( info ) 286 { 287 // this part sets up fBufferMem is passed in 'info' 288 289 290 if ( ( !info->unused0 && !info->unused1 && !info->unused2 && !info->unused3 && !info->unused4 291 && ! info->unused5 ) && info->auxInfo ) 292 { 293 switch( info->auxInfo->version ) 294 { 295 case 0 : 296 { 297 fBufferMem = info->auxInfo->u.v0.bufferMemoryMap ; 298 if ( fBufferMem ) 299 { 300 fBufferMem->retain() ; 301 } 302 303 break ; 304 } 305 306 case 1 : 307 case 2 : 308 { 309 fBufferMem = info->auxInfo->u.v1.bufferMemoryMap ; // handles version 2 also 310 if ( fBufferMem ) 311 { 312 fBufferMem->retain() ; 313 } 314 315 break ; 316 } 317 default : 318 ErrorLog( "unsupported version found in info->auxInfo!\n" ) ; 319 success = false ; 320 break ; 321 } ; 322 } 323 } 324 325 return success ; 326} 327 328void IODCLProgram::free() 329{ 330 if ( fExpansionData ) 331 { 332 if( fExpansionData->fDMACommand ) 333 { 334 fExpansionData->fDMACommand->complete(); 335 fExpansionData->fDMACommand->release(); 336 fExpansionData->fDMACommand = NULL; 337 } 338 339 delete fExpansionData ; 340 fExpansionData = NULL ; 341 } 342 343 if ( fBufferMem ) 344 { 345 fBufferMem->release() ; 346 fBufferMem = NULL ; 347 } 348 349 OSObject::free(); 350} 351 352IOReturn IODCLProgram::pause() 353{ 354 return kIOReturnSuccess; 355} 356 357IOReturn IODCLProgram::resume() 358{ 359 return kIOReturnSuccess; 360} 361 362void 363IODCLProgram::setForceStopProc ( 364 IOFWIsochChannel::ForceStopNotificationProc proc, 365 void * refCon, 366 IOFWIsochChannel * channel ) 367{ 368 DebugLog("IODCLProgram::setForceStopProc\n") ; 369} 370 371void 372IODCLProgram::setIsochResourceFlags ( IOFWIsochResourceFlags flags ) 373{ 374 fExpansionData->resourceFlags = flags ; 375} 376 377IOFWIsochResourceFlags 378IODCLProgram::getIsochResourceFlags () const 379{ 380 return fExpansionData->resourceFlags ; 381} 382 383IOMemoryMap * 384IODCLProgram::getBufferMap() const 385{ 386 return fBufferMem ; 387} 388