📄 supportfunc.c
字号:
IoFreeMdl(
pdx->DmaInfo[DmaIndex].pMdl
);
pdx->DmaInfo[DmaIndex].pMdl = NULL;
}
// Clear the DMA pending flag
pdx->DmaInfo[DmaIndex].bPending = FALSE;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
IrqL_Original
);
}
/******************************************************************************
*
* Function : PlxLockBufferAndBuildSgl
*
* Description: Lock a user buffer and build an SGL for it
*
******************************************************************************/
U32
PlxLockBufferAndBuildSgl(
DEVICE_EXTENSION *pdx,
U8 DmaIndex,
DMA_TRANSFER_ELEMENT *pDma
)
{
U32 i;
U32 offset;
U32 BusSgl;
U32 BusSglOriginal;
U32 BusAddr;
U32 SglSize;
U32 BlockSize;
U32 LocalAddr;
U32 TotalPages;
U32 *pCurrentPage;
U32 BytesRemaining;
PMDL pMdl;
KIRQL IrqL_Original;
BOOLEAN bFlag;
PLX_UINT_PTR VaSgl;
DebugPrintf(("Building SGL descriptors for buffer...\n"));
DebugPrintf((" User VA : 0x%08lx\n", (PLX_UINT_PTR)pDma->u.UserVa));
DebugPrintf((" Local Addr: 0x%08x\n", pDma->LocalAddr));
DebugPrintf((" Size : %d bytes\n", pDma->TransferCount));
// Get the MDL for the User buffer to get the page list
pMdl =
IoAllocateMdl(
(VOID*)pDma->u.UserVa,
pDma->TransferCount,
FALSE,
FALSE,
NULL
);
if (pMdl == NULL)
{
DebugPrintf(("ERROR - Unable to allocate an MDL for the User buffer\n"));
return 0;
}
// Attempt to lock the user buffer into memory
bFlag = FALSE;
try
{
MmProbeAndLockPages(
pMdl,
UserMode,
IoModifyAccess
);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
// Flag the exception
bFlag = TRUE;
}
// Verify that the pages were locked
if (bFlag)
{
DebugPrintf(("ERROR - Unable to lock user mode buffer pages\n"));
IoFreeMdl(
pMdl
);
return 0;
}
// Calculate total pages
TotalPages = (((U16)pMdl->Size - sizeof(MDL)) / sizeof(U32));
DebugPrintf((
"Page-locked %d user buffer pages...\n",
TotalPages
));
/******************************************************
* Build SGL descriptors
*
* The following code will build the SGL descriptors
* in PCI memory. There will be one descriptor for
* each page of memory since the pages are scattered
* throughout physical memory.
*****************************************************/
/*************************************************************
* Calculate memory needed for SGL descriptors
*
* Mem needed = #pages * size of descriptor
*
* Additionally, a value of 16 (10h) is added to provide a
* buffer to allow space to round up to the next 16-byte
* boundary, which is a requirement of the hardware.
************************************************************/
SglSize = (TotalPages * (4 * sizeof(U32))) + 16;
// Check if a previously allocated buffer can be re-used
if (pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa != NULL)
{
if (pdx->DmaInfo[DmaIndex].SglBuffer.Size >= SglSize)
{
// Buffer can be re-used, do nothing
DebugPrintf(("Re-using previously allocated SGL descriptor buffer\n"));
}
else
{
DebugPrintf(("Releasing previously allocated SGL descriptor buffer\n"));
// Release memory used for SGL descriptors
Plx_dma_buffer_free(
pdx,
&pdx->DmaInfo[DmaIndex].SglBuffer
);
pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa = NULL;
}
}
// Allocate memory for SGL descriptors if necessary
if (pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa == NULL)
{
DebugPrintf(("Allocating PCI memory for SGL descriptor buffer...\n"));
// Setup for transfer
pdx->DmaInfo[DmaIndex].SglBuffer.Size = SglSize;
pdx->DmaInfo[DmaIndex].SglBuffer.bCacheable = FALSE;
VaSgl =
(PLX_UINT_PTR)Plx_dma_buffer_alloc(
pdx,
&pdx->DmaInfo[DmaIndex].SglBuffer
);
if (VaSgl == 0)
{
DebugPrintf((
"ERROR - Unable to allocate %d bytes for %d SGL descriptors\n",
pdx->DmaInfo[DmaIndex].SglBuffer.Size,
TotalPages
));
MmUnlockPages(
pMdl
);
IoFreeMdl(
pMdl
);
return 0;
}
}
else
{
VaSgl = (PLX_UINT_PTR)pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa;
}
// Save MDL for deallocation after the DMA transfer
KeAcquireSpinLock(
&(pdx->Lock_DmaChannel),
&IrqL_Original
);
pdx->DmaInfo[DmaIndex].pMdl = pMdl;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
IrqL_Original
);
// Prepare for build of SGL
LocalAddr = pDma->LocalAddr;
// Get bus physical address of SGL descriptors
BusSgl = (U32)pdx->DmaInfo[DmaIndex].SglBuffer.BusPhysical;
// Make sure addresses are aligned on 16-byte boundary
VaSgl = (VaSgl + 0xF) & ~(0xF);
BusSgl = (BusSgl + 0xF) & ~(0xF);
// Store the starting address of the SGL for later return
BusSglOriginal = BusSgl;
DebugPrintf((
"Building SGL descriptor list located at 0x%08x...\n",
BusSglOriginal
));
// Point to first page in physical page list (located at end of MDL)
pCurrentPage = (U32*)(((U8*)pMdl) + sizeof(MDL));
// Set offset of first page
offset = pMdl->ByteOffset;
// Initialize bytes remaining
BytesRemaining = pDma->TransferCount;
// Build the SGL list
for (i = 0; i < TotalPages; i++)
{
// Calculate transfer size
if (BytesRemaining > (PAGE_SIZE - offset))
{
BlockSize = PAGE_SIZE - offset;
}
else
{
BlockSize = BytesRemaining;
}
// Get bus address of buffer
BusAddr = (*pCurrentPage << PAGE_SHIFT) + offset;
// Enable the following to display the parameters of each SGL descriptor
if (PLX_DEBUG_DISPLAY_SGL_DESCR)
{
DebugPrintf((
"SGL Desc %02d: PCI=%08Xh Loc=%08Xh Size=%Xh (%d) bytes\n",
i, (U32)BusAddr, LocalAddr, BlockSize, BlockSize
));
}
// Write PCI address in descriptor
*(((U32*)VaSgl) + SGL_DESC_IDX_PCI_ADDR) = BusAddr;
// Write Local address in descriptor
*(((U32*)VaSgl) + SGL_DESC_IDX_LOC_ADDR) = LocalAddr;
// Write transfer count in descriptor
*(((U32*)VaSgl) + SGL_DESC_IDX_COUNT) = BlockSize;
// Adjust byte count
BytesRemaining -= BlockSize;
if (BytesRemaining == 0)
{
// Write the last descriptor
*(((U32*)VaSgl) + SGL_DESC_IDX_NEXT_DESC) =
(pDma->LocalToPciDma << 3) | (1 << 1) | (1 << 0);
}
else
{
// Calculate address of next descriptor
BusSgl += (4 * sizeof(U32));
// Write next descriptor address
*(((U32*)VaSgl) + SGL_DESC_IDX_NEXT_DESC) =
BusSgl | (pDma->LocalToPciDma << 3) | (1 << 0);
// Adjust Local address
if (pdx->DmaInfo[DmaIndex].bLocalAddrConstant == FALSE)
LocalAddr += BlockSize;
// Adjust virtual address to next descriptor
VaSgl += (4 * sizeof(U32));
// Clear offset
offset = 0;
}
// Go to next page
pCurrentPage++;
}
// Make sure cache data is flushed
KeFlushIoBuffers(
pMdl,
(BOOLEAN)pDma->LocalToPciDma, // Read from device operation?
TRUE // DMA transfer?
);
// Return the physical address of the SGL
return BusSglOriginal;
}
#endif // DMA_SUPPORT
/******************************************************************************
*
* Function : Plx_dma_buffer_alloc
*
* Description: Allocates physically contiguous non-paged memory
*
******************************************************************************/
VOID*
Plx_dma_buffer_alloc(
DEVICE_EXTENSION *pdx,
PLX_PHYS_MEM_OBJECT *pMemObject
)
{
PHYSICAL_ADDRESS BufferLogicalAddress;
// Verify the DMA adapter object
if (pdx->pDmaAdapter == NULL)
{
DebugPrintf((
"ERROR - DMA Adapter object does not exist, cannot allocate physical memory\n"
));
return NULL;
}
// Attempt to allocate contiguous memory
#if defined(PLX_NT_DRIVER)
pMemObject->pKernelVa =
HalAllocateCommonBuffer(
pdx->pDmaAdapter,
pMemObject->Size,
&BufferLogicalAddress,
pMemObject->bCacheable // Enable Caching for buffer?
);
#else
pMemObject->pKernelVa =
pdx->pDmaAdapter->DmaOperations->AllocateCommonBuffer(
pdx->pDmaAdapter,
pMemObject->Size,
&BufferLogicalAddress,
pMemObject->bCacheable // Enable Caching for buffer?
);
#endif // PLX_NT_DRIVER
if (pMemObject->pKernelVa == NULL)
{
return NULL;
}
// Store the buffer logical/bus physical address
pMemObject->BusPhysical = BufferLogicalAddress.QuadPart;
// CPU Address is the same as bus on this architecture
pMemObject->CpuPhysical = BufferLogicalAddress.QuadPart;
// Clear the buffer
RtlZeroMemory(
pMemObject->pKernelVa,
pMemObject->Size
);
DebugPrintf(("Allocated physical memory...\n"));
DebugPrintf((
" CPU Phys Addr: 0x%08lx\n",
(PLX_UINT_PTR)pMemObject->CpuPhysical
));
DebugPrintf((
" Bus Phys Addr: 0x%08lx\n",
(PLX_UINT_PTR)pMemObject->BusPhysical
));
DebugPrintf((
" Kernel VA : 0x%p\n",
pMemObject->pKernelVa
));
DebugPrintf((
" Size : "
));
if (pMemObject->Size >= (10 << 10))
{
DebugPrintf_NoInfo((
"%d Kb\n",
(pMemObject->Size >> 10)
));
}
else
{
DebugPrintf_NoInfo((
"%d bytes\n",
pMemObject->Size
));
}
DebugPrintf((
" Cacheable? : %s\n",
(pMemObject->bCacheable == FALSE) ? "No" : "Yes"
));
return pMemObject->pKernelVa;
}
/******************************************************************************
*
* Function : Plx_dma_buffer_free
*
* Description: Frees previously allocated physical memory
*
******************************************************************************/
VOID
Plx_dma_buffer_free(
DEVICE_EXTENSION *pdx,
PLX_PHYS_MEM_OBJECT *pMemObject
)
{
PHYSICAL_ADDRESS BufferLogicalAddress;
// Verify the DMA adapter object
if (pdx->pDmaAdapter == NULL)
{
DebugPrintf((
"ERROR - DMA Adapter object does not exist, cannot allocate physical memory\n"
));
return;
}
// Set logical address
BufferLogicalAddress.QuadPart = pMemObject->BusPhysical;
// Release the buffer
#if defined(PLX_NT_DRIVER)
HalFreeCommonBuffer(
pdx->pDmaAdapter,
pMemObject->Size,
BufferLogicalAddress,
pMemObject->pKernelVa,
pMemObject->bCacheable // Enable Caching for buffer?
);
#else
pdx->pDmaAdapter->DmaOperations->FreeCommonBuffer(
pdx->pDmaAdapter,
pMemObject->Size,
BufferLogicalAddress,
pMemObject->pKernelVa,
pMemObject->bCacheable // Enable Caching for buffer?
);
#endif // PLX_NT_DRIVER
DebugPrintf((
"Released physical memory at 0x%08lx ",
(PLX_UINT_PTR)pMemObject->CpuPhysical
));
if (pMemObject->Size >= (10 << 10))
{
DebugPrintf_NoInfo((
"(%d Kb)\n",
(pMemObject->Size >> 10)
));
}
else
{
DebugPrintf_NoInfo((
"(%d bytes)\n",
pMemObject->Size
));
}
// Clear memory object properties
RtlZeroMemory(
pMemObject,
sizeof(PLX_PHYS_MEM_OBJECT)
);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -