📄 cfe_dmtest.c
字号:
the same technique the interrupt routine uses and compare the pointers to the descriptor tables, or we can use the count. Both methods are shown below. */#ifdef _SBDMA_TEST_PTRS_ curidx = d->dm_addptr - d->dm_dscrring; hwidx = ((DM_READCSR(d->dm_curdscr) & M_DM_CUR_DSCR_DSCR_ADDR) - d->dm_dscrring_phys) / sizeof(sbdmadscr_t); return (curidx == hwidx);#else return (G_DM_CUR_DSCR_DSCR_COUNT(DM_READCSR(d->dm_curdscr)) == 0);#endif}/* ********************************************************************* * DM_WAIT(d) * * Returns elapsed zb clks when an interrupt becomes pending on * the channel and also processes the interrupt. * CAUTION: spins forever if misused. * * Input parameters: * none * * Return value: * stop time (zbclks) ********************************************************************* */static uint64_tdm_wait(sbgendma_t *d){ uint64_t stop; while (!dm_isdone(d)) continue; stop = zclk_get(); d->dm_busy = 0; return stop;}#endif /* !_SBDMA_INTERRUPTS_ *//* ********************************************************************* * DM_BUILDDESCR_P(dsc,dest,src,len,flags) * * Builds a descriptor. * * Input parameters: * dsc - pointer to descriptor to build * dest - destination address (physical) * src - source address (physical) * len - number of bytes to transfer * flags - flags for transfer * * Return value: * nothing ********************************************************************* */static voiddm_builddescr_p(sbdmadscr_t *dsc, uint64_t dest, uint64_t src, int len, flags_t flags){ dsc->dscr_a = dest | flags; dsc->dscr_b = src | V_DM_DSCRB_SRC_LENGTH(len);}#define CACHE_ALIGN(x, t) ((t)(((unsigned long)(x) + 31) & ~31))/* ********************************************************************* * DM_ALLOCDSCRS(count) * * Allocates dynamic storage for a descriptor ring * * Input parameters: * cnt - number of descriptors * * Return value: * pointer to the allocated space (use only cache-aligned slots) ********************************************************************* */static void *dm_allocdscrs(int cnt){ /* Allocate with enough fudge to cache-align. */ return KMALLOC(cnt * sizeof(sbdmadscr_t) + 32, 0);}/* ********************************************************************* * DM_INITCTX(ch,n,priority) * * Initialize a generic DMA context - this structure describes * the hardware and software state for the device driver. * * Input parameters: * ch - channel number (0..3) * n - desired number of available descriptors * (ring size is n+1 to distinguish full/empty cases) * priority - priority for this channel (K_DM_DSCR_BASE_PRIORITY_x) * * Return value: * nothing ********************************************************************* */static voiddm_initctx(int ch, int n, int priority){ sbgendma_t *d; uint64_t base; /* Initialize the fields in the DMA controller's context. */ d = &sbgendma_ctx[ch]; d->ch = ch; d->dm_dscrbase = (sbport_t) A_DM_REGISTER(ch, R_DM_DSCR_BASE); d->dm_dscrcnt = (sbport_t) A_DM_REGISTER(ch, R_DM_DSCR_COUNT); d->dm_curdscr = (sbport_t) A_DM_REGISTER(ch, R_DM_CUR_DSCR_ADDR); /* Initialize the pointers to the DMA descriptor ring. */ d->dm_dscrmem = dm_allocdscrs(n+1); d->dm_dscrring = CACHE_ALIGN(d->dm_dscrmem, sbdmadscr_t *); d->dm_dscrring_end = d->dm_dscrring + (n+1); d->dm_addptr = d->dm_dscrring; d->dm_remptr = d->dm_dscrring; d->dm_newcnt = 0; d->dm_busy = 0; /* Calculate the physical address of the start of the descriptor ring. We need this for determining when the pointers wrap. */ d->dm_dscrring_phys = (sbphysaddr_t) SBDMA_VTOP(d->dm_dscrring); /* Finally, set up the DMA controller. */ base = d->dm_dscrring_phys | V_DM_DSCR_BASE_PRIORITY(priority) | V_DM_DSCR_BASE_RINGSZ(n+1); DM_WRITECSR(d->dm_dscrbase, base); (void)DM_READCSR(d->dm_dscrbase); /* push */ base = d->dm_dscrring_phys | V_DM_DSCR_BASE_PRIORITY(priority) | V_DM_DSCR_BASE_RINGSZ(n+1) | M_DM_DSCR_BASE_RESET; /* disable and reset */ DM_WRITECSR(d->dm_dscrbase, base); (void)DM_READCSR(d->dm_dscrbase); /* push */ base = d->dm_dscrring_phys | V_DM_DSCR_BASE_PRIORITY(priority) | V_DM_DSCR_BASE_RINGSZ(n+1) | M_DM_DSCR_BASE_ENABL; /* enable */ DM_WRITECSR(d->dm_dscrbase, base);}/* ********************************************************************* * DM_UNINITCTX(ch) * * Finalize a generic DMA context - this structure describes * the hardware and software state for the device driver. * * Input parameters: * ch - channel number (0..3) * * Return value: * nothing ********************************************************************* */static voiddm_uninitctx(int ch){ sbgendma_t *d; uint64_t base; /* Finalize the fields in the DMA controller's context. */ d = &sbgendma_ctx[ch]; if (d->dm_dscrmem != NULL) { KFREE(d->dm_dscrmem); } d->dm_dscrmem = NULL; d->dm_dscrring = NULL; d->dm_dscrring_end = NULL; d->dm_addptr = NULL; d->dm_remptr = NULL; d->dm_newcnt = 0; d->dm_busy = 0; d->dm_dscrring_phys = (sbphysaddr_t) 0; base = d->dm_dscrring_phys; DM_WRITECSR(d->dm_dscrbase, base); (void)DM_READCSR(d->dm_dscrbase); /* push */ DM_WRITECSR(d->dm_dscrbase, base | M_DM_DSCR_BASE_RESET);}/* ********************************************************************* * DM_STARTONE(ch,dscr) * * Start a single descriptor * * Input parameters: * ch - DMA channel number. * dscr - descriptor to run * * Return value: * start time (zbclks) ********************************************************************* */static uint64_tdm_startone(int ch, sbdmadscr_t *dscr){ sbgendma_t *d = &sbgendma_ctx[ch]; /* Try to put it on the queue. If this doesn't work, call the polling function until we get space. This can happen if the ring is full when we attempt to add a descriptor, which is very unlikely in this test program. */ for (;;) { if (dm_adddescr(d, dscr, 1) == 1) { break; }#ifdef _SBDMA_POLL_ dm_procbuffers(d);#endif } return dm_start(d);}/* ********************************************************************* * DM_RUNONE(ch,dscr) * * Run a single descriptor, waiting until it completes before * returning to the calling program. * * Input parameters: * ch - DMA channel number. * dscr - descriptor to run * * Return value: * elapsed time (zbclks) ********************************************************************* */static uint64_tdm_runone(int ch, sbdmadscr_t *dscr){ sbgendma_t *d = &sbgendma_ctx[ch]; uint64_t start, stop; start = dm_startone(ch, dscr); stop = dm_wait(d); return zclk_elapsed(stop, start);}/* ********************************************************************* * DM_RESET() * * Reset and initialize global data structures. * * Input parameters: * none * * Return value: * none ********************************************************************* */static voiddm_reset(void){ sbport_t dscrbase_p; int ch; for (ch = 0; ch < DM_NUM_CHANNELS; ch++) { dscrbase_p = (sbport_t) A_DM_REGISTER(ch, R_DM_DSCR_BASE); DM_WRITECSR(dscrbase_p, M_DM_DSCR_BASE_RESET); } for (ch = 0; ch < DM_NUM_CHANNELS; ch++) { dscrbase_p = (sbport_t) A_DM_REGISTER(ch, R_DM_DSCR_BASE); while (DM_READCSR(dscrbase_p) && M_DM_DSCR_BASE_ACTIVE) { /* XXX Need a timeout and fail path */ POLL(); } }}/* ********************************************************************* * DM_INIT() * * Initialize global data structures if necessary. * * Input parameters: * none * * Return value: * none ********************************************************************* */static voiddm_init(void){ if (!sbgendma_initialized) { dm_reset(); zclk_init(0); /* Time origin is arbitrary */ dm_initctx(SBDMA_CMD_CH, 1, K_DM_DSCR_BASE_PRIORITY_1);#ifdef _SBDMA_INTERRUPTS_ cfe_request_irq(K_INT_DM_CH_0 + SBDMA_CMD_CH, dm_interrupt, &sbgendma_ctx[SBDMA_CMD_CH], 0, 0);#endif /* _SBDMA_INTERRUPTS_ */ sbgendma_initialized = 1; }}/* ********************************************************************* * DM_CMD_INIT(flush) * * Initialize global data structures, if necessary. * * Input parameters: * flush - flush caches first (for timing) * * Return value: * none ********************************************************************* */static voiddm_cmd_init(int flush){ dm_init(); if (flush)#if 0 cfe_flushcache(16+1); /* L2 plus L1 D */#else ;#endif}/* ********************************************************************* * DM_BCOPY_P(src,dest,cnt,flags) * * This is an example implementation of "bcopy" that uses * the data mover. * * Input parameters: * ch - DMA channel number. * src - source physical address * dest - destination physical address * cnt - count of bytes to copy * flags - option flags * * Return value: * elapsed time (zbclks) ********************************************************************* */static uint64_tdm_bcopy_p(int ch, uint64_t src, uint64_t dest, int cnt, flags_t flags){ sbdmadscr_t dscr; if (src < dest && (uint64_t)(src + cnt) > (uint64_t)dest) { flags |= SRCDEC|DSTDEC; dest += cnt - 1; src += cnt - 1; } else { flags |= SRCINC|DSTINC; } dm_builddescr_p(&dscr, dest, src, cnt, flags|INTER); return dm_runone(ch, &dscr);}/* ********************************************************************* * DM_BCOPY(src,dest,cnt) * * This is an example implementation of "bcopy" that uses * the data mover. * * Input parameters: * src - source virtual address * dest - destination virtual address * cnt - count of bytes to copy * * Return value: * nothing ********************************************************************* */voiddm_bcopy(void *src, void *dest, int cnt){ dm_bcopy_p(SBDMA_CMD_CH, phys_addr((long)src), phys_addr((long)dest), cnt, 0);}/* ********************************************************************* * DM_MULTIBCOPY_P(ch,src,dest,cnt,flags) * * Input parameters: * ch - DMA channel number. * src - source physical address * dest - destination physical address * cnt - count of bytes to copy * step - maximum bytes per descriptor * flags - option flags * * Return value: * elapsed time (zbclks) ********************************************************************* */static uint64_tdm_multibcopy_p(int ch, uint64_t src, uint64_t dest, int cnt, int step, flags_t flags){ sbgendma_t *d = &sbgendma_ctx[ch]; sbdmadscr_t dscr; int dnum; uint64_t start, stop; dnum = (cnt + (step-1))/step; if (dnum == 0) { return 0; } flags |= SRCINC|DSTINC; dm_init(); dm_initctx(ch, dnum, K_DM_DSCR_BASE_PRIORITY_1);#ifdef _SBDMA_INTERRUPTS_ cfe_request_irq(K_INT_DM_CH_0 + ch, dm_interrupt, d, 0, 0);#endif while (cnt > 0) { int n = (cnt < step ? cnt : step); if (cnt <= n) flags |= INTER; dm_builddescr_p(&dscr, dest, src, n, flags); dm_adddescr(d, &dscr, 1); src += n; dest += n; cnt -= n; } start = dm_start(d); stop = dm_wait(d); cfe_free_irq(K_INT_DM_CH_0 + ch, 0); dm_uninitctx(ch); return zclk_elapsed(stop, start);}/* ********************************************************************* * DM_MULTIBCOPY(src,dest,cnt) * * This is a variant of BCOPY that queues up several descriptors to * do the work. * * Input parameters: * src - source virtual address * dest - destination virtual address * len - count of bytes to copy * blksize - maximum bytes per descriptor * * Return value: * nothing ********************************************************************* */voiddm_multibcopy(void *src, void *dest, int len, int blksize){ dm_multibcopy_p(SBDMA_CMD_CH, phys_addr((long) src), phys_addr((long) dest), len, blksize, 0);}/* ********************************************************************* * DM_BZERO_P(dest,cnt,flags) * * Input parameters: * ch - DMA channel number. * dest - physical address * cnt - count of bytes to zero * flags - option flags * * Return value: * elapsed time (zbclks) ********************************************************************* */static uint64_tdm_bzero_p(int ch, uint64_t dest, int cnt, flags_t flags){ sbdmadscr_t dscr; flags |= SRCCON|ZEROMEM|DSTINC; dm_builddescr_p(&dscr, dest, 0, cnt, flags|INTER); return dm_runone(ch, &dscr);}/* ********************************************************************* * DM_BZERO(dest,cnt) * * This is an example implementation of "bzero" that uses * the data mover. * * Input parameters: * dest - destination virtual address * cnt - count of bytes to zero * * Return value: * nothing ********************************************************************* */voiddm_bzero(void *dest, int cnt){ dm_bzero_p(SBDMA_CMD_CH, phys_addr((long) dest), cnt, 0);}/* ********************************************************************* * DM_BSINK_P(ch,src,cnt,flags) * * Input parameters: * ch - DMA channel number. * src - physical address * cnt - count of bytes to read * flags - option flags * * Return value: * elapsed time (zbclks) ********************************************************************* */static uint64_tdm_bsink_p(int ch, uint64_t src, int cnt, flags_t flags){ sbdmadscr_t dscr; flags |= SRCINC|PREFETCH|DSTCON; dm_builddescr_p(&dscr, 0, src, cnt, flags|INTER); return dm_runone(ch, &dscr);}/* ********************************************************************* * DM_BSINK(src,cnt) * * Input parameters: * src - physical address * cnt - count of bytes to read
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -