下面开始讲述利用WINDRIVER进行开发PCIE驱动,具体步骤如下图所示。在例子程序里有两种DMA传输方式 , 一种是通过查询方式,另一种是通过中断方式,上图是按照查询方式进行的,比较简单。简易来说,就是先打开PCIE的设备,然后为它分配内核物理内存,将分配到的物理地址写到PCIE卡里相应的寄存器,然后配置一些必须的DMA传输的包大小、包数等寄存器后便可开始DMA传输。 主要代码如下
static void myDMATranlation(WDC_DEVICE_HANDLE hDev, PDIAG_DMA pDma, BOOL fPolling, BOOL IsRead, char *mypBuf)在此完成所有的DMA传输操作,包括读写
{
DWORD dwStatus, dwOptions, i;
UINT32 u32Pattern;
WORD wSize, wCount;
BOOL fIsRead;
BOOL fEnable64bit;
BYTE bTrafficClass;
DWORD dwTotalCount;
u32Pattern = 0x10203040;
wCount = 256;
if(IsRead)
dwOptions = DMA_TO_DEVICE;//设置为读
else
dwOptions = DMA_FROM_DEVICE;
fIsRead = dwOptions & DMA_FROM_DEVICE ? FALSE : TRUE;
/* The BMD reference design does not support s/g DMA, so we use contiguous
*/
dwOptions |= DMA_KERNEL_BUFFER_ALLOC; ///采用内核分配BUFFER的方式
/* Get the max payload size from the device */
// wSize = VIRTEX5_DMAGetMaxPacketSize(hDev, fIsRead) / sizeof(UINT32);
wSize = 32; 固定为128!!!!!!!!
dwTotalCount = (DWORD)wCount * (DWORD)wSize;
/* Open DMA handle */
dwStatus = VIRTEX5_DMAOpen(hDev, &pDma->pBuf, dwOptions,
dwTotalCount * sizeof(UINT32), &pDma->hDma);
if (WD_STATUS_SUCCESS != dwStatus)
{
printf("\nFailed to open DMA handle. Error 0x%lx - %s\n", dwStatus,
Stat2Str(dwStatus));
return;
}
printf("\nDMA handle was opened successfully (handle 0x%lx)\n", pDma->hDma);
printf("Payload packet size in dwords 0x%hx\n", wSize);
/* Prepare the device registers for DMA transfer */
fEnable64bit = FALSE;
bTrafficClass = 0;
VIRTEX5_DMADevicePrepare(pDma->hDma, fIsRead, wSize, wCount, u32Pattern,
fEnable64bit, bTrafficClass, myaddr_offset); /*配置卡上的DMA控制器寄存器*/
VIRTEX5_DmaIntDisable(hDev, fIsRead);
/* Initialize the DMA buffer with user defined pattern */
if(fIsRead)
memcpy((char *)pDma->pBuf,mypBuf,dwTotalCount * sizeof(UINT32));
else
memset((char *)pDma->pBuf, 0xdeadbeaf, dwTotalCount * sizeof(UINT32));
/* Start DMA */
printf("Start DMA transfer\n");
VIRTEX5_DMAStart(pDma->hDma, fIsRead);//DMA从此开始占用CPU,开始
/* Poll for completion (if polling selected) */
if (fPolling)
{
if (VIRTEX5_DMAPollCompletion(pDma->hDma, fIsRead))
{
// DmaTransferVerify(hDev, pDma->pBuf, dwTotalCount, u32Pattern, fIsRead);
printf("tranlation is done!\n");
}
else
printf("timeout\n");
}
return;
Error:
DIAG_DMAClose(hDev, pDma);
}
void VIRTEX5_DMADevicePrepare(VIRTEX5_DMA_HANDLE hDma, BOOL fIsRead, WORD wSize,
WORD wCount, UINT32 u32Pattern, BOOL fEnable64bit, BYTE bTrafficClass, WORD wPcieAddr)
{
UINT32 tlps;
UINT32 LowerAddr;
BYTE UpperAddr;
WDC_DEVICE_HANDLE hDev;
PVIRTEX5_DEV_CTX pDevCtx;
if (!IsValidDmaHandle(hDma, "VIRTEX5_DMADevicePrepare"))
return;
hDev = hDma->hDev;
/* Assert Initiator Reset */
VIRTEX5_WriteReg32(hDev, DCR_OFFSET, 0x1); /*复位,写1*/
/* De-assert Initiator Reset */
VIRTEX5_WriteReg32(hDev, DCR_OFFSET, 0x0); /*复位,写0*/
LowerAddr = (UINT32)hDma->pDma->Page[0].pPhysicalAddr; ///低地址,物理地址
UpperAddr = (BYTE)((hDma->pDma->Page[0].pPhysicalAddr >> 32) & 0xFF);///高地址,物理地址
printf("LowerAddr is %x\n", LowerAddr);
printf("UpperAddr is %x\n", UpperAddr);
//tlps = (wSize & 0x1FFF) | /* tlps[0:12] - DMA TLP size */
// ((bTrafficClass & 0x7) << 16) | /* tlps[16:18] -
// DMA TLP Traffic Class */
// (fEnable64bit ? BIT19 : 0) | /* tlps[19] enable 64bit TLP */
// (UpperAddr << 24); /* tlps[24:31] - upper bits 33:39 of DMA addr*/
tlps = wSize & 0x1fff; //只有低12位有效
if (fIsRead)
{
/* Set lower 32bit of DMA address */
VIRTEX5_WriteReg32(hDev, READ_ADDR_OFFSET, LowerAddr);
/* Set size, traffic class, 64bit enable, upper 8bit of DMA address */
VIRTEX5_WriteReg32(hDev, READ_SIZE_OFFSET, tlps);
/* Set TLP count */
VIRTEX5_WriteReg16(hDev, READ_COUNT_OFFSET, wCount);
/* Set Read DMA pattern */
VIRTEX5_WriteReg32(hDev, READ_PATTERN_OFFSET, u32Pattern);
VIRTEX5_WriteReg32(hDev, PCIE_READ_ADDR_OFFSET, wPcieAddr);
}
else
{
/* Set lower 32bit of DMA address */
VIRTEX5_WriteReg32(hDev, WRITE_ADDR_OFFSET, LowerAddr);
/* Set size, traffic class, 64bit enable, upper 8bit of DMA address */
VIRTEX5_WriteReg32(hDev, WRITE_SIZE_OFFSET, tlps);
/* Set TLP count */
VIRTEX5_WriteReg16(hDev, WRITE_COUNT_OFFSET, wCount);
/* Set Read DMA pattern */
VIRTEX5_WriteReg32(hDev, WRITE_PATTERN_OFFSET, u32Pattern);
VIRTEX5_WriteReg32(hDev, PCIE_WRITE_ADDR_OFFSET, wPcieAddr);
}
pDevCtx = (PVIRTEX5_DEV_CTX)WDC_GetDevContext(hDev);
pDevCtx->fIsRead = fIsRead;
pDevCtx->u32Pattern = u32Pattern;
pDevCtx->dwTotalCount = (DWORD)wCount * (DWORD)wSize;
}
void VIRTEX5_DMAStart(VIRTEX5_DMA_HANDLE hDma, BOOL fIsRead)
{
if (!IsValidDmaHandle(hDma, "VIRTEX5_DMAStart"))
return;
VIRTEX5_DMASyncCpu(hDma);
/* Start DMA Transfer */
VIRTEX5_WriteReg32(hDma->hDev, VIRTEX5_DDMACR_OFFSET, /*此处0X10000指读DMA操作开始, 0X1表示写DMA操作开始**/
fIsRead ? 0x10000 : 0x1);
}
流程图