home *** CD-ROM | disk | FTP | other *** search
- /* DMATransfer.c */
- /*
- * DMATransfer.c
- * Copyright © 1995 Apple Computer Inc. All rights reserved.
- */
- /* .___________________________________________________________________________________.
- | This library simplifies using PrepareMemoryForIO with DMA and non-DMA hardware |
- | devices. These functions can be called from any interrupt level. |
- | |
- | PrepareDMATransfer prepares the next segment (logical or physical) that can |
- | be computed from the current state of the I/O table. The caller must adapt the |
- | result if required maximum transfer length limitations. |
- | |
- | Usage: |
- | status = PrepareMemoryForIO(&myIOTable); // Do first prepare |
- | if (status == noErr) { // Start dma preparation |
- | status = InitializeDMATransfer( |
- | &myIOTable, |
- | myLogicalAlignment, |
- | &myDMATable |
- | ); |
- | while (status == noErr) { // Start dma operation |
- | status = PrepareDMATransfer( |
- | &myDMATable, |
- | &myNextTransfer, |
- | &nextIsLogical |
- | ); |
- | if (status == noErr) { |
- | if (nextIsLogical) |
- | DoLogicalTransfer(&myNextTransfer); |
- | else { |
- | DoPhysicalTransfer(&myNextTransfer); |
- | } |
- | } // For all DMA segments for this preparation. |
- | } // while there is data to transmit |
- | } // if PrepareMemoryForIO succeeded |
- .___________________________________________________________________________________.
- */
-
- #include "DMATransfer.h"
- #include <DriverServices.h>
-
- #ifndef FALSE
- #define FALSE 0
- #define TRUE 1
- #endif
- #define DMA (*dmaTablePtr)
- #define IO (*ioTablePtr)
- static UInt32 gPageSize; /* GetLogicalPageSize() */
- static UInt32 gPageMask; /* pageSize - 1 */
-
- static void ComputeThisArea(
- DMATransferInfoPtr dmaTablePtr
- );
- static OSStatus GetNextSegment(
- DMATransferInfoPtr dmaTablePtr
- );
- static Boolean GetNextPhysicalTransfer(
- DMATransferInfoPtr dmaTablePtr
- );
-
- #ifndef TESTING
- #define TESTING 0
- #endif
- #if TESTING
- #include <stdio.h>
- #define LOG(what) printf what
- #else
- #define LOG(what) /* Nothing */
- #endif
-
- /* .___________________________________________________________________________________.
- | InitializeDMATransfer |
- | |
- | Initialize the DMATransferInfo record. |
- | Input: |
- | ioTable The prepared I/O Preparation table. It is "ready to run" |
- | logicalGranularity This is a power of two that is used to group the transfer |
- | into logical and physical segments. If zero, only physical |
- | transfers will be reported. If one and a logical segment |
- | begins on an odd-byte boundary, PrepareDMATransfer will |
- | return a one-byte logical transfer, then one or more |
- | physical transfers then, if necessary, a one-byte logical |
- | transfer. |
- | |
- | Output: |
- | dmaTablePtr The DMATransferInfo record that will manage this transfer. |
- | |
- | Result: |
- | noErr Normal. |
- | paramErr Bad parameters (ioTable or dmaTablePtr are NULL or an error |
- | in the IOTable parameters). |
- | |
- | Set the IOTable parameter block as follows: |
- | logicalMapping Required |
- | physicalMapping Required. |
- | mappingEntryCount > 0 |
- | options: |
- | kIOLogicalRanges Required if non-zero logical granularity. |
- | kIOMinimalLogicalMapping Required if non-zero logical granularity. |
- | kIOIsInput or kIOIsOutput One is required |
- .___________________________________________________________________________________.
- */
- OSStatus
- InitializeDMATransfer(
- const IOPreparationTable *ioTablePtr,
- UInt32 logicalAlignment,
- DMATransferInfoPtr dmaTablePtr
- )
- {
- OSStatus osStatus;
- UInt32 alignmentMask;
-
- if (gPageSize == 0) {
- gPageSize = GetLogicalPageSize();
- gPageMask = gPageSize - 1;
- }
- osStatus = noErr;
- alignmentMask = logicalAlignment - 1;
- if (ioTablePtr == NULL
- || dmaTablePtr == NULL
- || ioTablePtr->physicalMapping == NULL
- || ioTablePtr->mappingEntryCount == 0
- || ioTablePtr->lengthPrepared == 0) {
- LOG(("InitialDMATransfer: missing parameter or IOPreparationTable error\n"));
- osStatus = paramErr;
- }
- else if ((logicalAlignment & ~(-logicalAlignment)) != 0) {
- LOG(("InitializeDMATransfer: logicalAligment %lu must be power of 2\n",
- logicalAlignment));
- osStatus = paramErr;
- }
- else if (logicalAlignment >= gPageSize) {
- LOG(("InitializeDMATransfer: logicalAligment %lu must be < page size %lu\n",
- logicalAlignment, gPageSize));
- osStatus = paramErr;
- }
- else if ((ioTablePtr->options & kIOLogicalRanges) != 0
- && (ioTablePtr->logicalMapping == NULL
- || (ioTablePtr->options & kIOMinimalLogicalMapping) == 0)) {
- LOG(("InitializeDMATransfer: logical transfer requires logical mapping\n"));
- osStatus = paramErr;
- }
- else if ((ioTablePtr->options & kIOLogicalRanges) == 0
- && logicalAlignment != 0
- && ((((UInt32) ioTablePtr->physicalMapping[0]) & alignmentMask) != 0
- || (ioTablePtr->lengthPrepared & alignmentMask) != 0)) {
- LOG(("InitializeDMATransfer: unaligned physical transfer\n"));
- osStatus = paramErr;
- }
- else {
- /*
- * Setup our private globals and call GetNextSegment to compute the first
- * (or only) transfer segment. We call it here as this function is probably
- * being called at "task" context and, for simple transfers, we won't have
- * to scan the physical table in a primary interrupt service routine.
- *
- * This library presumes that it is the only preparation. Some adjustments
- * will be needed to support partial preparation.
- */
- DMA.ioTablePtr = ioTablePtr;
- DMA.logicalAlignment = logicalAlignment;
- if (IO.firstPrepared == 0) {
- /*
- * This is the first preparation: initialize the scatter-gather index.
- */
- DMA.scatterGatherIndex = 0;
- DMA.prepareCount = 0;
- DMA.rangeCount = 0;
- DMA.rangeLength = 0;
- }
- /*
- * The preparation writes the physical map from index zero.
- */
- DMA.physicalMapIndex = 0;
- DMA.prepareCount = 0;
- osStatus = GetNextSegment(dmaTablePtr);
- }
- return (osStatus);
- }
-
- /* .___________________________________________________________________________________.
- | PrepareDMATransfer |
- | |
- | Prepare the next DMA segment. |
- | Input: |
- | dmaTablePtr The DMATransferInfo record that will manage this transfer. |
- | |
- | Output: |
- | nextTransferAddress Gets the segment start address (required). |
- | nextTransferCount Gets the segment transfer count (required). |
- | nextIsLogical TRUE if this is a logical address. |
- | |
- | Result: |
- | noErr Normal |
- | paramErr Programming bug. |
- | eofErr Nothing more to transfer. |
- | |
- | Notes: |
- | |
- | eofErr is a normal status results. They should be replaced by |
- | by private error codes. |
- | |
- | If logical addresses are needed, the PrepareMemoryForIO must provide a "minimal |
- | logical mapping" table. |
- .___________________________________________________________________________________.
- */
- OSStatus
- PrepareDMATransfer(
- DMATransferInfoPtr dmaTablePtr,
- AddressRange *nextTransferRange,
- Boolean *nextIsLogical
- )
- {
- OSStatus osStatus;
- const IOPreparationTable *ioTablePtr;
-
- ioTablePtr = DMA.ioTablePtr;
- if (dmaTablePtr == NULL || nextTransferRange == NULL || nextIsLogical == NULL) {
- LOG(("Bogus PrepareDMATransfer parameters\n"));
- osStatus = paramErr;
- }
- else {
- osStatus = noErr;
- computeNextTransfer:
- if (DMA.logicalStart.length != 0) {
- *nextTransferRange = DMA.logicalStart;
- DMA.logicalStart.length = 0;
- *nextIsLogical = TRUE;
- }
- else if (GetNextPhysicalTransfer(dmaTablePtr)) {
- *nextTransferRange = DMA.physicalRange;
- *nextIsLogical = FALSE;
- }
- else if (DMA.logicalEnd.length != 0) {
- *nextTransferRange = DMA.logicalEnd;
- DMA.logicalEnd.length = 0;
- *nextIsLogical = TRUE;
- }
- else {
- /*
- * Get here to compute the next scatter-gather segment. GetNextSegment
- * will return eofErr when we run off the end of the entire "prepared"
- * transfer.
- */
- ++DMA.scatterGatherIndex;
- osStatus = GetNextSegment(dmaTablePtr);
- if (osStatus == noErr)
- goto computeNextTransfer;
- }
- }
- if (osStatus == noErr) {
- /*
- * We have some data to transfer: advance our indexes.
- */
- DMA.rangeCount += nextTransferRange->length;
- DMA.prepareCount += nextTransferRange->length;
- }
- return (osStatus);
- }
-
- /* .___________________________________________________________________________________.
- | GetNextSegment |
- | |
- | Compute a logical segment (either the only segment or the current scatter-gather |
- | segment). |
- | |
- | Input: |
- | dmaTablePtr The DMATransferInfo record that will manage this transfer. |
- | |
- | Output: |
- | The DMA global context is updated. |
- | |
- | Result: |
- | noErr Normal |
- | paramErr Programming bug. |
- | eofErr Nothing more to transfer. |
- | |
- | Notes: |
- | eofErr is an expected status result. It could be replaced by a private code. |
- .___________________________________________________________________________________.
- */
- static OSStatus
- GetNextSegment(
- DMATransferInfoPtr dmaTablePtr
- )
- {
- OSStatus osStatus;
- const IOPreparationTable *ioTablePtr;
- #define RANGE (IO.rangeInfo)
- #define RANGETABLE (IO.rangeInfo.multipleRanges.rangeTable)
-
- ioTablePtr = DMA.ioTablePtr;
- osStatus = noErr;
- if (DMA.prepareCount >= IO.lengthPrepared)
- osStatus = eofErr;
- else if (DMA.rangeCount < DMA.rangeLength) {
- /*
- * We can get here if we need several calls to PrepareMemoryForIO to
- * consume a single scatter-gather area.
- */
- ComputeThisArea(dmaTablePtr);
- }
- else if ((IO.options & kIOMultipleRanges) == 0) {
- /*
- * There is a single logical area (this is normal). If this function is
- * re-called, DMA.scatterGatherIndex will be non-zero (it was incremented
- * when we were previously called). Return eofErr to indicate a normal,
- * successful, completion.
- */
- if (DMA.scatterGatherIndex > 0)
- osStatus = eofErr;
- else {
- /*
- * This is the initial call for a single logical area. Compute the
- * logical and physical areas.
- */
- DMA.rangeLength = RANGE.range.length;
- ComputeThisArea(dmaTablePtr);
- }
- }
- else if (DMA.scatterGatherIndex >= RANGE.multipleRanges.entryCount)
- osStatus = eofErr;
- else {
- /*
- * We are processing a scatter-gather I/O table. Compute this segment.
- */
- DMA.rangeLength = RANGETABLE[DMA.scatterGatherIndex].length;
- ComputeThisArea(dmaTablePtr);
- }
- return (osStatus);
- #undef RANGETABLE
- #undef RANGE
- }
-
- /* .___________________________________________________________________________________.
- | ComputeThisArea |
- | |
- | Compute the current logical segment. The caller has selected the segment. |
- | This function creates the initial and final logical segments and adjusts the |
- | physical transfer parameters if necessary. |
- | |
- | Input: |
- | dmaTablePtr The DMATransferInfo record that will manage this transfer. |
- | dmaTablePtr->scatterGatherIndex is the index into the logical mapping table. |
- | |
- | Output: |
- | The DMA global context is updated. |
- | |
- | Result: |
- | none |
- .___________________________________________________________________________________.
- */
- static void
- ComputeThisArea(
- DMATransferInfoPtr dmaTablePtr
- )
- {
- const IOPreparationTable *ioTablePtr;
- static const AddressRange gNullAddressRange;
- ByteCount lastPageLength;
- ByteCount segmentLength;
- UInt32 alignmentMask;
- ByteCount firstPageLength; /* First physical chunk */
- LogicalAddress *logicalMapPtr;
- /*
- * To keep the line lengths reasonable, logicalBase will refer to the base
- * of the initial logical area represented as an integer. Don't make this a
- * variable as the actual DMA.logicalStart.base must always be correct.
- */
- #define logicalBase ((UInt32) DMA.logicalStart.base)
-
- ioTablePtr = DMA.ioTablePtr;
- DMA.logicalStart = gNullAddressRange;
- DMA.logicalEnd = gNullAddressRange;
- DMA.firstPageOffset = firstPageLength = DMA.physicalStart = 0;
- logicalMapPtr = &IO.logicalMapping[DMA.scatterGatherIndex * 2];
- /*
- * Get the actual transfer length; breaking it into initial, physical, and
- * final segments.
- */
- segmentLength = DMA.rangeLength;
- if ((segmentLength + DMA.prepareCount) > IO.lengthPrepared)
- segmentLength = (IO.lengthPrepared - DMA.prepareCount);
- DMA.physicalEnd = segmentLength;
- if ((IO.options & kIOLogicalRanges) != 0 /* Is logical alignment possible */
- && DMA.logicalAlignment != 0) { /* And logical alignment is needed */
- /*
- * Compute the logical transfer parameters.
- */
- alignmentMask = DMA.logicalAlignment - 1;
- DMA.logicalStart.base = logicalMapPtr[0];
- if ((logicalBase & alignmentMask) != 0) {
- DMA.logicalStart.length =
- DMA.logicalAlignment - (logicalBase & alignmentMask);
- }
- if (DMA.logicalStart.length > segmentLength)
- DMA.logicalStart.length = segmentLength;
- DMA.physicalStart += DMA.logicalStart.length;
- DMA.logicalEnd.length =
- (segmentLength - DMA.logicalStart.length) & alignmentMask;
- DMA.physicalEnd -= DMA.logicalEnd.length;
- }
- /*
- * If there is an initial logical area length, compute the base of the initial
- * logical area. The first physical transfer will be offset by the initial
- * logical length.
- */
- if (DMA.logicalStart.length != 0) {
- DMA.firstPageOffset = DMA.logicalStart.length;
- if (PageOffset(logicalBase + DMA.logicalStart.length) == 0) {
- /*
- * Since the initial logical area consumed the remainder of a physical
- * page, we'll move to the start of the next page.
- */
- ++DMA.physicalMapIndex;
- DMA.firstPageOffset = 0;
- }
- }
- /*
- * If there is a final logical area, compute its starting address. This is
- * also a good place to compute the length of the first physical page. (Note
- * that the initial logical segment is included in firstPageLength).
- */
- firstPageLength = gPageSize - PageOffset(logicalBase);
- if (firstPageLength > segmentLength)
- firstPageLength = segmentLength;
- if (DMA.logicalEnd.length != 0) {
- if (PageOffset(logicalBase) + segmentLength <= gPageSize) {
- /*
- * Since the entire transfer is contained within a single page,
- * PrepareMemoryForIO will only compute a single result logical page.
- * If there is no physical transfer, combine the initial and final
- * logical transfers. (Hmm. can this cause the fifo to choke?)
- */
- if (DMA.physicalStart >= DMA.physicalEnd) {
- DMA.logicalStart.length += DMA.logicalEnd.length;
- DMA.logicalEnd.length = 0;
- }
- else {
- /*
- * The final segment starts at the end of the (only) logical page.
- */
- DMA.logicalEnd.base = (void *)
- (logicalBase + segmentLength - DMA.logicalEnd.length);
- }
- }
- else {
- /*
- * There are multiple pages. The final logical transfer starts at
- * the base of the last page, taken from the IOTable plus the
- * amount of physical transfer that lives in the last physical page.
- * First, compute the number of bytes that will be transferred from
- * the last physical (i.e., logical) page. This will be a combination
- * of physical and logical transfers, and includes the final logical
- * transfer. PageOffset removes any intervening full pages.
- */
- lastPageLength = PageOffset(segmentLength - firstPageLength);
- DMA.logicalEnd.base = (void *) (
- ((UInt32) logicalMapPtr[1])
- + lastPageLength
- - DMA.logicalEnd.length
- );
- }
- }
- #undef logicalBase
- }
-
- /* .___________________________________________________________________________________.
- | GetNextPhysicalTransfer |
- | |
- | Compute the next physical segment. It begins from the current physical location |
- | (DMA.physicalFirstPrepared) and extends for as many pages as are physically |
- | contiguous. |
- | |
- | Input: |
- | dmaTablePtr The DMATransferInfo record that will manage this transfer. |
- | pageOffset Offset into the physical page -- this will be non-zero if |
- | this is the first physical page and we had required an |
- | initial logical transfer to handle unaligned memory. |
- | |
- | Output: |
- | The DMA global context is updated. |
- | |
- | Result: |
- | TRUE if there is a physical transfer remaining. |
- .___________________________________________________________________________________.
- */
- static Boolean
- GetNextPhysicalTransfer(
- DMATransferInfoPtr dmaTablePtr
- )
- {
- const IOPreparationTable *ioTablePtr;
- ByteCount newPosition;
- Boolean result;
-
- ioTablePtr = DMA.ioTablePtr;
- if (DMA.physicalStart >= DMA.physicalEnd) {
- DMA.physicalRange.length = 0;
- result = FALSE;
- }
- else {
- DMA.physicalRange.base = (void *)
- (((UInt32) IO.physicalMapping[DMA.physicalMapIndex])
- + DMA.firstPageOffset
- );
- DMA.firstPageOffset = 0;
- /*
- * The range length extends from the current page offset to the end of
- * the page. If we start at the beginning of the page, PageOffset will
- * be zero.
- */
- DMA.physicalRange.length =
- gPageSize - PageOffset((UInt32) DMA.physicalRange.base);
- newPosition = DMA.physicalStart + DMA.physicalRange.length;
- while (newPosition < DMA.physicalEnd
- && NextPageIsContiguous(IO.physicalMapping, DMA.physicalMapIndex)) {
- ++DMA.physicalMapIndex;
- DMA.physicalRange.length += gPageSize;
- newPosition += gPageSize;
- }
- /*
- * We've reached the end of the physical sequence -- or as far as we can
- * go this time. We'll always restart at the next sequence. Finally,
- * ensure that we didn't fall off the end of the preparation.
- */
- ++DMA.physicalMapIndex;
- if (newPosition > DMA.physicalEnd) {
- newPosition = DMA.physicalEnd;
- DMA.physicalRange.length = newPosition - DMA.physicalStart;
- }
- DMA.physicalStart = newPosition;
- result = TRUE;
- }
- return (result);
- }
-
- #if TESTING
- #include <stdlib.h>
- #include <console.h>
-
- #undef DMA
- #undef IO
-
- #define kWorkSize 32768
- #define kPageSize 4096
- #define kMaxScatterGather 16
- UInt8 gWorkArea[kWorkSize + kPageSize];
- UInt8 *gWorkAreaStart;
- UInt32 gPageAlign;
- IOPreparationTable gIOTable;
- AddressRange gScatterGatherTable[kMaxScatterGather];
- LogicalAddress gLogicalMapping[kMaxScatterGather * 2];
- PhysicalAddress gPhysicalMapping[(kWorkSize / kPageSize) + 2];
- DMATransferInfo gDMATable;
-
- typedef struct SimpleArea {
- UInt32 offset;
- UInt32 byteCount;
- } SimpleArea, *SimpleAreaPtr;
-
- SimpleArea gSimpleTest[] = {
- { 0, 16384 },
- #if 0
- { 1, 4096 },
- { 1, 16384 },
- { 2, 4096 },
- { 3, 4096 },
- { 5, 4096 },
- { 8, 4096 },
- { 13, 4096 },
- { 21, 4096 },
- { 0, 1 },
- { 0, 2 },
- { 0, 14 },
- { 0, 15 },
- { 0, 16 },
- { 0, 17 },
- { 0, 18 },
- { 4095, 1 },
- { 4095, 2 },
- { 4095, 3 },
- { 4095, 4 },
- { 4095, 4095 },
- { 4095, 4096 },
- { 4095, 4097 },
- { 4095, 8195 },
- { 8193, 517 },
- #endif
- { 0, 0 }
- };
- SimpleArea gSGTest1[] = { /* Simple SG area */
- { 0, 4096 },
- { 0, 0 }
- };
- SimpleArea gSGTest2[] = { /* Two simple areas */
- { 0, 4096 },
- { 8192, 4096 },
- { 0, 0 }
- };
- SimpleArea gSGTest3[] = { /* Three repeated logical transfers */
- { 0, 1 },
- { 0, 1 },
- { 0, 1 },
- { 0, 0 }
- };
- SimpleArea gSGTest4[] = { /* Two adjacent areas in one page */
- { 0, 512 },
- { 512, 512 },
- { 0, 0 }
- };
- SimpleArea gSGTest5[] = { /* Two identical areas */
- { 0, 512 },
- { 0, 512 },
- { 0, 0 }
- };
- SimpleArea gSGTest6[] = { /* Four randomly complex areas */
- { 0, 1 },
- { 8193, 517 },
- { 8193, 516 },
- { 0, 1 },
- { 0, 0 }
- };
- SimpleArea gSGTest7[] = {
- { 0, 16384 },
- { 8192, 16384 },
- { 0, 0 }
- };
- SimpleArea gSGTest8[] = {
- { 1, 1 },
- { 2, 1 },
- { 8193, 1 },
- { 0, 0 }
- };
-
- SimpleArea *gSGTestVector[] = {
- // gSGTest1, gSGTest2, gSGTest3, gSGTest4, gSGTest5, gSGTest6,
- gSGTest7, gSGTest8,
- NULL
- };
-
- #define CLEAR(what) BlockZero(&what, sizeof what)
-
- void TestSimpleArea(
- const SimpleAreaPtr simpleAreaPtr,
- ByteCount granularity
- );
- void TestScatterGatherArea(
- const SimpleAreaPtr sgAreaPtr, /* Vector */
- ByteCount granularity
- );
-
- #define ClearWorkArea() CLEAR(gWorkArea)
- Boolean UpdateWorkArea(
- UInt32 offset,
- ByteCount byteCount,
- AddressRange *thisTransferPtr
- );
- void CheckWorkArea(
- UInt32 offset,
- ByteCount byteCount
- );
- void DoPreparationAndTest(void);
- void TestThisPreparation(void);
- void DumpPrepareIOTable(
- IOPreparationTable *ioTable
- );
- void DumpDMATable(
- DMATransferInfo *dmaTable
- );
- ItemCount GetMapEntryCount(
- void *areaBaseAddress,
- ByteCount areaLength
- );
-
- void
- main(
- int argc,
- char **argv
- )
- {
- ItemCount i;
- ByteCount granularity;
-
- if (gPageSize == 0) {
- gPageSize = GetLogicalPageSize();
- gPageMask = gPageSize - 1;
- }
- do { argc = argc; argv = argv; } while (0);
- printf("Hello world!\n");
- /*
- * Compute a page-aligned base address for our work area.
- */
- for (gPageAlign = 0; gPageAlign < kPageSize; gPageAlign++) {
- if ((((UInt32) &gWorkArea[gPageAlign]) & (kPageSize - 1)) == 0)
- break;
- }
- gWorkAreaStart = &gWorkArea[gPageAlign];
- for (granularity = 0; granularity <= 8192; granularity += 4096) {
- for (i = 0; gSimpleTest[i].byteCount != 0; i++) {
- printf("*\n*** Simple Area Test %ld\n*\n", i);
- TestSimpleArea(&gSimpleTest[i], granularity);
- }
- for (i = 0; gSGTestVector[i] != NULL; i++) {
- printf("*\n*** Scatter Gather Test %ld\n*\n", i);
- TestScatterGatherArea(gSGTestVector[i], granularity);
- }
- }
- exit(EXIT_SUCCESS);
- }
-
- void
- TestSimpleArea(
- const SimpleAreaPtr simpleAreaPtr,
- ByteCount granularity
- )
- {
- LogicalAddress areaAddress;
-
- /*
- * Initialize the ioTable.
- */
- areaAddress = &gWorkAreaStart[simpleAreaPtr->offset];
- printf("%08lx, %lu offset, %lu byteCount\n",
- areaAddress,
- simpleAreaPtr->offset,
- simpleAreaPtr->byteCount
- );
- CLEAR(gIOTable);
- CLEAR(gLogicalMapping);
- CLEAR(gPhysicalMapping);
- gIOTable.options = kIOMinimalLogicalMapping | kIOLogicalRanges | kIOIsInput;
- gIOTable.state = 0;
- gIOTable.addressSpace = kCurrentAddressSpaceID;
- gIOTable.granularity = granularity;
- gIOTable.firstPrepared = 0;
- gIOTable.lengthPrepared = 0;
- if (gIOTable.granularity == 0)
- gIOTable.mappingEntryCount = GetMapEntryCount(areaAddress, simpleAreaPtr->byteCount);
- else {
- gIOTable.mappingEntryCount = GetMapEntryCount(0, gIOTable.granularity);
- }
- gIOTable.logicalMapping = gLogicalMapping;
- gIOTable.physicalMapping = gPhysicalMapping;
- gIOTable.rangeInfo.range.base = areaAddress;
- gIOTable.rangeInfo.range.length = simpleAreaPtr->byteCount;
- DoPreparationAndTest();
- }
-
- void
- TestScatterGatherArea(
- const SimpleAreaPtr sgAreaPtr, /* Vector */
- ByteCount granularity
- )
- {
- LogicalAddress areaAddress;
- ItemCount totalMapAreaCount;
- ItemCount thisMapAreaCount;
- UInt32 i;
-
- /*
- * Initialize the ioTable.
- */
- totalMapAreaCount = 0;
- for (i = 0; sgAreaPtr[i].byteCount != 0; i++) {
- areaAddress = &gWorkAreaStart[sgAreaPtr[i].offset];
- thisMapAreaCount = GetMapEntryCount(areaAddress, sgAreaPtr[i].byteCount);
- totalMapAreaCount += thisMapAreaCount;
- printf("%2lu: %08lx, %6lu offset, %6lu byteCount, %2lu map count\n",
- i,
- areaAddress,
- sgAreaPtr[i].offset,
- sgAreaPtr[i].byteCount,
- thisMapAreaCount
- );
- gScatterGatherTable[i].base = areaAddress;
- gScatterGatherTable[i].length = sgAreaPtr[i].byteCount;
- }
- printf("%lu total mapping entries\n", totalMapAreaCount);
- CLEAR(gIOTable);
- CLEAR(gLogicalMapping);
- CLEAR(gPhysicalMapping);
- gIOTable.options = kIOMinimalLogicalMapping | kIOLogicalRanges | kIOIsInput;
- gIOTable.options |= kIOMultipleRanges;
- gIOTable.state = 0;
- gIOTable.addressSpace = kCurrentAddressSpaceID;
- gIOTable.granularity = granularity;
- gIOTable.firstPrepared = 0;
- gIOTable.lengthPrepared = 0;
- if (gIOTable.granularity == 0)
- gIOTable.mappingEntryCount = totalMapAreaCount;
- else {
- gIOTable.mappingEntryCount = GetMapEntryCount(0, gIOTable.granularity);
- }
- gIOTable.mappingEntryCount = totalMapAreaCount;
- gIOTable.logicalMapping = gLogicalMapping;
- gIOTable.physicalMapping = gPhysicalMapping;
- gIOTable.rangeInfo.multipleRanges.entryCount = i;
- gIOTable.rangeInfo.multipleRanges.rangeTable = &gScatterGatherTable[0];
- DoPreparationAndTest();
- }
-
- void
- DoPreparationAndTest(void)
- {
- OSStatus osStatus;
-
- do {
- printf("\n -- Preparation: first prepared = %ld\n", gIOTable.firstPrepared);
- osStatus = PrepareMemoryForIO(&gIOTable);
- if (osStatus != noErr) {
- printf("PrepareMemoryForIO error: %ld\n", (long) osStatus);
- exit(EXIT_FAILURE);
- }
- else {
- TestThisPreparation();
- }
- CheckpointIO(gIOTable.preparationID, kNilOptions);
- gIOTable.firstPrepared += gIOTable.lengthPrepared;
- } while (osStatus == noErr && (gIOTable.state & kIOStateDone) == 0);
- }
-
- void
- TestThisPreparation(void)
- {
- OSStatus osStatus;
- AddressRange thisTransfer;
- UInt32 totalTransferCount;
- Boolean isLogical;
- ItemCount pass;
-
- DumpPrepareIOTable(&gIOTable);
- osStatus = InitializeDMATransfer(&gIOTable, 8, &gDMATable);
- if (osStatus == eofErr) {
- printf("EOF from InitializeDMATransfer\n");
- return;
- }
- else if (osStatus != noErr) {
- printf("InitializeDMATransfer error: %ld\n", (long) osStatus);
- exit(EXIT_FAILURE);
- }
- pass = 0;
- totalTransferCount = 0;
- while (osStatus == noErr) {
- osStatus = PrepareDMATransfer(&gDMATable, &thisTransfer, &isLogical);
- if (0 && pass == 0)
- DumpDMATable(&gDMATable);
- if (osStatus == eofErr) {
- printf("At normal end\n");
- break;
- }
- if (osStatus != noErr) {
- printf("Failure: %ld\n", (long) osStatus);
- exit(EXIT_FAILURE);
- }
- /* Got the data */
- totalTransferCount += thisTransfer.length;
- printf("%ld %ld: %8lx base, %6lu length, %s, map %2lu,"
- " first %6lu, length %6lu: %6lu\n",
- pass,
- gDMATable.scatterGatherIndex,
- thisTransfer.base, thisTransfer.length,
- (isLogical) ? " logical" : "physical",
- (UInt32) gDMATable.physicalMapIndex,
- (UInt32) gDMATable.physicalStart,
- (UInt32) gDMATable.physicalEnd,
- totalTransferCount
- );
- ++pass;
- }
- }
-
- void
- DumpPrepareIOTable(
- IOPreparationTable *ioTable
- )
- {
- UInt32 i;
- UInt32 totalMapCount;
- UInt32 thisMapCount;
- UInt32 thisTransferCount;
- UInt32 totalTransferCount;
-
- totalMapCount = 0;
- totalTransferCount = 0;
- printf("%6ld granularity, %6ld first prepared, %6ld length prepared, %ld state\n",
- ioTable->granularity,
- ioTable->firstPrepared,
- ioTable->lengthPrepared,
- (unsigned long) ioTable->state
- );
- if ((ioTable->options & kIOMultipleRanges) != 0) {
- /*
- * Scatter-gather table
- */
- printf("%ld range%s\n",
- ioTable->rangeInfo.multipleRanges.entryCount,
- (ioTable->rangeInfo.multipleRanges.entryCount == 1) ? "" : "s"
- );
- for (i = 0; i < ioTable->rangeInfo.multipleRanges.entryCount; i++) {
- thisTransferCount = ioTable->rangeInfo.multipleRanges.rangeTable[i].length;
- thisMapCount = GetMapEntryCount(
- ioTable->rangeInfo.multipleRanges.rangeTable[i].base,
- thisTransferCount
- );
- totalMapCount += thisMapCount;
- totalTransferCount += thisTransferCount;
- printf("%2ld: %08lx %6ld, logicalMap %08lx %08lx, page %2ld\n",
- i,
- ioTable->rangeInfo.multipleRanges.rangeTable[i].base,
- thisTransferCount,
- ioTable->logicalMapping[i * 2],
- ioTable->logicalMapping[(i * 2) + 1],
- thisMapCount
- );
- }
- }
- else {
- /*
- * Simple table.
- */
- thisMapCount = GetMapEntryCount(
- ioTable->rangeInfo.range.base,
- ioTable->rangeInfo.range.length
- );
- totalMapCount += thisMapCount;
- thisTransferCount = ioTable->rangeInfo.range.length;
- totalTransferCount += thisTransferCount;
- printf("%08lx %6ld, logicalMap %08lx %08lx, page %2ld\n",
- ioTable->rangeInfo.range.base,
- thisTransferCount,
- ioTable->logicalMapping[0],
- ioTable->logicalMapping[1],
- thisMapCount
- );
- }
- printf("%ld total transfer, physical map %ld allocated, %ld found\n",
- totalTransferCount,
- ioTable->mappingEntryCount,
- totalMapCount
- );
- for (i = 0; i < ioTable->mappingEntryCount; i++)
- printf("%2d: %08lx\n", (int) i, ioTable->physicalMapping[i]);
- }
-
- void
- DumpDMATable(
- DMATransferInfo *dmaTable
- )
- {
- printf("%8lu logicalAlignment\n", dmaTable->logicalAlignment);
- printf("%8lu scatterGatherIndex\n", dmaTable->scatterGatherIndex);
- printf("%8lu physicalMapIndex\n", dmaTable->physicalMapIndex);
- printf("%8lu physicalStart\n", dmaTable->physicalStart);
- printf("%8lu physicalEnd\n", dmaTable->physicalEnd);
- printf("%08lx physicalRange.base\n", dmaTable->physicalRange.base);
- printf("%8lu physicalRange.length\n", dmaTable->physicalRange.length);
- printf("%08lx logicalStart.base\n", dmaTable->logicalStart.base);
- printf("%8lu logicalStart.length\n", dmaTable->logicalStart.length);
- printf("%08lx logicalEnd.base\n", dmaTable->logicalEnd.base);
- printf("%8lu logicalEnd.length\n", dmaTable->logicalEnd.length);
- }
-
- ItemCount
- GetMapEntryCount(
- void *areaBaseAddress,
- ByteCount areaLength
- )
- {
- ItemCount result;
- ByteCount normalizedLength;
- UInt32 areaAddress;
-
- areaAddress = (UInt32) areaBaseAddress;
- normalizedLength = PageBaseAddress(areaAddress + areaLength - 1)
- - PageBaseAddress(areaAddress);
- result = (ItemCount) (normalizedLength / gPageSize) + 1;
- return (result);
- }
-
- #endif
-
-
-