AppleEHCIitdMemoryBlock* AppleEHCIitdMemoryBlock::NewMemoryBlock(void) { AppleEHCIitdMemoryBlock *me = new AppleEHCIitdMemoryBlock; IOByteCount len; IODMACommand *dmaCommand = NULL; UInt64 offset = 0; IODMACommand::Segment32 segments; UInt32 numSegments = 1; IOReturn status = kIOReturnSuccess; if (me) { // Use IODMACommand to get the physical address dmaCommand = IODMACommand::withSpecification(kIODMACommandOutputHost32, 32, PAGE_SIZE, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly)); if (!dmaCommand) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not create IODMACommand"); return NULL; } USBLog(6, "AppleEHCIitdMemoryBlock::NewMemoryBlock - got IODMACommand %p", dmaCommand); // allocate one page on a page boundary below the 4GB line me->_buffer = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIOMemoryUnshared | kIODirectionInOut, kEHCIPageSize, kEHCIStructureAllocationPhysicalMask); // allocate exactly one physical page if (me->_buffer) { status = me->_buffer->prepare(); if (status) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not prepare buffer"); me->_buffer->release(); me->_buffer = NULL; me->release(); dmaCommand->release(); return NULL; } me->_sharedLogical = (EHCIIsochTransferDescriptorSharedPtr)me->_buffer->getBytesNoCopy(); bzero(me->_sharedLogical, kEHCIPageSize); status = dmaCommand->setMemoryDescriptor(me->_buffer); if (status) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not set memory descriptor"); me->_buffer->complete(); me->_buffer->release(); me->_buffer = NULL; me->release(); dmaCommand->release(); return NULL; } status = dmaCommand->gen32IOVMSegments(&offset, &segments, &numSegments); dmaCommand->clearMemoryDescriptor(); dmaCommand->release(); if (status || (numSegments != 1) || (segments.fLength != kEHCIPageSize)) { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not get physical segment"); me->_buffer->complete(); me->_buffer->release(); me->_buffer = NULL; me->release(); return NULL; } me->_sharedPhysical = segments.fIOVMAddr; } else { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock, could not allocate buffer!"); me->release(); me = NULL; } } else { USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock, constructor failed!"); } return me; }
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); }