2 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #define IOKIT_ENABLE_SHARED_PTR
31 #include <IOKit/assert.h>
33 #include <libkern/OSTypes.h>
34 #include <libkern/OSByteOrder.h>
35 #include <libkern/OSDebug.h>
37 #include <IOKit/IOReturn.h>
38 #include <IOKit/IOLib.h>
39 #include <IOKit/IODMACommand.h>
40 #include <IOKit/IOMapper.h>
41 #include <IOKit/IOMemoryDescriptor.h>
42 #include <IOKit/IOBufferMemoryDescriptor.h>
44 #include "IOKitKernelInternal.h"
46 #define MAPTYPE(type) ((UInt) (type) & kTypeMask)
47 #define IS_NONCOHERENT(type) (MAPTYPE(type) == kNonCoherent)
50 kWalkSyncIn
= 0x01,// bounce -> md
51 kWalkSyncOut
= 0x02,// bounce <- md
52 kWalkSyncAlways
= 0x04,
53 kWalkPreflight
= 0x08,
54 kWalkDoubleBuffer
= 0x10,
61 #define fInternalState reserved
62 #define fState reserved->fState
63 #define fMDSummary reserved->fMDSummary
67 // no direction => OutIn
68 #define SHOULD_COPY_DIR(op, direction) \
69 ((kIODirectionNone == (direction)) \
70 || (kWalkSyncAlways & (op)) \
71 || (((kWalkSyncIn & (op)) ? kIODirectionIn : kIODirectionOut) \
75 #define SHOULD_COPY_DIR(state, direction) (true)
79 #define DEBG(fmt, args...) { IOLog(fmt, ## args); kprintf(fmt, ## args); }
81 #define DEBG(fmt, args...) {}
85 #define LOGTAG 0x87654321
88 /**************************** class IODMACommand ***************************/
91 #define super IOCommand
92 OSDefineMetaClassAndStructorsWithZone(IODMACommand
, IOCommand
, ZC_NONE
);
94 OSMetaClassDefineReservedUsedX86(IODMACommand
, 0);
95 OSMetaClassDefineReservedUsedX86(IODMACommand
, 1);
96 OSMetaClassDefineReservedUsedX86(IODMACommand
, 2);
97 OSMetaClassDefineReservedUsedX86(IODMACommand
, 3);
98 OSMetaClassDefineReservedUsedX86(IODMACommand
, 4);
99 OSMetaClassDefineReservedUsedX86(IODMACommand
, 5);
100 OSMetaClassDefineReservedUsedX86(IODMACommand
, 6);
101 OSMetaClassDefineReservedUnused(IODMACommand
, 7);
102 OSMetaClassDefineReservedUnused(IODMACommand
, 8);
103 OSMetaClassDefineReservedUnused(IODMACommand
, 9);
104 OSMetaClassDefineReservedUnused(IODMACommand
, 10);
105 OSMetaClassDefineReservedUnused(IODMACommand
, 11);
106 OSMetaClassDefineReservedUnused(IODMACommand
, 12);
107 OSMetaClassDefineReservedUnused(IODMACommand
, 13);
108 OSMetaClassDefineReservedUnused(IODMACommand
, 14);
109 OSMetaClassDefineReservedUnused(IODMACommand
, 15);
112 OSSharedPtr
<IODMACommand
>
113 IODMACommand::withRefCon(void * refCon
)
115 OSSharedPtr
<IODMACommand
> me
= OSMakeShared
<IODMACommand
>();
117 if (me
&& !me
->initWithRefCon(refCon
)) {
124 OSSharedPtr
<IODMACommand
>
125 IODMACommand::withSpecification(SegmentFunction outSegFunc
,
126 const SegmentOptions
* segmentOptions
,
127 uint32_t mappingOptions
,
131 OSSharedPtr
<IODMACommand
> me
= OSMakeShared
<IODMACommand
>();
133 if (me
&& !me
->initWithSpecification(outSegFunc
, segmentOptions
, mappingOptions
,
141 OSSharedPtr
<IODMACommand
>
142 IODMACommand::withSpecification(SegmentFunction outSegFunc
,
143 UInt8 numAddressBits
,
144 UInt64 maxSegmentSize
,
145 MappingOptions mappingOptions
,
146 UInt64 maxTransferSize
,
151 OSSharedPtr
<IODMACommand
> me
= OSMakeShared
<IODMACommand
>();
153 if (me
&& !me
->initWithSpecification(outSegFunc
,
154 numAddressBits
, maxSegmentSize
,
155 mappingOptions
, maxTransferSize
,
156 alignment
, mapper
, refCon
)) {
163 OSSharedPtr
<IODMACommand
>
164 IODMACommand::cloneCommand(void *refCon
)
166 SegmentOptions segmentOptions
=
168 .fStructSize
= sizeof(segmentOptions
),
169 .fNumAddressBits
= (uint8_t)fNumAddressBits
,
170 .fMaxSegmentSize
= fMaxSegmentSize
,
171 .fMaxTransferSize
= fMaxTransferSize
,
172 .fAlignment
= fAlignMask
+ 1,
173 .fAlignmentLength
= fAlignMaskInternalSegments
+ 1,
174 .fAlignmentInternalSegments
= fAlignMaskLength
+ 1
177 return IODMACommand::withSpecification(fOutSeg
, &segmentOptions
,
178 fMappingOptions
, fMapper
.get(), refCon
);
181 #define kLastOutputFunction ((SegmentFunction) kLastOutputFunction)
184 IODMACommand::initWithRefCon(void * refCon
)
186 if (!super::init()) {
191 reserved
= IONew(IODMACommandInternal
, 1);
196 bzero(reserved
, sizeof(IODMACommandInternal
));
203 IODMACommand::initWithSpecification(SegmentFunction outSegFunc
,
204 const SegmentOptions
* segmentOptions
,
205 uint32_t mappingOptions
,
209 if (!initWithRefCon(refCon
)) {
213 if (kIOReturnSuccess
!= setSpecification(outSegFunc
, segmentOptions
,
214 mappingOptions
, mapper
)) {
222 IODMACommand::initWithSpecification(SegmentFunction outSegFunc
,
223 UInt8 numAddressBits
,
224 UInt64 maxSegmentSize
,
225 MappingOptions mappingOptions
,
226 UInt64 maxTransferSize
,
231 SegmentOptions segmentOptions
=
233 .fStructSize
= sizeof(segmentOptions
),
234 .fNumAddressBits
= numAddressBits
,
235 .fMaxSegmentSize
= maxSegmentSize
,
236 .fMaxTransferSize
= maxTransferSize
,
237 .fAlignment
= alignment
,
238 .fAlignmentLength
= 1,
239 .fAlignmentInternalSegments
= alignment
242 return initWithSpecification(outSegFunc
, &segmentOptions
, mappingOptions
, mapper
, refCon
);
246 IODMACommand::setSpecification(SegmentFunction outSegFunc
,
247 const SegmentOptions
* segmentOptions
,
248 uint32_t mappingOptions
,
251 IOService
* device
= NULL
;
252 UInt8 numAddressBits
;
253 UInt64 maxSegmentSize
;
254 UInt64 maxTransferSize
;
259 if (!outSegFunc
|| !segmentOptions
) {
260 return kIOReturnBadArgument
;
263 is32Bit
= ((OutputHost32
== outSegFunc
)
264 || (OutputBig32
== outSegFunc
)
265 || (OutputLittle32
== outSegFunc
));
267 numAddressBits
= segmentOptions
->fNumAddressBits
;
268 maxSegmentSize
= segmentOptions
->fMaxSegmentSize
;
269 maxTransferSize
= segmentOptions
->fMaxTransferSize
;
270 alignment
= segmentOptions
->fAlignment
;
272 if (!numAddressBits
) {
274 } else if (numAddressBits
> 32) {
275 return kIOReturnBadArgument
; // Wrong output function for bits
279 if (numAddressBits
&& (numAddressBits
< PAGE_SHIFT
)) {
280 return kIOReturnBadArgument
;
283 if (!maxSegmentSize
) {
284 maxSegmentSize
--; // Set Max segment to -1
286 if (!maxTransferSize
) {
287 maxTransferSize
--; // Set Max transfer to -1
289 if (mapper
&& !OSDynamicCast(IOMapper
, mapper
)) {
293 if (!mapper
&& (kUnmapped
!= MAPTYPE(mappingOptions
))) {
294 IOMapper::checkForSystemMapper();
295 mapper
= IOMapper::gSystem
;
299 fOutSeg
= outSegFunc
;
300 fNumAddressBits
= numAddressBits
;
301 fMaxSegmentSize
= maxSegmentSize
;
302 fMappingOptions
= mappingOptions
;
303 fMaxTransferSize
= maxTransferSize
;
307 fAlignMask
= alignment
- 1;
309 alignment
= segmentOptions
->fAlignmentLength
;
313 fAlignMaskLength
= alignment
- 1;
315 alignment
= segmentOptions
->fAlignmentInternalSegments
;
317 alignment
= (fAlignMask
+ 1);
319 fAlignMaskInternalSegments
= alignment
- 1;
321 switch (MAPTYPE(mappingOptions
)) {
323 case kUnmapped
: break;
324 case kNonCoherent
: break;
330 return kIOReturnBadArgument
;
333 return kIOReturnBadArgument
;
337 if (mapper
!= fMapper
) {
338 fMapper
.reset(mapper
, OSRetain
);
341 fInternalState
->fIterateOnly
= (0 != (kIterateOnly
& mappingOptions
));
342 fInternalState
->fDevice
= device
;
344 return kIOReturnSuccess
;
351 IODelete(reserved
, IODMACommandInternal
, 1);
356 // Correct use of this class when setting an IOMemoryDescriptor
357 // in fMemory via setMemoryDescriptor(desc) is, for the caller, to
358 // have a matching call to clearMemoryDescriptor() before releasing
359 // the object. The matching call has also the effect of releasing
360 // the ref taken on the IOMemoryDescriptor in setMemoryDescriptor().
362 // A number of "misbehaving" drivers has been found during testing,
363 // whereby a matching call to clearMemoryDescriptor() is missing:
368 // Both the approaches taken in said drivers are wrong, but have gone
369 // basically silent with fMemory being a regular pointer. With fMemory
370 // becoming a OSSharedPtr, the IODMACommand destructor expects to find
371 // either fMemory reset (through the call to clearMemoryDescriptor()) or
372 // a reference hold for the release.
374 // For this reason, this workaround of detaching fMemory is put in
375 // place here, choosing the leak over the panic for misbehaving
376 // drivers. Once all instances are fixed, this workaround will be
379 // Note: all well behaving drivers that have matching calls for
380 // setMemoryDescriptor() and clearMemoryDescriptor() are unaffected
381 // since fMemory will be null at this point.
388 IODMACommand::setMemoryDescriptor(const IOMemoryDescriptor
*mem
, bool autoPrepare
)
390 IOReturn err
= kIOReturnSuccess
;
392 if (mem
== fMemory
) {
398 return kIOReturnSuccess
;
402 // As we are almost certainly being called from a work loop thread
403 // if fActive is true it is probably not a good time to potentially
404 // block. Just test for it and return an error
406 return kIOReturnBusy
;
408 clearMemoryDescriptor();
412 bzero(&fMDSummary
, sizeof(fMDSummary
));
413 err
= mem
->dmaCommandOperation(kIOMDGetCharacteristics
| (kMapped
== MAPTYPE(fMappingOptions
)),
414 &fMDSummary
, sizeof(fMDSummary
));
419 ppnum_t highPage
= fMDSummary
.fHighestPage
? fMDSummary
.fHighestPage
: gIOLastPage
;
421 if ((kMapped
== MAPTYPE(fMappingOptions
))
423 fInternalState
->fCheckAddressing
= false;
425 fInternalState
->fCheckAddressing
= (fNumAddressBits
&& (highPage
>= (1UL << (fNumAddressBits
- PAGE_SHIFT
))));
428 fInternalState
->fNewMD
= true;
429 fMemory
.reset(const_cast<IOMemoryDescriptor
*>(mem
), OSRetain
);
430 fInternalState
->fSetActiveNoMapper
= (!fMapper
);
431 if (fInternalState
->fSetActiveNoMapper
) {
432 mem
->dmaCommandOperation(kIOMDSetDMAActive
, this, 0);
437 clearMemoryDescriptor();
446 IODMACommand::clearMemoryDescriptor(bool autoComplete
)
448 if (fActive
&& !autoComplete
) {
449 return kIOReturnNotReady
;
456 if (fInternalState
->fSetActiveNoMapper
) {
457 fMemory
->dmaCommandOperation(kIOMDSetDMAInactive
, this, 0);
462 return kIOReturnSuccess
;
465 const IOMemoryDescriptor
*
466 IODMACommand::getMemoryDescriptor() const
468 return fMemory
.get();
472 IODMACommand::getIOMemoryDescriptor() const
474 OSSharedPtr
<IOMemoryDescriptor
> mem
;
476 mem
= reserved
->fCopyMD
;
485 IODMACommand::segmentOp(
487 IODMACommand
*target
,
492 IOOptionBits op
= (IOOptionBits
)(uintptr_t) reference
;
493 addr64_t maxPhys
, address
;
498 IODMACommandInternal
* state
= target
->reserved
;
500 if (target
->fNumAddressBits
&& (target
->fNumAddressBits
< 64) && (state
->fLocalMapperAllocValid
|| !target
->fMapper
)) {
501 maxPhys
= (1ULL << target
->fNumAddressBits
);
507 address
= segment
.fIOVMAddr
;
508 length
= segment
.fLength
;
512 if (!state
->fMisaligned
) {
513 mask
= (segmentIndex
? target
->fAlignMaskInternalSegments
: state
->fSourceAlignMask
);
514 state
->fMisaligned
|= (0 != (mask
& address
));
515 if (state
->fMisaligned
) {
516 DEBG("misaligned address %qx:%qx, %x\n", address
, length
, mask
);
519 if (!state
->fMisaligned
) {
520 mask
= target
->fAlignMaskLength
;
521 state
->fMisaligned
|= (0 != (mask
& length
));
522 if (state
->fMisaligned
) {
523 DEBG("misaligned length %qx:%qx, %x\n", address
, length
, mask
);
527 if (state
->fMisaligned
&& (kWalkPreflight
& op
)) {
528 return kIOReturnNotAligned
;
531 if (!state
->fDoubleBuffer
) {
532 if ((address
+ length
- 1) <= maxPhys
) {
534 } else if (address
<= maxPhys
) {
535 DEBG("tail %qx, %qx", address
, length
);
536 length
= (address
+ length
- maxPhys
- 1);
537 address
= maxPhys
+ 1;
538 DEBG("-> %qx, %qx\n", address
, length
);
543 return kIOReturnSuccess
;
546 uint64_t numPages64
= atop_64(round_page_64((address
& PAGE_MASK
) + length
));
547 if (numPages64
> UINT_MAX
) {
548 return kIOReturnVMError
;
550 numPages
= (typeof(numPages
))numPages64
;
552 if (kWalkPreflight
& op
) {
553 state
->fCopyPageCount
+= numPages
;
557 if (kWalkPrepare
& op
) {
558 lastPage
= state
->fCopyNext
;
559 for (IOItemCount idx
= 0; idx
< numPages
; idx
++) {
560 vm_page_set_offset(lastPage
, atop_64(address
) + idx
);
561 lastPage
= vm_page_get_next(lastPage
);
565 if (!lastPage
|| SHOULD_COPY_DIR(op
, target
->fMDSummary
.fDirection
)) {
566 lastPage
= state
->fCopyNext
;
567 for (IOItemCount idx
= 0; idx
< numPages
; idx
++) {
568 if (SHOULD_COPY_DIR(op
, target
->fMDSummary
.fDirection
)) {
569 addr64_t cpuAddr
= address
;
573 if ((kMapped
== MAPTYPE(target
->fMappingOptions
))
574 && target
->fMapper
) {
575 cpuAddr
= target
->fMapper
->mapToPhysicalAddress(address
);
578 remapAddr
= ptoa_64(vm_page_get_phys_page(lastPage
));
579 if (!state
->fDoubleBuffer
) {
580 remapAddr
+= (address
& PAGE_MASK
);
582 chunk
= PAGE_SIZE
- (address
& PAGE_MASK
);
583 if (chunk
> length
) {
586 if (chunk
> (UINT_MAX
- PAGE_SIZE
+ 1)) {
587 chunk
= (UINT_MAX
- PAGE_SIZE
+ 1);
590 DEBG("cpv: 0x%qx %s 0x%qx, 0x%qx, 0x%02lx\n", remapAddr
,
591 (kWalkSyncIn
& op
) ? "->" : "<-",
594 if (kWalkSyncIn
& op
) { // cppvNoModSnk
595 copypv(remapAddr
, cpuAddr
, (unsigned int) chunk
,
596 cppvPsnk
| cppvFsnk
| cppvPsrc
| cppvNoRefSrc
);
598 copypv(cpuAddr
, remapAddr
, (unsigned int) chunk
,
599 cppvPsnk
| cppvFsnk
| cppvPsrc
| cppvNoRefSrc
);
604 lastPage
= vm_page_get_next(lastPage
);
607 state
->fCopyNext
= lastPage
;
610 return kIOReturnSuccess
;
613 OSSharedPtr
<IOBufferMemoryDescriptor
>
614 IODMACommand::createCopyBuffer(IODirection direction
, UInt64 length
)
616 mach_vm_address_t mask
= 0xFFFFF000; //state->fSourceAlignMask
617 return IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task
,
618 direction
, length
, mask
);
622 IODMACommand::walkAll(uint32_t op
)
624 IODMACommandInternal
* state
= fInternalState
;
626 IOReturn ret
= kIOReturnSuccess
;
630 if (kWalkPreflight
& op
) {
631 state
->fMisaligned
= false;
632 state
->fDoubleBuffer
= false;
633 state
->fPrepared
= false;
634 state
->fCopyNext
= NULL
;
635 state
->fCopyPageAlloc
= NULL
;
636 state
->fCopyPageCount
= 0;
637 state
->fNextRemapPage
= NULL
;
638 state
->fCopyMD
= NULL
;
640 if (!(kWalkDoubleBuffer
& op
)) {
643 ret
= genIOVMSegments(op
, segmentOp
, (void *)(uintptr_t) op
, &offset
, state
, &numSegments
);
646 op
&= ~kWalkPreflight
;
648 state
->fDoubleBuffer
= (state
->fMisaligned
|| state
->fForceDoubleBuffer
);
649 state
->fForceDoubleBuffer
= false;
650 if (state
->fDoubleBuffer
) {
651 state
->fCopyPageCount
= (typeof(state
->fCopyPageCount
))(atop_64(round_page(state
->fPreparedLength
)));
654 if (state
->fCopyPageCount
) {
655 vm_page_t mapBase
= NULL
;
657 DEBG("preflight fCopyPageCount %d\n", state
->fCopyPageCount
);
659 if (!fMapper
&& !state
->fDoubleBuffer
) {
663 panic("fMapper copying");
666 kr
= vm_page_alloc_list(state
->fCopyPageCount
,
667 (kma_flags_t
)(KMA_LOMEM
| KMA_NOPAGEWAIT
), &mapBase
);
668 if (KERN_SUCCESS
!= kr
) {
669 DEBG("vm_page_alloc_list(%d) failed (%d)\n", state
->fCopyPageCount
, kr
);
675 state
->fCopyPageAlloc
= mapBase
;
676 state
->fCopyNext
= state
->fCopyPageAlloc
;
679 ret
= genIOVMSegments(op
, segmentOp
, (void *)(uintptr_t) op
, &offset
, state
, &numSegments
);
680 state
->fPrepared
= true;
681 op
&= ~(kWalkSyncIn
| kWalkSyncOut
);
683 DEBG("alloc IOBMD\n");
684 state
->fCopyMD
= createCopyBuffer(fMDSummary
.fDirection
, state
->fPreparedLength
);
686 if (state
->fCopyMD
) {
687 ret
= kIOReturnSuccess
;
688 state
->fPrepared
= true;
690 DEBG("IODMACommand !alloc IOBMD");
691 return kIOReturnNoResources
;
697 if (state
->fPrepared
&& ((kWalkSyncIn
| kWalkSyncOut
) & op
)) {
698 if (state
->fCopyPageCount
) {
699 DEBG("sync fCopyPageCount %d\n", state
->fCopyPageCount
);
701 if (state
->fCopyPageAlloc
) {
702 state
->fCopyNext
= state
->fCopyPageAlloc
;
705 ret
= genIOVMSegments(op
, segmentOp
, (void *)(uintptr_t) op
, &offset
, state
, &numSegments
);
706 } else if (state
->fCopyMD
) {
707 DEBG("sync IOBMD\n");
709 if (SHOULD_COPY_DIR(op
, fMDSummary
.fDirection
)) {
710 OSSharedPtr
<IOMemoryDescriptor
> poMD
= fMemory
;
714 if (kWalkSyncIn
& op
) {
715 bytes
= poMD
->writeBytes(state
->fPreparedOffset
,
716 state
->fCopyMD
->getBytesNoCopy(),
717 state
->fPreparedLength
);
719 bytes
= poMD
->readBytes(state
->fPreparedOffset
,
720 state
->fCopyMD
->getBytesNoCopy(),
721 state
->fPreparedLength
);
723 DEBG("fCopyMD %s %lx bytes\n", (kWalkSyncIn
& op
) ? "wrote" : "read", bytes
);
724 ret
= (bytes
== state
->fPreparedLength
) ? kIOReturnSuccess
: kIOReturnUnderrun
;
726 ret
= kIOReturnSuccess
;
732 if (kWalkComplete
& op
) {
733 if (state
->fCopyPageAlloc
) {
734 vm_page_free_list(state
->fCopyPageAlloc
, FALSE
);
735 state
->fCopyPageAlloc
= NULL
;
736 state
->fCopyPageCount
= 0;
738 if (state
->fCopyMD
) {
739 state
->fCopyMD
.reset();
742 state
->fPrepared
= false;
748 IODMACommand::getNumAddressBits(void)
750 return (UInt8
) fNumAddressBits
;
754 IODMACommand::getAlignment(void)
756 return fAlignMask
+ 1;
760 IODMACommand::getAlignmentLength(void)
762 return fAlignMaskLength
+ 1;
766 IODMACommand::getAlignmentInternalSegments(void)
768 return fAlignMaskInternalSegments
+ 1;
772 IODMACommand::prepareWithSpecification(SegmentFunction outSegFunc
,
773 const SegmentOptions
* segmentOptions
,
774 uint32_t mappingOptions
,
784 return kIOReturnNotPermitted
;
787 ret
= setSpecification(outSegFunc
, segmentOptions
, mappingOptions
, mapper
);
788 if (kIOReturnSuccess
!= ret
) {
792 ret
= prepare(offset
, length
, flushCache
, synchronize
);
798 IODMACommand::prepareWithSpecification(SegmentFunction outSegFunc
,
799 UInt8 numAddressBits
,
800 UInt64 maxSegmentSize
,
801 MappingOptions mappingOptions
,
802 UInt64 maxTransferSize
,
810 SegmentOptions segmentOptions
=
812 .fStructSize
= sizeof(segmentOptions
),
813 .fNumAddressBits
= numAddressBits
,
814 .fMaxSegmentSize
= maxSegmentSize
,
815 .fMaxTransferSize
= maxTransferSize
,
816 .fAlignment
= alignment
,
817 .fAlignmentLength
= 1,
818 .fAlignmentInternalSegments
= alignment
821 return prepareWithSpecification(outSegFunc
, &segmentOptions
, mappingOptions
, mapper
,
822 offset
, length
, flushCache
, synchronize
);
827 IODMACommand::prepare(UInt64 offset
, UInt64 length
, bool flushCache
, bool synchronize
)
829 IODMACommandInternal
* state
= fInternalState
;
830 IOReturn ret
= kIOReturnSuccess
;
831 uint32_t mappingOptions
= fMappingOptions
;
833 // check specification has been set
835 return kIOReturnNotReady
;
839 length
= fMDSummary
.fLength
;
842 if (length
> fMaxTransferSize
) {
843 return kIOReturnNoSpace
;
847 if ((state
->fPreparedOffset
!= offset
)
848 || (state
->fPreparedLength
!= length
)) {
849 ret
= kIOReturnNotReady
;
852 if (fAlignMaskLength
& length
) {
853 return kIOReturnNotAligned
;
856 if (atop_64(state
->fPreparedLength
) > UINT_MAX
) {
857 return kIOReturnVMError
;
859 state
->fPreparedOffset
= offset
;
860 state
->fPreparedLength
= length
;
862 state
->fMisaligned
= false;
863 state
->fDoubleBuffer
= false;
864 state
->fPrepared
= false;
865 state
->fCopyNext
= NULL
;
866 state
->fCopyPageAlloc
= NULL
;
867 state
->fCopyPageCount
= 0;
868 state
->fNextRemapPage
= NULL
;
869 state
->fCopyMD
= NULL
;
870 state
->fLocalMapperAlloc
= 0;
871 state
->fLocalMapperAllocValid
= false;
872 state
->fLocalMapperAllocLength
= 0;
874 state
->fSourceAlignMask
= fAlignMask
;
876 state
->fSourceAlignMask
&= page_mask
;
879 state
->fCursor
= state
->fIterateOnly
880 || (!state
->fCheckAddressing
881 && (!state
->fSourceAlignMask
882 || ((fMDSummary
.fPageAlign
& (1 << 31)) && (0 == (fMDSummary
.fPageAlign
& state
->fSourceAlignMask
)))));
884 if (!state
->fCursor
) {
885 IOOptionBits op
= kWalkPrepare
| kWalkPreflight
;
892 if (IS_NONCOHERENT(mappingOptions
) && flushCache
) {
893 if (state
->fCopyMD
) {
894 state
->fCopyMD
->performOperation(kIOMemoryIncoherentIOStore
, 0, length
);
896 fMemory
->performOperation(kIOMemoryIncoherentIOStore
, offset
, length
);
901 IOMDDMAMapArgs mapArgs
;
902 bzero(&mapArgs
, sizeof(mapArgs
));
903 mapArgs
.fMapper
= fMapper
.get();
904 mapArgs
.fCommand
= this;
905 mapArgs
.fMapSpec
.device
= state
->fDevice
;
906 mapArgs
.fMapSpec
.alignment
= fAlignMask
+ 1;
907 mapArgs
.fMapSpec
.numAddressBits
= fNumAddressBits
? ((UInt8
) fNumAddressBits
) : 64;
908 mapArgs
.fLength
= state
->fPreparedLength
;
909 OSSharedPtr
<IOMemoryDescriptor
> md
= state
->fCopyMD
;
914 mapArgs
.fOffset
= state
->fPreparedOffset
;
917 ret
= md
->dmaCommandOperation(kIOMDDMAMap
, &mapArgs
, sizeof(mapArgs
));
919 if ((kIOReturnSuccess
== ret
)
920 && mapArgs
.fAllocLength
921 && (mapArgs
.fAllocLength
!= mapArgs
.fLength
)) {
924 IOMDDMAWalkSegmentState walkState
;
925 IOMDDMAWalkSegmentArgs
* walkArgs
= (IOMDDMAWalkSegmentArgs
*) (void *)&walkState
;
928 IOPhysicalLength segLen
;
930 uint64_t phys
, align
;
931 uint64_t mapperPageMask
;
932 uint64_t mapperPageShift
;
933 uint64_t insertOffset
;
937 assert(mapArgs
.fAllocLength
> mapArgs
.fLength
);
939 mapperPageMask
= fMapper
->getPageSize();
940 assert(mapperPageMask
);
942 mapperPageShift
= (64 - __builtin_clzll(mapperPageMask
));
943 walkArgs
->fMapped
= false;
944 length
= state
->fPreparedLength
;
945 mdOp
= kIOMDFirstSegment
;
947 for (index
= 0; index
< length
; segCount
++) {
948 walkArgs
->fOffset
= state
->fPreparedOffset
+ index
;
950 ret
= md
->dmaCommandOperation(mdOp
, &walkState
, sizeof(walkState
));
951 mdOp
= kIOMDWalkSegments
;
952 assert(kIOReturnSuccess
== ret
);
953 if (ret
!= kIOReturnSuccess
) {
954 panic("dmaCommandOperation");
956 segLen
= walkArgs
->fLength
;
959 if (ret
!= kIOReturnSuccess
) {
964 if (LOGTAG
== fMemory
->getTag()) {
965 IOLog("DMA[%p] alloc 0x%qx, 0x%qx\n", this, mapArgs
.fAlloc
, mapArgs
.fAllocLength
);
967 #endif /* defined(LOGTAG) */
969 state
->fMapSegments
= IONewZero(IODMACommandMapSegment
, segCount
);
970 if (!state
->fMapSegments
) {
971 ret
= kIOReturnNoMemory
;
974 state
->fMapSegmentsCount
= segCount
;
976 switch (kIODirectionOutIn
& fMDSummary
.fDirection
) {
977 case kIODirectionOut
:
978 mapOptions
= kIODMAMapReadAccess
;
981 mapOptions
= kIODMAMapWriteAccess
;
984 mapOptions
= kIODMAMapReadAccess
| kIODMAMapWriteAccess
;
988 mdOp
= kIOMDFirstSegment
;
990 for (insertOffset
= 0, index
= 0; index
< length
; segCount
++) {
991 walkArgs
->fOffset
= state
->fPreparedOffset
+ index
;
992 ret
= md
->dmaCommandOperation(mdOp
, &walkState
, sizeof(walkState
));
993 mdOp
= kIOMDWalkSegments
;
994 if (ret
!= kIOReturnSuccess
) {
995 panic("dmaCommandOperation 0x%x", ret
);
997 phys
= walkArgs
->fIOVMAddr
;
998 segLen
= walkArgs
->fLength
;
1001 if (LOGTAG
== fMemory
->getTag()) {
1002 IOLog("DMA[%p] phys[%d] 0x%qx, 0x%qx\n", this, segCount
, (uint64_t) phys
, (uint64_t) segLen
);
1004 #endif /* defined(LOGTAG) */
1006 align
= (phys
& mapperPageMask
);
1009 if (LOGTAG
== fMemory
->getTag()) {
1010 IOLog("DMA[%p] runs[%d] dmaoff 0x%qx, mapoff 0x%qx, align 0x%qx\n", this, segCount
, index
, insertOffset
, align
);
1012 #endif /* defined(LOGTAG) */
1014 assert(segCount
< state
->fMapSegmentsCount
);
1015 state
->fMapSegments
[segCount
].fDMAOffset
= state
->fPreparedOffset
+ index
;
1016 state
->fMapSegments
[segCount
].fMapOffset
= insertOffset
;
1017 state
->fMapSegments
[segCount
].fPageOffset
= align
;
1020 // segment page align
1021 segLen
= ((phys
+ segLen
+ mapperPageMask
) & ~mapperPageMask
);
1024 insertOffset
+= segLen
;
1026 state
->fLocalMapperAllocBase
= (mapArgs
.fAlloc
& ~mapperPageMask
);
1028 if (LOGTAG
== fMemory
->getTag()) {
1029 IOLog("IODMACommand fMapSegmentsCount %d\n", state
->fMapSegmentsCount
);
1031 #endif /* defined(LOGTAG) */
1034 if (kIOReturnSuccess
== ret
) {
1035 state
->fLocalMapperAlloc
= mapArgs
.fAlloc
;
1036 state
->fLocalMapperAllocValid
= true;
1037 state
->fLocalMapperAllocLength
= mapArgs
.fAllocLength
;
1040 if (kIOReturnSuccess
== ret
) {
1041 state
->fPrepared
= true;
1048 IODMACommand::complete(bool invalidateCache
, bool synchronize
)
1050 IODMACommandInternal
* state
= fInternalState
;
1051 IOReturn ret
= kIOReturnSuccess
;
1052 OSSharedPtr
<IOMemoryDescriptor
> copyMD
;
1055 return kIOReturnNotReady
;
1059 copyMD
= state
->fCopyMD
;
1061 if (IS_NONCOHERENT(fMappingOptions
) && invalidateCache
) {
1063 copyMD
->performOperation(kIOMemoryIncoherentIOFlush
, 0, state
->fPreparedLength
);
1065 OSSharedPtr
<IOMemoryDescriptor
> md
= fMemory
;
1066 md
->performOperation(kIOMemoryIncoherentIOFlush
, state
->fPreparedOffset
, state
->fPreparedLength
);
1070 if (!state
->fCursor
) {
1071 IOOptionBits op
= kWalkComplete
;
1078 if (state
->fLocalMapperAllocValid
) {
1079 IOMDDMAMapArgs mapArgs
;
1080 bzero(&mapArgs
, sizeof(mapArgs
));
1081 mapArgs
.fMapper
= fMapper
.get();
1082 mapArgs
.fCommand
= this;
1083 mapArgs
.fAlloc
= state
->fLocalMapperAlloc
;
1084 mapArgs
.fAllocLength
= state
->fLocalMapperAllocLength
;
1085 OSSharedPtr
<IOMemoryDescriptor
> md
= copyMD
;
1087 mapArgs
.fOffset
= 0;
1090 mapArgs
.fOffset
= state
->fPreparedOffset
;
1093 ret
= md
->dmaCommandOperation(kIOMDDMAUnmap
, &mapArgs
, sizeof(mapArgs
));
1095 state
->fLocalMapperAlloc
= 0;
1096 state
->fLocalMapperAllocValid
= false;
1097 state
->fLocalMapperAllocLength
= 0;
1098 if (state
->fMapSegments
) {
1099 IODelete(state
->fMapSegments
, IODMACommandMapSegment
, state
->fMapSegmentsCount
);
1100 state
->fMapSegments
= NULL
;
1101 state
->fMapSegmentsCount
= 0;
1105 state
->fPrepared
= false;
1112 IODMACommand::getPreparedOffsetAndLength(UInt64
* offset
, UInt64
* length
)
1114 IODMACommandInternal
* state
= fInternalState
;
1116 return kIOReturnNotReady
;
1120 *offset
= state
->fPreparedOffset
;
1123 *length
= state
->fPreparedLength
;
1126 return kIOReturnSuccess
;
1130 IODMACommand::synchronize(IOOptionBits options
)
1132 IODMACommandInternal
* state
= fInternalState
;
1133 IOReturn ret
= kIOReturnSuccess
;
1136 if (kIODirectionOutIn
== (kIODirectionOutIn
& options
)) {
1137 return kIOReturnBadArgument
;
1141 return kIOReturnNotReady
;
1145 if (kForceDoubleBuffer
& options
) {
1146 if (state
->fDoubleBuffer
) {
1147 return kIOReturnSuccess
;
1149 ret
= complete(false /* invalidateCache */, true /* synchronize */);
1150 state
->fCursor
= false;
1151 state
->fForceDoubleBuffer
= true;
1152 ret
= prepare(state
->fPreparedOffset
, state
->fPreparedLength
, false /* flushCache */, true /* synchronize */);
1155 } else if (state
->fCursor
) {
1156 return kIOReturnSuccess
;
1159 if (kIODirectionIn
& options
) {
1160 op
|= kWalkSyncIn
| kWalkSyncAlways
;
1161 } else if (kIODirectionOut
& options
) {
1162 op
|= kWalkSyncOut
| kWalkSyncAlways
;
1170 struct IODMACommandTransferContext
{
1172 UInt64 bufferOffset
;
1177 kIODMACommandTransferOpReadBytes
= 1,
1178 kIODMACommandTransferOpWriteBytes
= 2
1182 IODMACommand::transferSegment(void *reference
,
1183 IODMACommand
*target
,
1186 UInt32 segmentIndex
)
1188 IODMACommandTransferContext
* context
= (IODMACommandTransferContext
*) reference
;
1189 UInt64 length
= min(segment
.fLength
, context
->remaining
);
1190 addr64_t ioAddr
= segment
.fIOVMAddr
;
1191 addr64_t cpuAddr
= ioAddr
;
1193 context
->remaining
-= length
;
1196 UInt64 copyLen
= length
;
1197 if ((kMapped
== MAPTYPE(target
->fMappingOptions
))
1198 && target
->fMapper
) {
1199 cpuAddr
= target
->fMapper
->mapToPhysicalAddress(ioAddr
);
1200 copyLen
= min(copyLen
, page_size
- (ioAddr
& (page_size
- 1)));
1203 if (copyLen
> (UINT_MAX
- PAGE_SIZE
+ 1)) {
1204 copyLen
= (UINT_MAX
- PAGE_SIZE
+ 1);
1207 switch (context
->op
) {
1208 case kIODMACommandTransferOpReadBytes
:
1209 copypv(cpuAddr
, context
->bufferOffset
+ (addr64_t
) context
->buffer
, (unsigned int) copyLen
,
1210 cppvPsrc
| cppvNoRefSrc
| cppvFsnk
| cppvKmap
);
1212 case kIODMACommandTransferOpWriteBytes
:
1213 copypv(context
->bufferOffset
+ (addr64_t
) context
->buffer
, cpuAddr
, (unsigned int) copyLen
,
1214 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
1218 context
->bufferOffset
+= copyLen
;
1221 return context
->remaining
? kIOReturnSuccess
: kIOReturnOverrun
;
1225 IODMACommand::transfer(IOOptionBits transferOp
, UInt64 offset
, void * buffer
, UInt64 length
)
1227 IODMACommandInternal
* state
= fInternalState
;
1228 IODMACommandTransferContext context
;
1229 Segment64 segments
[1];
1230 UInt32 numSegments
= 0 - 1;
1236 if (offset
>= state
->fPreparedLength
) {
1239 length
= min(length
, state
->fPreparedLength
- offset
);
1241 context
.buffer
= buffer
;
1242 context
.bufferOffset
= 0;
1243 context
.remaining
= length
;
1244 context
.op
= transferOp
;
1245 (void) genIOVMSegments(kWalkClient
, transferSegment
, &context
, &offset
, &segments
[0], &numSegments
);
1247 return length
- context
.remaining
;
1251 IODMACommand::readBytes(UInt64 offset
, void *bytes
, UInt64 length
)
1253 return transfer(kIODMACommandTransferOpReadBytes
, offset
, bytes
, length
);
1257 IODMACommand::writeBytes(UInt64 offset
, const void *bytes
, UInt64 length
)
1259 return transfer(kIODMACommandTransferOpWriteBytes
, offset
, const_cast<void *>(bytes
), length
);
1263 IODMACommand::genIOVMSegments(UInt64
*offsetP
,
1265 UInt32
*numSegmentsP
)
1267 return genIOVMSegments(kWalkClient
, clientOutputSegment
, (void *) fOutSeg
,
1268 offsetP
, segmentsP
, numSegmentsP
);
1272 IODMACommand::genIOVMSegments(uint32_t op
,
1273 InternalSegmentFunction outSegFunc
,
1277 UInt32
*numSegmentsP
)
1279 IODMACommandInternal
* internalState
= fInternalState
;
1280 IOOptionBits mdOp
= kIOMDWalkSegments
;
1281 IOReturn ret
= kIOReturnSuccess
;
1283 if (!(kWalkComplete
& op
) && !fActive
) {
1284 return kIOReturnNotReady
;
1287 if (!offsetP
|| !segmentsP
|| !numSegmentsP
|| !*numSegmentsP
) {
1288 return kIOReturnBadArgument
;
1291 IOMDDMAWalkSegmentArgs
*state
=
1292 (IOMDDMAWalkSegmentArgs
*)(void *) fState
;
1294 UInt64 offset
= *offsetP
+ internalState
->fPreparedOffset
;
1295 UInt64 memLength
= internalState
->fPreparedOffset
+ internalState
->fPreparedLength
;
1297 if (offset
>= memLength
) {
1298 return kIOReturnOverrun
;
1301 if ((offset
== internalState
->fPreparedOffset
) || (offset
!= state
->fOffset
) || internalState
->fNewMD
) {
1303 internalState
->fIOVMAddrValid
= state
->fIOVMAddr
= 0;
1304 internalState
->fNextRemapPage
= NULL
;
1305 internalState
->fNewMD
= false;
1306 mdOp
= kIOMDFirstSegment
;
1308 if (internalState
->fLocalMapperAllocValid
) {
1309 state
->fMapped
= true;
1310 state
->fMappedBase
= internalState
->fLocalMapperAlloc
;
1312 state
->fMapped
= false;
1317 UInt32 segIndex
= 0;
1318 UInt32 numSegments
= *numSegmentsP
;
1319 Segment64 curSeg
= { 0, 0 };
1320 bool curSegValid
= false;
1323 if (fNumAddressBits
&& (fNumAddressBits
< 64)) {
1324 maxPhys
= (1ULL << fNumAddressBits
);
1330 while (internalState
->fIOVMAddrValid
|| (state
->fOffset
< memLength
)) {
1332 if (!internalState
->fIOVMAddrValid
) {
1335 state
->fOffset
= offset
;
1336 state
->fLength
= memLength
- offset
;
1341 if (internalState
->fLocalMapperAllocValid
) {
1342 if (!internalState
->fMapSegmentsCount
) {
1343 state
->fIOVMAddr
= internalState
->fLocalMapperAlloc
+ offset
- internalState
->fPreparedOffset
;
1344 rtn
= kIOReturnSuccess
;
1352 uint64_t off2Ind
= internalState
->fOffset2Index
;
1354 // Validate the previous offset
1356 && (offset
== internalState
->fNextOffset
|| off2Ind
<= offset
)) {
1357 ind
= internalState
->fIndex
;
1359 ind
= off2Ind
= 0; // Start from beginning
1362 if (LOGTAG
== fMemory
->getTag()) {
1363 IOLog("DMA[%p] offsets 0x%qx, 0x%qx, 0x%qx ind %qd\n", this, offset
, internalState
->fPreparedOffset
, internalState
->fNextOffset
, ind
);
1365 #endif /* defined(LOGTAG) */
1367 // Scan through iopl info blocks looking for block containing offset
1368 while (ind
< internalState
->fMapSegmentsCount
&& offset
>= internalState
->fMapSegments
[ind
].fDMAOffset
) {
1371 if (ind
< internalState
->fMapSegmentsCount
) {
1372 length
= internalState
->fMapSegments
[ind
].fDMAOffset
;
1376 length
-= offset
; // Remainder within iopl
1378 // Go back to actual range as search goes past it
1380 off2Ind
= internalState
->fMapSegments
[ind
].fDMAOffset
;
1382 // Subtract offset till this iopl in total list
1383 runOffset
= offset
- off2Ind
;
1385 // Compute an offset relative to the mapped base
1387 runOffset
+= internalState
->fMapSegments
[ind
].fPageOffset
;
1388 address
= internalState
->fLocalMapperAllocBase
+ internalState
->fMapSegments
[ind
].fMapOffset
+ runOffset
;
1390 if (LOGTAG
== fMemory
->getTag()) {
1391 IOLog("DMA[%p] addrlen 0x%qx, 0x%qx\n", this, address
, length
);
1393 #endif /* defined(LOGTAG) */
1395 state
->fIOVMAddr
= address
;
1396 state
->fLength
= length
;
1398 internalState
->fIndex
= ind
;
1399 internalState
->fOffset2Index
= off2Ind
;
1400 internalState
->fNextOffset
= state
->fOffset
+ length
;
1402 rtn
= kIOReturnSuccess
;
1409 IOMemoryDescriptor
* memory
=
1410 internalState
->fCopyMD
? internalState
->fCopyMD
.get() : fMemory
.get();
1411 rtn
= memory
->dmaCommandOperation(mdOp
, fState
, sizeof(fState
));
1412 mdOp
= kIOMDWalkSegments
;
1416 && !ml_at_interrupt_context()
1417 && (rtn
== kIOReturnSuccess
)
1419 && strcmp("AppleNVMeMMU", fMapper
->getName())) {
1420 uint64_t checkOffset
;
1421 IOPhysicalLength segLen
;
1422 IOMemoryDescriptor
* memory
=
1423 internalState
->fCopyMD
? internalState
->fCopyMD
.get() : fMemory
.get();
1424 for (checkOffset
= 0; checkOffset
< state
->fLength
;) {
1425 addr64_t phys
= memory
->getPhysicalSegment(offset
+ checkOffset
, &segLen
, kIOMemoryMapperNone
);
1426 addr64_t mapperPhys
;
1428 mapperPhys
= fMapper
->mapToPhysicalAddress(state
->fIOVMAddr
+ checkOffset
);
1429 mapperPhys
|= (phys
& (fMapper
->getPageSize() - 1));
1430 if (mapperPhys
!= phys
) {
1431 panic("DMA[%p] mismatch at offset %llx + %llx, dma %llx mapperPhys %llx != %llx, len %llx\n",
1432 this, offset
, checkOffset
,
1433 state
->fIOVMAddr
+ checkOffset
, mapperPhys
, phys
, state
->fLength
);
1435 checkOffset
+= page_size
- (phys
& page_mask
);
1439 if (rtn
== kIOReturnSuccess
) {
1440 internalState
->fIOVMAddrValid
= true;
1441 assert(state
->fLength
);
1442 if (curSegValid
&& ((curSeg
.fIOVMAddr
+ curSeg
.fLength
) == state
->fIOVMAddr
)) {
1443 UInt64 length
= state
->fLength
;
1445 curSeg
.fLength
+= length
;
1446 internalState
->fIOVMAddrValid
= state
->fIOVMAddr
= 0;
1448 } else if (rtn
== kIOReturnOverrun
) {
1449 internalState
->fIOVMAddrValid
= state
->fIOVMAddr
= state
->fLength
= 0; // At end
1455 // seg = state, offset = end of seg
1457 UInt64 length
= state
->fLength
;
1459 curSeg
.fIOVMAddr
= state
->fIOVMAddr
;
1460 curSeg
.fLength
= length
;
1462 internalState
->fIOVMAddrValid
= state
->fIOVMAddr
= 0;
1465 if (!internalState
->fIOVMAddrValid
) {
1467 if ((kWalkClient
& op
) && (curSeg
.fIOVMAddr
+ curSeg
.fLength
- 1) > maxPhys
) {
1468 if (internalState
->fCursor
) {
1469 curSegValid
= curSeg
.fIOVMAddr
= 0;
1470 ret
= kIOReturnMessageTooLarge
;
1472 } else if (curSeg
.fIOVMAddr
<= maxPhys
) {
1473 UInt64 remain
, newLength
;
1475 newLength
= (maxPhys
+ 1 - curSeg
.fIOVMAddr
);
1476 DEBG("trunc %qx, %qx-> %qx\n", curSeg
.fIOVMAddr
, curSeg
.fLength
, newLength
);
1477 remain
= curSeg
.fLength
- newLength
;
1478 state
->fIOVMAddr
= newLength
+ curSeg
.fIOVMAddr
;
1479 internalState
->fIOVMAddrValid
= true;
1480 curSeg
.fLength
= newLength
;
1481 state
->fLength
= remain
;
1484 UInt64 addr
= curSeg
.fIOVMAddr
;
1485 ppnum_t addrPage
= (ppnum_t
) atop_64(addr
);
1486 vm_page_t remap
= NULL
;
1487 UInt64 remain
, newLength
;
1489 DEBG("sparse switch %qx, %qx ", addr
, curSeg
.fLength
);
1491 remap
= internalState
->fNextRemapPage
;
1492 if (remap
&& (addrPage
== vm_page_get_offset(remap
))) {
1494 for (remap
= internalState
->fCopyPageAlloc
;
1495 remap
&& (addrPage
!= vm_page_get_offset(remap
));
1496 remap
= vm_page_get_next(remap
)) {
1501 panic("no remap page found");
1504 curSeg
.fIOVMAddr
= ptoa_64(vm_page_get_phys_page(remap
))
1505 + (addr
& PAGE_MASK
);
1507 internalState
->fNextRemapPage
= vm_page_get_next(remap
);
1509 newLength
= PAGE_SIZE
- (addr
& PAGE_MASK
);
1510 if (newLength
< curSeg
.fLength
) {
1511 remain
= curSeg
.fLength
- newLength
;
1512 state
->fIOVMAddr
= addr
+ newLength
;
1513 internalState
->fIOVMAddrValid
= true;
1514 curSeg
.fLength
= newLength
;
1515 state
->fLength
= remain
;
1518 DEBG("-> %qx, %qx offset %qx\n", curSeg
.fIOVMAddr
, curSeg
.fLength
, offset
);
1522 // reduce size of output segment
1523 uint64_t reduce
, leftover
= 0;
1526 if (curSeg
.fLength
> fMaxSegmentSize
) {
1527 leftover
+= curSeg
.fLength
- fMaxSegmentSize
;
1528 curSeg
.fLength
= fMaxSegmentSize
;
1529 state
->fIOVMAddr
= curSeg
.fLength
+ curSeg
.fIOVMAddr
;
1530 internalState
->fIOVMAddrValid
= true;
1533 // alignment current length
1535 reduce
= (curSeg
.fLength
& fAlignMaskLength
);
1536 if (reduce
&& (curSeg
.fLength
> reduce
)) {
1538 curSeg
.fLength
-= reduce
;
1539 state
->fIOVMAddr
= curSeg
.fLength
+ curSeg
.fIOVMAddr
;
1540 internalState
->fIOVMAddrValid
= true;
1543 // alignment next address
1545 reduce
= (state
->fIOVMAddr
& fAlignMaskInternalSegments
);
1546 if (reduce
&& (curSeg
.fLength
> reduce
)) {
1548 curSeg
.fLength
-= reduce
;
1549 state
->fIOVMAddr
= curSeg
.fLength
+ curSeg
.fIOVMAddr
;
1550 internalState
->fIOVMAddrValid
= true;
1554 DEBG("reduce seg by 0x%llx @ 0x%llx [0x%llx, 0x%llx]\n",
1556 curSeg
.fIOVMAddr
, curSeg
.fLength
);
1557 state
->fLength
= leftover
;
1563 if (internalState
->fCursor
) {
1567 mask
= (segIndex
? fAlignMaskInternalSegments
: internalState
->fSourceAlignMask
);
1568 misaligned
= (0 != (mask
& curSeg
.fIOVMAddr
));
1570 mask
= fAlignMaskLength
;
1571 misaligned
|= (0 != (mask
& curSeg
.fLength
));
1575 DEBG("cursor misaligned %qx:%qx\n", curSeg
.fIOVMAddr
, curSeg
.fLength
);
1577 curSegValid
= curSeg
.fIOVMAddr
= 0;
1578 ret
= kIOReturnNotAligned
;
1583 if (offset
>= memLength
) {
1584 curSeg
.fLength
-= (offset
- memLength
);
1586 internalState
->fIOVMAddrValid
= state
->fIOVMAddr
= state
->fLength
= 0; // At end
1591 if (internalState
->fIOVMAddrValid
) {
1592 if ((segIndex
+ 1 == numSegments
)) {
1596 if ((LOGTAG
== fMemory
->getTag()) && (kWalkClient
== op
)) {
1597 IOLog("DMA[%p] outseg 0x%qx, 0x%qx\n", this, curSeg
.fIOVMAddr
, curSeg
.fLength
);
1599 #endif /* defined(LOGTAG) */
1600 ret
= (*outSegFunc
)(reference
, this, curSeg
, segmentsP
, segIndex
++);
1601 curSegValid
= curSeg
.fIOVMAddr
= 0;
1602 if (kIOReturnSuccess
!= ret
) {
1610 if ((LOGTAG
== fMemory
->getTag()) && (kWalkClient
== op
)) {
1611 IOLog("DMA[%p] outseg 0x%qx, 0x%qx\n", this, curSeg
.fIOVMAddr
, curSeg
.fLength
);
1613 #endif /* defined(LOGTAG) */
1614 ret
= (*outSegFunc
)(reference
, this, curSeg
, segmentsP
, segIndex
++);
1617 if (kIOReturnSuccess
== ret
) {
1618 state
->fOffset
= offset
;
1619 *offsetP
= offset
- internalState
->fPreparedOffset
;
1620 *numSegmentsP
= segIndex
;
1626 IODMACommand::clientOutputSegment(
1627 void *reference
, IODMACommand
*target
,
1628 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1630 SegmentFunction segmentFunction
= (SegmentFunction
) reference
;
1631 IOReturn ret
= kIOReturnSuccess
;
1633 if (target
->fNumAddressBits
&& (target
->fNumAddressBits
< 64)
1634 && ((segment
.fIOVMAddr
+ segment
.fLength
- 1) >> target
->fNumAddressBits
)
1635 && (target
->reserved
->fLocalMapperAllocValid
|| !target
->fMapper
)) {
1636 DEBG("kIOReturnMessageTooLarge(fNumAddressBits) %qx, %qx\n", segment
.fIOVMAddr
, segment
.fLength
);
1637 ret
= kIOReturnMessageTooLarge
;
1640 if (!(*segmentFunction
)(target
, segment
, vSegList
, outSegIndex
)) {
1641 DEBG("kIOReturnMessageTooLarge(fOutSeg) %qx, %qx\n", segment
.fIOVMAddr
, segment
.fLength
);
1642 ret
= kIOReturnMessageTooLarge
;
1649 IODMACommand::genIOVMSegments(SegmentFunction segmentFunction
,
1652 UInt32
*numSegmentsP
)
1654 return genIOVMSegments(kWalkClient
, clientOutputSegment
, (void *) segmentFunction
,
1655 offsetP
, segmentsP
, numSegmentsP
);
1659 IODMACommand::OutputHost32(IODMACommand
*,
1660 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1662 Segment32
*base
= (Segment32
*) vSegList
;
1663 base
[outSegIndex
].fIOVMAddr
= (UInt32
) segment
.fIOVMAddr
;
1664 base
[outSegIndex
].fLength
= (UInt32
) segment
.fLength
;
1669 IODMACommand::OutputBig32(IODMACommand
*,
1670 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1672 const UInt offAddr
= outSegIndex
* sizeof(Segment32
);
1673 const UInt offLen
= offAddr
+ sizeof(UInt32
);
1674 OSWriteBigInt32(vSegList
, offAddr
, (UInt32
) segment
.fIOVMAddr
);
1675 OSWriteBigInt32(vSegList
, offLen
, (UInt32
) segment
.fLength
);
1680 IODMACommand::OutputLittle32(IODMACommand
*,
1681 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1683 const UInt offAddr
= outSegIndex
* sizeof(Segment32
);
1684 const UInt offLen
= offAddr
+ sizeof(UInt32
);
1685 OSWriteLittleInt32(vSegList
, offAddr
, (UInt32
) segment
.fIOVMAddr
);
1686 OSWriteLittleInt32(vSegList
, offLen
, (UInt32
) segment
.fLength
);
1691 IODMACommand::OutputHost64(IODMACommand
*,
1692 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1694 Segment64
*base
= (Segment64
*) vSegList
;
1695 base
[outSegIndex
] = segment
;
1700 IODMACommand::OutputBig64(IODMACommand
*,
1701 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1703 const UInt offAddr
= outSegIndex
* sizeof(Segment64
);
1704 const UInt offLen
= offAddr
+ sizeof(UInt64
);
1705 OSWriteBigInt64(vSegList
, offAddr
, (UInt64
) segment
.fIOVMAddr
);
1706 OSWriteBigInt64(vSegList
, offLen
, (UInt64
) segment
.fLength
);
1711 IODMACommand::OutputLittle64(IODMACommand
*,
1712 Segment64 segment
, void *vSegList
, UInt32 outSegIndex
)
1714 const UInt offAddr
= outSegIndex
* sizeof(Segment64
);
1715 const UInt offLen
= offAddr
+ sizeof(UInt64
);
1716 OSWriteLittleInt64(vSegList
, offAddr
, (UInt64
) segment
.fIOVMAddr
);
1717 OSWriteLittleInt64(vSegList
, offLen
, (UInt64
) segment
.fLength
);