IOReturn AppleSamplePCI::generateDMAAddresses( IOMemoryDescriptor * memDesc ) { // Get the physical segment list. These could be used to generate a scatter gather // list for hardware. // This is the old getPhysicalSegment() loop calling IOMemoryDescriptor, // it will fail (panic) on new machines with memory above the 4Gb line IODMACommand * cmd; IOReturn err = kIOReturnSuccess; IOByteCount offset = 0; IOPhysicalAddress physicalAddr; IOPhysicalLength segmentLength; UInt32 index = 0; while( (physicalAddr = memDesc->getPhysicalSegment( offset, &segmentLength ))) { IOLog("Physical segment(%ld) %08lx:%08lx\n", index, physicalAddr, segmentLength); offset += segmentLength; index++; } // 64 bit physical address generation using IODMACommand do { cmd = IODMACommand::withSpecification( // outSegFunc - Host endian since we read the address data with the cpu // and 64 bit wide quantities kIODMACommandOutputHost64, // numAddressBits 64, // maxSegmentSize - zero for unrestricted physically contiguous chunks 0, // mappingOptions - kMapped for DMA addresses IODMACommand::kMapped, // maxTransferSize - no restriction 0, // alignment - no restriction 1 ); if (!cmd) { IOLog("IODMACommand::withSpecification failed\n"); break; } // point at the memory descriptor and use the auto prepare option // to prepare the entire range err = cmd->setMemoryDescriptor(memDesc); if (kIOReturnSuccess != err) { IOLog("setMemoryDescriptor failed (0x%x)\n", err); break; } UInt64 offset = 0; while ((kIOReturnSuccess == err) && (offset < memDesc->getLength())) { // use the 64 bit variant to match outSegFunc IODMACommand::Segment64 segments[1]; UInt32 numSeg = 1; // use the 64 bit variant to match outSegFunc err = cmd->gen64IOVMSegments(&offset, &segments[0], &numSeg); IOLog("gen64IOVMSegments(%x) addr 0x%qx, len 0x%qx, nsegs %ld\n", err, segments[0].fIOVMAddr, segments[0].fLength, numSeg); } // if we had a DMA controller, kick off the DMA here // when the DMA has completed, // clear the memory descriptor and use the auto complete option // to complete the transaction err = cmd->clearMemoryDescriptor(); if (kIOReturnSuccess != err) { IOLog("clearMemoryDescriptor failed (0x%x)\n", err); } } while (false); if (cmd) cmd->release(); // end 64 bit loop // 32 bit physical address generation using IODMACommand // any memory above 4Gb in the memory descriptor will be buffered // to memory below the 4G line, on machines without remapping HW support do { cmd = IODMACommand::withSpecification( // outSegFunc - Host endian since we read the address data with the cpu // and 32 bit wide quantities kIODMACommandOutputHost32, // numAddressBits 32, // maxSegmentSize - zero for unrestricted physically contiguous chunks 0, // mappingOptions - kMapped for DMA addresses IODMACommand::kMapped, // maxTransferSize - no restriction 0, // alignment - no restriction 1 ); if (!cmd) { IOLog("IODMACommand::withSpecification failed\n"); break; } // point at the memory descriptor and use the auto prepare option // to prepare the entire range err = cmd->setMemoryDescriptor(memDesc); if (kIOReturnSuccess != err) { IOLog("setMemoryDescriptor failed (0x%x)\n", err); break; } UInt64 offset = 0; while ((kIOReturnSuccess == err) && (offset < memDesc->getLength())) { // use the 32 bit variant to match outSegFunc IODMACommand::Segment32 segments[1]; UInt32 numSeg = 1; // use the 32 bit variant to match outSegFunc err = cmd->gen32IOVMSegments(&offset, &segments[0], &numSeg); IOLog("gen32IOVMSegments(%x) addr 0x%lx, len 0x%lx, nsegs %ld\n", err, segments[0].fIOVMAddr, segments[0].fLength, numSeg); } // if we had a DMA controller, kick off the DMA here // when the DMA has completed, // clear the memory descriptor and use the auto complete option // to complete the transaction err = cmd->clearMemoryDescriptor(); if (kIOReturnSuccess != err) { IOLog("clearMemoryDescriptor failed (0x%x)\n", err); } } while (false); if (cmd) cmd->release(); // end 32 bit loop return (err); }
IOReturn IOUSBController::CheckForDisjointDescriptor(IOUSBCommand *command, UInt16 maxPacketSize) { IOMemoryDescriptor *buf = command->GetBuffer(); IOBufferMemoryDescriptor *newBuf = NULL; IOByteCount length = command->GetReqCount(); IODMACommand *dmaCommand = command->GetDMACommand(); IOByteCount segLength = 0; IOByteCount offset = 0; IOReturn err; UInt64 offset64; IODMACommand::Segment64 segment64; UInt32 numSegments; // USBTrace_Start( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this ); // Zero length buffers are valid, but they are surely not disjoint, so just return success. // if ( length == 0 ) return kIOReturnSuccess; if (!dmaCommand) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - no dmaCommand", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument, 0, 1 ); return kIOReturnBadArgument; } if (dmaCommand->getMemoryDescriptor() != buf) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - mismatched memory descriptor (%p) and dmaCommand memory descriptor (%p)", getName(), this, buf, dmaCommand->getMemoryDescriptor()); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, kIOReturnBadArgument, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 ); return kIOReturnBadArgument; } while (length) { offset64 = offset; numSegments = 1; err = dmaCommand->gen64IOVMSegments(&offset64, &segment64, &numSegments); if (err || (numSegments != 1)) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err (%p) trying to generate segments at offset (%qd), length (%d), segLength (%d), total length (%d), buf (%p), numSegments (%d)", getName(), this, (void*)err, offset64, (int)length, (int)segLength, (int)command->GetReqCount(), buf, (int)numSegments); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, offset64, length, segLength, 3 ); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, segLength, command->GetReqCount(), numSegments, 4 ); return kIOReturnBadArgument; } // 3036056 since length might be less than the length of the descriptor, we are OK if the physical // segment is longer than we need if (segment64.fLength >= length) return kIOReturnSuccess; // this is the last segment, so we are OK // since length is a 32 bit quantity, then we know from the above statement that if we are here we are 32 bit only segLength = (IOByteCount)segment64.fLength; // so the segment is less than the rest of the length - we need to check against maxPacketSize if (segLength % maxPacketSize) { // this is the error case. I need to copy the descriptor to a new descriptor and remember that I did it USBLog(6, "%s[%p]::CheckForDisjointDescriptor - found a disjoint segment of length (%d) MPS (%d)", getName(), this, (int)segLength, maxPacketSize); length = command->GetReqCount(); // we will not return to the while loop, so don't worry about changing the value of length // allocate a new descriptor which is the same total length as the old one newBuf = IOBufferMemoryDescriptor::withOptions((command->GetDirection() == kUSBIn) ? kIODirectionIn : kIODirectionOut, length); if (!newBuf) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - could not allocate new buffer", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnNoMemory, 0, 5 ); return kIOReturnNoMemory; } USBLog(7, "%s[%p]::CheckForDisjointDescriptor, obtained buffer %p of length %d", getName(), this, newBuf, (int)length); // first close out (and complete) the original dma command descriptor USBLog(7, "%s[%p]::CheckForDisjointDescriptor, clearing memDec (%p) from dmaCommand (%p)", getName(), this, dmaCommand->getMemoryDescriptor(), dmaCommand); dmaCommand->clearMemoryDescriptor(); // copy the bytes to the buffer if necessary if (command->GetDirection() == kUSBOut) { USBLog(7, "%s[%p]::CheckForDisjointDescriptor, copying %d bytes from desc %p to buffer %p", getName(), this, (int)length, buf, newBuf->getBytesNoCopy()); if (buf->readBytes(0, newBuf->getBytesNoCopy(), length) != length) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - bad copy on a write", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, 0, 0, 6 ); newBuf->release(); return kIOReturnNoMemory; } } err = newBuf->prepare(); if (err) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in prepare", getName(), this, err); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 7 ); newBuf->release(); return err; } err = dmaCommand->setMemoryDescriptor(newBuf); if (err) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in setMemoryDescriptor", getName(), this, err); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 8 ); newBuf->complete(); newBuf->release(); return err; } command->SetOrigBuffer(command->GetBuffer()); command->SetDisjointCompletion(command->GetClientCompletion()); USBLog(7, "%s[%p]::CheckForDisjointDescriptor - changing buffer from (%p) to (%p) and putting new buffer in dmaCommand (%p)", getName(), this, command->GetBuffer(), newBuf, dmaCommand); command->SetBuffer(newBuf); IOUSBCompletion completion; completion.target = this; completion.action = (IOUSBCompletionAction)DisjointCompletion; completion.parameter = command; command->SetClientCompletion(completion); command->SetDblBufLength(length); // for the IOFree - the other buffer may change size return kIOReturnSuccess; } length -= segLength; // adjust our master length pointer offset += segLength; } USBLog(5, "%s[%p]::CheckForDisjointDescriptor - returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument); // USBTrace_End( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument); return kIOReturnBadArgument; }