📄 dma.c
字号:
XLLP_DMAC_ALIGNMENT_T *aLign
)
{
XLLP_UINT32_T i;
XLLP_UINT32_T maxPages;
XLLP_UINT32_T *aPages;
BOOL fResult;
XLLP_UINT32_T firstPageOffset;
XLLP_UINT32_T lastPageOffset;
XLLP_STATUS_T status=XLLP_STATUS_SUCCESS;
//
// In case there are errors, that's what we shall return
//
*pBufferMdl = NULL;
if(!pBuffer)
return XLLP_ERR_MEM_ALLOC;
//
// Find maximum number of pages that can be occupied by this buffer
//
maxPages = OSGetMaxPages(pBuffer, bufferLength);
aPages = (XLLP_UINT32_T*) OSMemAlloc( maxPages*sizeof(XLLP_UINT32_T));
if(!aPages)
return XLLP_ERR_MEM_ALLOC;
//
// Get list of all physical pages occupied by this buffer
//
fResult = OSLockPhysicalPages(pBuffer, bufferLength, aPages, LOCKFLAG_WRITE);
if (!fResult)
{
RETAILMSG(1,(TEXT("DMA:>XllpDmacCreateBufferMdl Error..\r\n")));
status = XLLP_ERR_MEM_ALLOC;
goto Label_CreateBufferMdl;
}
//
// Allocate space for MDL for the number of entries we calculated above
//
if( (*pBufferMdl = XllpDmacAllocateMdl(maxPages)) == NULL)
{
fResult = XLLP_ERR_MEM_ALLOC;
goto Label_CreateBufferMdl;
}
//
// Initialize entries in the MDL
// The buffer can be starting from middle of a page and also ending in middle of a page
//
firstPageOffset = ((XLLP_UINT32_T)pBuffer & (PAGE_SIZE-1));
lastPageOffset = (((XLLP_UINT32_T)pBuffer + bufferLength) & (PAGE_SIZE-1));
(*pBufferMdl)->numEntries = maxPages;
(*pBufferMdl)->bufferPtr = pBuffer;
//
// Add the starting page offset for the first physical block
// Set the length to buffer length for default case of no page breaks in between
// If there are page breaks, then the length will get adjusted below.
//
(*pBufferMdl)->physBlock[0].physicalAds = (aPages[0] + firstPageOffset);
(*pBufferMdl)->physBlock[0].blockLength = bufferLength;
if(maxPages > 1)
{
//
// Since there are page breaks, set the size of first block to only the size on first page
//
(*pBufferMdl)->physBlock[0].blockLength = (PAGE_SIZE - firstPageOffset);
for(i=1; i<maxPages-1; ++i)
{
//
// We got a page break
// Set the starting address of next block
// Initialize the size of next physical block to PAGE_SIZE
//
(*pBufferMdl)->physBlock[i].physicalAds = aPages[i];
(*pBufferMdl)->physBlock[i].blockLength = PAGE_SIZE;
}
//
// Adjust the size of last block with the last page offset in case the
// buffer ends in middle of a page
//
(*pBufferMdl)->physBlock[i].physicalAds = aPages[i];
(*pBufferMdl)->physBlock[i].blockLength = lastPageOffset == 0 ? PAGE_SIZE : lastPageOffset;
}
//
// If physical address of any of the blocks does not start at 8 byte boundary we may
// need to turn on the alignment flag
//
*aLign = XLLP_DMAC_ALIGNMENT_OFF;
for(i=1; i<maxPages-1; ++i)
if ((*pBufferMdl)->physBlock[i].physicalAds & 0x7)
*aLign = XLLP_DMAC_ALIGNMENT_ON;
Label_CreateBufferMdl:
OSMemFree(aPages);
return XLLP_STATUS_SUCCESS;
}
//******************************************************************************
//
// Function Name: XllpDmacAllocDmaDescriptorList
//
// Description: Allocates a DMA descriptor list for the buffer
//
//
// Input Arguments:
// numEntries: Number of descriptor entries for which space needs to be allocated
//
// Output Arguments:
//
// Return Value:
// pDmaDescInfo: Pointer to structure which contains information about allocated
// DMA descriptors.
//
// Notes:
// The allocated DMA descriptors will be aligned on 16 byte physical boundaries
//
//*******************************************************************************
PDmaDescInfo XllpDmacAllocDmaDescriptorList
(
XLLP_UINT32_T numEntries
)
{
XLLP_UINT32_T memSize;
XLLP_UINT32_T descAlignOffset;
PDmaDescInfo pDmaDescInfo;
//
// Allocate an extra descriptor so that we can align the decriptors appropriately
// The DMA descriptors need to be aligned on 16 byte boundaries.
//
memSize = sizeof(DmaDescInfo) + ((numEntries + 1) * sizeof(XLLP_DMAC_DESCRIPTOR_T));
pDmaDescInfo = (PDmaDescInfo) OSMemAlloc( memSize );
if(pDmaDescInfo)
{
pDmaDescInfo->memPtr = (XLLP_UINT8_T*)pDmaDescInfo;
pDmaDescInfo->numEntries = numEntries;
descAlignOffset = (XLLP_UINT32_T)pDmaDescInfo + sizeof(DmaDescInfo) +
sizeof(XLLP_DMAC_DESCRIPTOR_T);
descAlignOffset &= XLLP_DMAC_ALIGN_MASK;
pDmaDescInfo->pDmaDescList = (P_XLLP_DMAC_DESCRIPTOR_T) descAlignOffset;
}
return (pDmaDescInfo);
}
//******************************************************************************
//
// Function Name: XllpDmacFreeDescriptorList
//
// Description: Frees a previously allocated DMA descriptor list for the buffer
//
//
// Input Arguments:
// pDmaDescInfo: Pointer to structure which contains information about allocated
// DMA descriptors.
//
// Output Arguments:
//
// Return Value:
//
// Notes:
//
//
//*******************************************************************************
VOID XllpDmacFreeDescriptorList
(
PDmaDescInfo pDmaDescInfo
)
{
OSMemFree( pDmaDescInfo->memPtr );
}
//******************************************************************************
//
// Function Name: XllpDmacGetXfrDone
//
// Description: Gets the number of bytes transferred for a particular descriptor
// list
//
// Input Arguments:
//
//
// Output Arguments:
//
// Return Value:
//
// Notes:
//
//
//*******************************************************************************
XLLP_STATUS_T XllpDmacGetXfrDone
(
XLLP_DMAC_CHANNEL_T dmaChannel,
PBufferMdl pBufferMdl,
XLLP_DMAC_TRANSFER_TYPE_T transferType,
XLLP_UINT32_T *bytesXferred
)
{
XLLP_UINT32_T currAddress;
XLLP_UINT32_T i;
XLLP_UINT32_T bytesDone=0;
XLLP_UINT32_T bytesRem=0;
PPhysBlock pPhys=pBufferMdl->physBlock;
*bytesXferred = 0;
if(transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM)
currAddress = pDmacHandle->DDG[dmaChannel].DTADR;
else
currAddress = pDmacHandle->DDG[dmaChannel].DSADR;
for(i=0;i<pBufferMdl->numEntries;++i)
{
bytesDone += pPhys[i].blockLength;
if(currAddress >= pPhys[i].physicalAds &&
currAddress <= pPhys[i].physicalAds + pPhys[i].blockLength )
break;
}
if(i==pBufferMdl->numEntries)
{
RETAILMSG(1,(TEXT("DMA:>XllpDmacGetXfrDone bad Mdl. dmaChan=%d \r\n"), dmaChannel ));
return XLLP_ERR_BAD_MDL;
}
bytesRem = XllpDmacGetRemainingXfrLength(dmaChannel);
bytesDone -= bytesRem;
*bytesXferred = bytesDone;
RETAILMSG(1,(TEXT("DMA:>XllpDmacGetXfrDone dmaChan=%d bytesDone=%d curAds=0x%08x \r\n"), dmaChannel, bytesDone, currAddress));
return XLLP_STATUS_SUCCESS;
}
//******************************************************************************
//
// Function Name: XllpDmacSetupTransfer
//
// Description: Sets up a complete transfer operation
//
// Input Arguments:
// aChannelPriority DMA channel priority
// pUserBuffer Pointer to user buffer
// xferByteCount Number of bytes to be transferred
// transferType Transfer type
// deviceAddress Address on device. This can be 4 byte aligned
// aDeviceDrcmr Device DRCMR for mapping the DMA Channel
// dmaIntHandler DMA interrupt handle to be called on completion or errors
// pUserContext User context to be passed back in callback
// intEnableBitmask Bitmask of interrupts that can be enabled during the transfer
// descBasedXfr Descriptor based transfer or not.
// pCmd Pointer to value of DCMD register for current operation
//
//
// Output Arguments:
// dmaChannel DMA channel allocated for current operation
// pUserDmaDescInfo UserDMA descriptor information
// pUserBufferMdl Mdl decribing the user buffer
//
// Return Value:
// XLLP_STATUS_SUCCESS: on success
//
// Notes: This is a workhorse routine which sets up either descriptor based
// or non-descriptor based transfer operation.
//
//*******************************************************************************
XLLP_STATUS_T XllpDmacSetupTransfer
(
XLLP_DMAC_CHANNEL_PRIORITY_T aChannelPriority,
XLLP_UINT8_T* pUserBuffer,
XLLP_UINT32_T xferByteCount,
XLLP_DMAC_TRANSFER_TYPE_T transferType,
XLLP_UINT32_T deviceAddress,
XLLP_DMAC_DEVICE_T aDeviceDrcmr,
DeviceDmaIntHandler dmaIntHandler,
PVOID pUserContext,
XLLP_UINT32_T intEnableBitmask,
XLLP_UINT32_T descBasedXfr,
XLLP_DMAC_COMMAND_T* pCmd,
XLLP_DMAC_CHANNEL_T* dmaChannel,
PDmaDescInfo* pUserDmaDescInfo,
PBufferMdl* pUserBufferMdl
)
{
XLLP_STATUS_T status;
XLLP_DMAC_CHANNEL_T aChannel=XLLP_INVALID_DMA_CHANNEL;
PBufferMdl pBufferMdl=NULL;
PDmaDescInfo pDmaDescInfo=NULL;
XLLP_DMAC_ALIGNMENT_T aLign=XLLP_DMAC_ALIGNMENT_ON;
XLLP_UINT32_T physAds;
physAds = XllpDmacGetPhysicalAds(pUserBuffer);
//RETAILMSG(1,(TEXT("DMA: XllpDmacSetupTransfer physAds=0x%08x devAds=0x%08x \r\n"), physAds, deviceAddress));
//
// Allocate a DMA channel based on specified user priority
//
status = XllpDmacAllocChannel(&aChannel, aChannelPriority );
if (status != XLLP_STATUS_SUCCESS)
return status;
//
// Register a handler for the allocated DMA channel
//
*dmaChannel = (UINT32)(aChannel);
status = XllpDmacRegisterDeviceHandler(aChannel, dmaIntHandler,pUserContext);
if (status != XLLP_STATUS_SUCCESS)
goto Label_CleanSetupDmacTransfer;
if(descBasedXfr)
{
//
// Create a MDL for the buffer
//
status = XllpDmacCreateBufferMdl(pUserBuffer, xferByteCount, &pBufferMdl, &aLign);
if (status != XLLP_STATUS_SUCCESS)
goto Label_CleanSetupDmacTransfer;
//
// Create the DMA descriptor list for this buffer
//
status = XllpDmacCreateDescriptorListFromMdl(pBufferMdl,
transferType,
&pDmaDescInfo,
deviceAddress,
pCmd);
if (status != XLLP_STATUS_SUCCESS)
goto Label_CleanSetupDmacTransfer;
//
// Load the DMA descriptors into the DMA registers
//
XllpDmacCfgChannelDescTransfer((XLLP_DMAC_DESCRIPTOR_T*)XllpDmacGetPhysicalAds((void*) pDmaDescInfo->pDmaDescList),
aChannel,
aDeviceDrcmr,
aLign);
//
// Just need to call XllpDmacStartTransfer to initiate transfer at this point
// Return the DMA descriptor information, since the user will have to free this later on
//
*pUserDmaDescInfo = pDmaDescInfo;
*pUserBufferMdl = pBufferMdl;
}
if(!descBasedXfr)
{
XllpDmacCfgChannelNoDescTransfer(((transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM) ? deviceAddress : physAds),
((transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM) ? physAds : deviceAddress),
pCmd,
aChannel,
aDeviceDrcmr,
aLign);
}
//
// Enable specified interrupts for the DMA channel
//
status = XllpDmacEnableInterrupts(aChannel, intEnableBitmask);
if (status != XLLP_STATUS_SUCCESS)
goto Label_CleanSetupDmacTransfer;
//
// Just need to call XllpDmacStartTransfer to initiate transfer at this point
//
return XLLP_STATUS_SUCCESS;
Label_CleanSetupDmacTransfer:
if(pBufferMdl)
XllpDmacFreeBufferMdl(pUserBuffer, xferByteCount, pBufferMdl);
if (pDmaDescInfo)
XllpDmacFreeDescriptorList(pDmaDescInfo);
if (aChannel != XLLP_INVALID_DMA_CHANNEL)
{
XllpDmacDisableInterrupts(aChannel, XLLP_ALL_INTERRUPTS_SOURCE);
XllpDmacUnregisterDeviceHandler(aChannel);
XllpDmacFreeChannel(aChannel, aDeviceDrcmr);
}
return status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -