📄 ixp425pcidma.c
字号:
lastReq1.callback = currAtp1.callback; lastReq1.parameter = currAtp1.parameter; error1 = regval & PCI_DMACTRL_APDE1; /*If there is a transfer queued, initiate it*/ if (atpRequestQueueSize > 2) { req = atpTransferGet (); atpTransferInitiate (req); } atpRequestQueueSize--; } /*This code would appear to be more at home within the body of the if blocks above, but the point of this control flow structure is to invoke the next atpTransferInitiate as soon as possible after getting the interrupt, so that we maximize utilisation of the DMA channel, so we obviously want to avoid invoking client code callbacks before initiating our transfer*/ if (lastReq0.callback != NULL) { if (error0 != 0) { (lastReq0.callback)(PCI_ERROR, lastReq0.parameter); } else { (lastReq0.callback)(PCI_OK, lastReq0.parameter); } } if (lastReq1.callback != NULL) { if (error1 != 0) { (lastReq1.callback)(PCI_ERROR, lastReq1.parameter); } else { (lastReq1.callback)(PCI_OK, lastReq1.parameter); } } intUnlock(key); return;}/**************************************************************************** pciPtaIsr - interrupt handler for PTA DMA channel** This routine handles pci_ptadma_int interrupts. Such interrupts may indicate that * one or both of the register sets' corresponding PTA DMA transfers have completed.** RETURNS: N/A*/voidpciPtaIsr (int param){ UINT32 regval; UINT32 newval; UINT32 key; PCI_DMA_REQUEST lastReq0; PCI_DMA_REQUEST lastReq1; PCI_DMA_REQUEST *req; UINT32 error0; UINT32 error1; if (ptaRequestQueueSize == 0) { return; } key=intLock(); /*Check what caused the interrupt*/ REG_READ (PCI_CSR_BASE, PCI_DMACTRL_OFFSET, regval); error0 = 0; error1 = 0; lastReq0.callback = NULL; lastReq1.callback = NULL; if (regval & PCI_DMACTRL_PADC0) { /*register set 0 transfer complete*/ newval = (regval & PCI_DMACTRL_APDCEN) | (regval & PCI_DMACTRL_PADCEN) | (PCI_DMACTRL_PADC0); REG_WRITE(PCI_CSR_BASE, PCI_DMACTRL_OFFSET, newval); lastReq0.callback = currPta0.callback; lastReq0.parameter = currPta0.parameter; error0 = regval & PCI_DMACTRL_PADE0; /*If there is a transfer queued, initiate it*/ if (ptaRequestQueueSize > 2) { req=ptaTransferGet (); ptaTransferInitiate (req); } ptaRequestQueueSize--; } /* note that this is intentionally a separate "if", and should never be an "else if" since both transfers can have completed by the time we read the register*/ if(regval & PCI_DMACTRL_PADC1) { /*register set 1 transfer complete*/ newval = (regval & PCI_DMACTRL_APDCEN) | (regval & PCI_DMACTRL_PADCEN) | (PCI_DMACTRL_PADC1); REG_WRITE(PCI_CSR_BASE, PCI_DMACTRL_OFFSET, newval); lastReq1.callback = currPta1.callback; lastReq1.parameter = currPta1.parameter; error1 = regval & PCI_DMACTRL_PADE1; /*If there is a transfer queued, initiate it*/ if (ptaRequestQueueSize > 2) { req=ptaTransferGet (); ptaTransferInitiate (req); } ptaRequestQueueSize--; } /*This code would appear to be more at home within the body of the if blocks above, but the point of this control flow structure is to invoke the next ptaTransferInitiate as soon as possible after getting the interrupt, so that we maximize utilisation of the DMA channel, so we obviously want to avoid invoking client code callbacks before initiating our transfer*/ if (lastReq0.callback != NULL) { if (error0 != 0) { (lastReq0.callback)(PCI_ERROR, lastReq0.parameter); } else { (lastReq0.callback)(PCI_OK, lastReq0.parameter); } } /*Again, both requests may have completed so this is not an "else if"*/ if (lastReq1.callback != NULL) { if (error1 != 0) { (lastReq1.callback)(PCI_ERROR, lastReq1.parameter); } else { (lastReq1.callback)(PCI_OK, lastReq1.parameter); } } intUnlock(key); return;}/************************************************ pciDmaTransfer - transfer a block of data using DMA** This routine sets up a DMA transfer. If possible, it initiates* the transfer immediately, otherwise it adds it to a queue.* The destination and source addresses must be 4-byte aligned.** RETURNS: OK or ERROR if invalid parameters are supplied, or if the * relevant queue is full.*/STATUS pciDmaTransfer (void *buffer, void *pciAddr, UINT32 direction, UINT32 length, PCICALLBACKFUNC callback, UINT32 parameter){ UINT32 key; PCI_DMA_REQUEST newTransfer; if (length > IXP425_PCI_DMA_MAX_LEN) { return ERROR; } /*Check alignment of addresses*/ if (((UINT32)buffer & (UINT32)0x3) != 0) { return ERROR; } if (((UINT32)pciAddr & (UINT32)0x3) != 0) { return ERROR; } if (direction == IXP425_PCI_DMA_DIR_OUT) { /*AHB to PCI transfer*/ key=intLock(); if (atpRequestQueueSize < 2) { /*If the queue size is 0 or 1, this means that there is a free register set, so we can send the transfer directly to the registers*/ newTransfer.buffer = buffer; newTransfer.pciAddr = pciAddr; newTransfer.length = length; newTransfer.callback = callback; newTransfer.parameter = parameter; atpTransferInitiate(&newTransfer); } else { /*Otherwise we must add the request to the queue*/ if(atpTransferAdd(buffer, pciAddr, length, callback, parameter)!=OK) { intUnlock(key); return ERROR; } } /*regardless of whether we sent the transfer directly to the registers or queued it, the queue size has increased, since we consider the registers to be part of the queue*/ atpRequestQueueSize++; intUnlock(key); } else if (direction == IXP425_PCI_DMA_DIR_IN) { /*PCI to AHB transfer*/ key=intLock(); if (ptaRequestQueueSize < 2) { newTransfer.buffer = buffer; newTransfer.pciAddr = pciAddr; newTransfer.length = length; newTransfer.callback = callback; newTransfer.parameter = parameter; ptaTransferInitiate(&newTransfer); } else { if(ptaTransferAdd(buffer, pciAddr, length, callback, parameter)!=OK) { intUnlock(key); return ERROR; } } ptaRequestQueueSize++; intUnlock(key); } else { return ERROR; } return OK;}LOCAL voidpciOddByteTransfer (void *pciAddr, UINT8 *data, UINT32 direction, UINT32 length){ UINT32 i; for (i=0; i<length; i++) { if (direction == IXP425_PCI_DMA_DIR_OUT) { pciMemOutByte (pciAddr, *data); } else { pciMemInByte (pciAddr, (UINT8*)data); } pciAddr = (void*)((UINT8*)pciAddr+1); data = data + 1; } }LOCAL STATUSpciDmaSingleMbufTransfer (M_BLK *buffer, void *pciAddr, UINT32 direction, PCICALLBACKFUNC callback, UINT32 parameter){ UINT8 *data; UINT32 length; UINT32 lengthInLwords; UINT32 lengthDmaInBytes; UINT32 nonAlMaskAhb; UINT32 nonAlMaskPci; UINT32 numOdd; STATUS retval; data = buffer->mBlkHdr.mData; length = buffer->mBlkHdr.mLen; nonAlMaskAhb = (UINT32)data & (UINT32)0x3; nonAlMaskPci = (UINT32)pciAddr & (UINT32)0x3; /*If the AHB and PCI addresses are not equally misaligned we cannot do a DMA transfer*/ if (nonAlMaskPci != nonAlMaskAhb) { return ERROR; } if (nonAlMaskAhb) { /*there are odd bytes at the start of the transfer*/ numOdd = 4 - nonAlMaskAhb; pciOddByteTransfer (pciAddr, (UINT8*)data, direction, numOdd); pciAddr = (void*)((UINT8*)pciAddr+numOdd); data = data + numOdd; length -= numOdd; } /*now do the dma transfer*/ lengthDmaInBytes = ((UINT32)length & ~((UINT32)0x3)); lengthInLwords = lengthDmaInBytes >> 2; retval=pciDmaTransfer (data, pciAddr, direction, lengthInLwords, callback, parameter); if (retval != OK) { return retval; } /*transfer any odd bytes left over*/ length = length - lengthDmaInBytes; if (length != 0) { data = data + lengthDmaInBytes; pciAddr = (void*)((UINT8*)pciAddr+lengthDmaInBytes); pciOddByteTransfer(pciAddr, (UINT8*)data, direction, length); } return OK;}/************************************************ pciDmaMbufTransfer - transfer an Mbuf or chain of Mbufs of data using DMA** This routine transfers an mBuf's data across the PCI* bus using as much DMA as possible. If the data to be * transferred is not word aligned, the odd bytes at the * beginning and end of the block are transferred using * individual non-prefetch memory transactions, which will* have a negative impact on throughput.** RETURNS: OK, or ERROR if invalid parameters are supplied, or if the * relevant queue is full.*/ STATUS pciDmaMbufTransfer (M_BLK* buffer, void *pciAddr, UINT32 direction, PCICALLBACKFUNC callback, UINT32 parameter){ M_BLK* currentMblk; STATUS retval; if ((direction != IXP425_PCI_DMA_DIR_IN) && (direction != IXP425_PCI_DMA_DIR_OUT)) { return ERROR; } currentMblk = buffer; while (currentMblk != NULL) { retval=pciDmaSingleMbufTransfer (currentMblk, pciAddr, direction, callback, parameter); if (retval!=OK) { return retval; } pciAddr = (void*)((UINT8*)pciAddr+currentMblk->mBlkHdr.mLen); currentMblk = currentMblk->mBlkHdr.mNext; } return OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -