📄 mcd_dmaapi.c
字号:
|| MCD_chStatus[channel] == MCD_IDLE) { MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT; /* This register is selected to know which initiator is actually asserted. */ if ((MCD_dmaBar->ptdDebug >> channel) & 0x1) MCD_chStatus[channel] = MCD_RUNNING; else MCD_chStatus[channel] = MCD_IDLE; /* do not change the status if it is already paused. */ } } return MCD_chStatus[channel];}/******************** End of MCD_dmaStatus() ************************//********************************************************************//* Function: MCD_startDma * Ppurpose: Starts a particular kind of DMA * Arguments: * srcAddr - the channel on which to run the DMA * srcIncr - the address to move data from, or buffer-descriptor address * destAddr - the amount to increment the source address per transfer * destIncr - the address to move data to * dmaSize - the amount to increment the destination address per transfer * xferSize - the number bytes in of each data movement (1, 2, or 4) * initiator - what device initiates the DMA * priority - priority of the DMA * flags - flags describing the DMA * funcDesc - description of byte swapping, bit swapping, and CRC actions * srcAddrVirt - virtual buffer descriptor address TBD * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK */int MCD_startDma(int channel, s8 * srcAddr, s16 srcIncr, s8 * destAddr, s16 destIncr, u32 dmaSize, u32 xferSize, u32 initiator, int priority, u32 flags, u32 funcDesc#ifdef MCD_NEED_ADDR_TRANS s8 * srcAddrVirt#endif ){ int srcRsdIncr, destRsdIncr; int *cSave; short xferSizeIncr; int tcrCount = 0;#ifdef MCD_INCLUDE_EU u32 *realFuncArray;#endif if ((channel < 0) || (channel >= NCHANNELS)) return (MCD_CHANNEL_INVALID); /* tbd - need to determine the proper response to a bad funcDesc when not including EU functions, for now, assign a benign funcDesc, but maybe should return an error */#ifndef MCD_INCLUDE_EU funcDesc = MCD_FUNC_NOEU1;#endif#ifdef MCD_DEBUG printf("startDma:Setting up params\n");#endif /* Set us up for task-wise priority. We don't technically need to do this on every start, but since the register involved is in the same longword as other registers that users are in control of, setting it more than once is probably preferable. That since the documentation doesn't seem to be completely consistent about the nature of the PTD control register. */ MCD_dmaBar->ptdControl |= (u16) 0x8000; /* Not sure what we need to keep here rtm TBD */#if 1 /* Calculate additional parameters to the regular DMA calls. */ srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0); destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0); xferSizeIncr = (xferSize & 0xffff) | 0x20000000; /* Remember for each channel which variant is running. */ MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr; MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr; MCD_remVariants.remDestIncr[channel] = destIncr; MCD_remVariants.remSrcIncr[channel] = srcIncr; MCD_remVariants.remXferSize[channel] = xferSize;#endif cSave = (int *)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET + CURRBD;#ifdef MCD_INCLUDE_EU /* may move this to EU specific calls */ realFuncArray = (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00); /* Modify the LURC's normal and byte-residue-loop functions according to parameter. */ realFuncArray[(LURC * 16)] = xferSize == 4 ? funcDesc : xferSize == 2 ? funcDesc & 0xfffff00f : funcDesc & 0xffff000f; realFuncArray[(LURC * 16 + 1)] = (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;#endif /* Write the initiator field in the TCR, and also set the initiator-hold bit. Note that,due to a hardware quirk, this could collide with an MDE access to the initiator-register file, so we have to verify that the write reads back correctly. */ MCD_dmaBar->taskControl[channel] = (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM; while (((MCD_dmaBar->taskControl[channel] & 0x1fff) != ((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM)) && (tcrCount < 1000)) { tcrCount++; /*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020; */ MCD_dmaBar->taskControl[channel] = (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM; } MCD_dmaBar->priority[channel] = (u8) priority & PRIORITY_PRI_MASK; /* should be albe to handle this stuff with only one write to ts reg - tbd */ if (channel < 8 && channel >= 0) { MCD_dmaBar->taskSize0 &= ~(0xf << (7 - channel) * 4); MCD_dmaBar->taskSize0 |= (xferSize & 3) << (((7 - channel) * 4) + 2); MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel) * 4); } else { MCD_dmaBar->taskSize1 &= ~(0xf << (15 - channel) * 4); MCD_dmaBar->taskSize1 |= (xferSize & 3) << (((15 - channel) * 4) + 2); MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel) * 4); } /* setup task table flags/options which mostly control the line buffers */ MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK; MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags); if (flags & MCD_FECTX_DMA) { /* TDTStart and TDTEnd */ MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECTX].TDTstart; MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECTX].TDTend; MCD_startDmaENetXmit(srcAddr, srcAddr, destAddr, MCD_taskTable, channel); } else if (flags & MCD_FECRX_DMA) { /* TDTStart and TDTEnd */ MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_FECRX].TDTstart; MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_FECRX].TDTend; MCD_startDmaENetRcv(srcAddr, srcAddr, destAddr, MCD_taskTable, channel); } else if (flags & MCD_SINGLE_DMA) { /* this buffer descriptor is used for storing off initial parameters for later progress query calculation and for the DMA to write the resulting checksum. The DMA does not use this to determine how to operate, that info is passed with the init routine */ MCD_relocBuffDesc[channel].srcAddr = srcAddr; MCD_relocBuffDesc[channel].destAddr = destAddr; /* definitely not its final value */ MCD_relocBuffDesc[channel].lastDestAddr = destAddr; MCD_relocBuffDesc[channel].dmaSize = dmaSize; MCD_relocBuffDesc[channel].flags = 0; /* not used */ MCD_relocBuffDesc[channel].csumResult = 0; /* not used */ MCD_relocBuffDesc[channel].next = 0; /* not used */ /* Initialize the progress-querying stuff to show no progress: */ ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr; ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr; ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0; ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[CURRBD + CSAVE_OFFSET] =(u32) & (MCD_relocBuffDesc[channel]); /* tbd - need to keep the user from trying to call the EU routine when MCD_INCLUDE_EU is not defined */ if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) { /* TDTStart and TDTEnd */ MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart; MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLENOEU].TDTend; MCD_startDmaSingleNoEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize, xferSizeIncr, flags, (int *) &(MCD_relocBuffDesc[channel]), cSave, MCD_taskTable, channel); } else { /* TDTStart and TDTEnd */ MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_SINGLEEU].TDTstart; MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_SINGLEEU].TDTend; MCD_startDmaSingleEu(srcAddr, srcIncr, destAddr, destIncr, dmaSize, xferSizeIncr, flags, (int *) &(MCD_relocBuffDesc[channel]), cSave, MCD_taskTable, channel); } } else { /* chained DMAS */ /* Initialize the progress-querying stuff to show no progress: */#if 1 /* (!defined(MCD_NEED_ADDR_TRANS)) */ ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)((MCD_bufDesc *) srcAddr)->srcAddr; ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)((MCD_bufDesc *) srcAddr)->destAddr;#else /* if using address translation, need the virtual addr of the first buffdesc */ ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)((MCD_bufDesc *) srcAddrVirt)->srcAddr; ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)((MCD_bufDesc *) srcAddrVirt)->destAddr;#endif ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0; ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr; if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) { /*TDTStart and TDTEnd */ MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart; MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINNOEU].TDTend; MCD_startDmaChainNoEu((int *)srcAddr, srcIncr, destIncr, xferSize, xferSizeIncr, cSave, MCD_taskTable, channel); } else { /*TDTStart and TDTEnd */ MCD_taskTable[channel].TDTstart = MCD_modelTaskTable[TASK_CHAINEU].TDTstart; MCD_taskTable[channel].TDTend = MCD_modelTaskTable[TASK_CHAINEU].TDTend; MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr, xferSize, xferSizeIncr, cSave, MCD_taskTable, channel); } } MCD_chStatus[channel] = MCD_IDLE; return (MCD_OK);}/************************ End of MCD_startDma() *********************//********************************************************************//* Function: MCD_XferProgrQuery * Purpose: Returns progress of DMA on requested channel * Arguments: channel - channel to retrieve progress for * progRep - pointer to user supplied MCD_XferProg struct * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK * * Notes: * MCD_XferProgrQuery() upon completing or after aborting a DMA, or * while the DMA is in progress, this function returns the first * DMA-destination address not (or not yet) used in the DMA. When * encountering a non-ready buffer descriptor, the information for * the last completed descriptor is returned. * * MCD_XferProgQuery() has to avoid the possibility of getting * partially-updated information in the event that we should happen * to query DMA progress just as the DMA is updating it. It does that * by taking advantage of the fact context is not saved frequently for * the most part. We therefore read it at least twice until we get the * same information twice in a row. * * Because a small, but not insignificant, amount of time is required * to write out the progress-query information, especially upon * completion of the DMA, it would be wise to guarantee some time lag * between successive readings of the progress-query information. *//* How many iterations of the loop below to execute to stabilize values */#define STABTIME 0int MCD_XferProgrQuery(int channel, MCD_XferProg * progRep){ MCD_XferProg prevRep; int again; /* true if we are to try again to ge consistent results */ int i; /* used as a time-waste counter */ int destDiffBytes; /* Total no of bytes that we think actually got xfered. */ int numIterations; /* number of iterations */ int bytesNotXfered; /* bytes that did not get xfered. */ s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr; int subModVal, addModVal; /* Mode values to added and subtracted from the final destAddr */ if ((channel < 0) || (channel >= NCHANNELS)) return (MCD_CHANNEL_INVALID); /* Read a trial value for the progress-reporting values */ prevRep.lastSrcAddr = (s8 *) ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[SRCPTR + CSAVE_OFFSET]; prevRep.lastDestAddr = (s8 *) ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DESTPTR + CSAVE_OFFSET]; prevRep.dmaSize = ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT + CSAVE_OFFSET]; prevRep.currBufDesc = (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[CURRBD + CSAVE_OFFSET]; /* Repeatedly reread those values until they match previous values: */ do { /* Waste a little bit of time to ensure stability: */ for (i = 0; i < STABTIME; i++) { /* make sure this loop does something so that it doesn't get optimized out */ i += i >> 2; } /* Check them again: */ progRep->lastSrcAddr = (s8 *) ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[SRCPTR + CSAVE_OFFSET]; progRep->lastDestAddr = (s8 *) ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DESTPTR + CSAVE_OFFSET]; progRep->dmaSize = ((volatile int *)MCD_taskTable[channel]. contextSaveSpace)[DCOUNT + CSAVE_OFFSET]; progRep->currBufDesc = (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -