📄 tffsarch.c
字号:
tffsInfo.dma_buf_size = 0; if ((tffs_dma_mode >= 1)#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) || !defined(PXA27X_DCACHE_BUG_WORKAROUND) && (tffs_dma_mode <= 3)#endif ) { /* allocate intermediate DMA buffer (we assume one MMU page will be enough) */ tffsInfo.dma_buf_size = PAGE_SIZE; tffsInfo.dma_buf_vptr = #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) consistent_alloc ((GFP_KERNEL | GFP_DMA), tffsInfo.dma_buf_size, &tffsInfo.dma_buf_paddr);#else dma_alloc_coherent (NULL, tffsInfo.dma_buf_size, &tffsInfo.dma_buf_paddr, (GFP_KERNEL | GFP_DMA));#endif if (tffsInfo.dma_buf_vptr == NULL) { /* failed to allocate intermediate DMA buffer, won't use DMA */ tffs_dma_mode = 0; pxa_free_dma (tffsInfo.channel); tffsInfo.channel = -1; tffsInfo.dma_buf_size = 0; PrintkError ("can't alloc DMA buffer, won't use DMA"); } } }}/*-----------------------------------------------------------------------* * * * t f f s _ d m a _ r e l e a s e * * * * Release all previously allocated DMA resources (channel, intermediate * * DMA buffer etc.). For Intel PXA27x (Mainstone) board. * * * *-----------------------------------------------------------------------*/static void tffs_dma_release(void){ /* if previously was allocated, release DMA channel */ if (tffsInfo.channel >= 0) { pxa_free_dma (tffsInfo.channel); tffsInfo.channel = -1; } /* if previously was allocated, release intermediate DMA buffer */ if (tffsInfo.dma_buf_vptr != NULL) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) consistent_free (tffsInfo.dma_buf_vptr, PAGE_SIZE, tffsInfo.dma_buf_paddr);#else dma_free_coherent (NULL, PAGE_SIZE, tffsInfo.dma_buf_vptr, tffsInfo.dma_buf_paddr);#endif tffsInfo.dma_buf_vptr = NULL; }}/*-----------------------------------------------------------------------* * * * _ _ d m a s w _ b r e a d * * * * Transfer data from DiskOnChip's I/O reguster to RAM buffer. * * Example implementation For Intel PXA27x (Mainstone) board. * * * * Parameters: * * off offset of DiskOnChip's I/O register from the base * * of DiskOnChip window * * vbuf virtual address of RAM buffer * * bytes bytes to transfer * * * *-----------------------------------------------------------------------*/staticvoid __dmasw_bread ( int off, void * vbuf, unsigned int bytes ){ int chan = tffsInfo.channel; u_int tmp; register int waiting; register int direct_dma; profiling[2]++; direct_dma = ((tffs_dma_mode & 4) ? TRUE : FALSE); /* Due to a bug in kernel routine blk_dma_inv_range_harvard() * (arch/arm/mm/blockops.c), we allow direct DMA to destination * buffer 'vbuf' only when it's aligned at CPU's cache line boundary. */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && defined(PXA27X_DCACHE_BUG_WORKAROUND) if ((u32)vbuf & 31) direct_dma = FALSE;#endif /* Set source physical address for DMA transfer (this would be DiskOnChip's * I/O register which is located at offset 'off' from the DiskOnChip's * base address as specified by tffs_addr[0]). */ DSADR(chan) = tffs_addr[0] + off; /* Set target physical address for DMA transfer. * This would be physical address of intermediate DMA buffer (for * DMA modes 1/2/3), or physical address of the destination buffer * (for DMA modes 5/6/7). */ if (direct_dma == TRUE) /* do DMA transfer directly into 'vbuf' */ { if (virt_addr_valid((unsigned long)vbuf)) /* 'vbuf' is in low memory */ { DTADR(chan) = __pa (vbuf); } else /* 'vbuf' is in high memory */ { char * k_vbuf = (char *) page_address(vmalloc_to_page(vbuf)) + ((unsigned long)vbuf & (PAGE_SIZE - 1)); if (k_vbuf == NULL) { PrintkError ("error, DMA requested on high memory page"); return; } DTADR(chan) = __pa (k_vbuf); /* andrayk Nov 22 2006: possible bug. Routine consistent_alloc() * (arch/arm/mm/consistent.c) applies __pa() macro to it's 'vbuf' * argument (see below). This might cause CPU exception. */ } /* Write (if dirty) and purge contents of 'vbuf' from CPU cache(s) */ /* Possible options: * consistent_sync(vbuf, bytes, DMA_FROM_DEVICE); ARM/SH * dma_cache_inv((unsigned long)vbuf, (unsigned long)bytes); MIPS/PPC/x86 */#ifdef PXA27X_DCACHE_BUG_WORKAROUND /* Routine blk_dma_inv_range_harvard() (arch/arm/mm/blockops.c) appears * to be buggy: it seems to constantly shoot past the end of the address * range [vbuf..vbuf+bytes] by 32 bytes. It also appears to write some * bogus data into this RAM address range while invalidating it in D-cache. */ consistent_sync (vbuf, bytes - 1, DMA_FROM_DEVICE);#else consistent_sync (vbuf, bytes, DMA_FROM_DEVICE);#endif } else /* transfer into intermediate DMA buffer */ { DTADR(chan) = tffsInfo.dma_buf_paddr; } /* specify parameters of DMA transfer */ tmp = DCMD_INCTRGADDR | /* increment target address */ DCMD_WIDTH2 | /* 16-bit data path */ /* DCMD_ENDIRQEN | */ /* don't generate interrupt at the end of transfer */ bytes; if ((bytes & 31) == 0) tmp |= DCMD_BURST32; /* 32-bytes burst */ DCMD(chan) = tmp; /* clear all status bits, and start DMA transfer */ DCSR(chan) = (DCSR_RUN | DCSR_NODESC | DCSR_ENDINTR | DCSR_STOPSTATE | DCSR_BUSERR); /* poll DMA channel's status register for end of DMA transfer */ for (waiting = 100000; waiting > 0; waiting--) /* hope this is long enough ... */ { /* read Channel Status Register to find out status of DMA transfer */ tmp = DCSR (chan); if (tmp & (DCSR_STOPSTATE | DCSR_BUSERR)) { if ((tmp & DCSR_BUSERR) == 0) { /* DMA transfer completed, move data from the intermediate DMA * buffer to the destination buffer (in case it was used). */ if (direct_dma == FALSE) memcpy (vbuf, tffsInfo.dma_buf_vptr, bytes); } else { PrintkError ("Bus error, DMA transfer failed"); /* andrayk Mar 24 2006: DMA transfer failed, find way to let MTD know this */ } return; } } PrintkError ("DMA transfer timed out");}/*-----------------------------------------------------------------------* * * * _ _ d m a s w _ b w r i t e * * * * Transfer data from RAM buffer to DiskOnChip's I/O reguster. * * Example implementation for Intel PXA27x (Mainstone) board. * * * * Parameters: * * off offset of DiskOnChip's I/O register from the base * * of DiskOnChip window * * vbuf virtual address of RAM buffer * * bytes bytes to transfer * * * *-----------------------------------------------------------------------*/staticvoid __dmasw_bwrite ( int off, void * vbuf, unsigned int bytes ){ int chan = tffsInfo.channel; u_int tmp; register int waiting; profiling[3]++; /* Set target physical address for DMA transfer (this would be DiskOnChip's * I/O register which is located at offset 'off' from the DiskOnChip's * base address as specified by tffs_addr[0]). */ DTADR(chan) = tffs_addr[0] + off; /* set source physical address for DMA transfer */ if (tffs_dma_mode & 4) /* do DMA transfer directly from 'vbuf' */ { /* Write (if dirty) contents of 'vbuf' from CPU D-cache to RAM. * Possible options: * consistent_sync(vbuf, bytes, DMA_TO_DEVICE); ARM/SH * dma_cache_wback((unsigned long)vbuf, (unsigned long)bytes); MIPS/PPC/x86 */ consistent_sync (vbuf, bytes, DMA_TO_DEVICE); if (virt_addr_valid((unsigned long)vbuf)) /* 'vbuf' is in low memory */ { DSADR(chan) = __pa (vbuf); } else /* 'vbuf' is in high memory */ { char * k_vbuf = (char *) page_address(vmalloc_to_page(vbuf)) + ((unsigned long)vbuf & (PAGE_SIZE - 1)); if (k_vbuf == NULL) { PrintkError ("error, DMA requested on high memory page"); return; } DSADR(chan) = __pa (k_vbuf); } } else /* use intermediate DMA buffer */ { /* move data from RAM buffer to the intermediate DMA buffer */ memcpy (tffsInfo.dma_buf_vptr, vbuf, bytes); DSADR(chan) = tffsInfo.dma_buf_paddr; } /* specify parameters of DMA transfer */ tmp = DCMD_INCSRCADDR | /* increment source address */ DCMD_WIDTH2 | /* 16-bit data path */ /* DCMD_ENDIRQEN | */ /* don't generate interrupt at the end of transfer */ bytes; if ((bytes & 31) == 0) tmp |= DCMD_BURST32; /* 32-bytes burst */ DCMD(chan) = tmp; /* clear all status bits, and start DMA transfer */ DCSR(chan) = (DCSR_RUN | DCSR_NODESC | DCSR_ENDINTR | DCSR_STOPSTATE | DCSR_BUSERR); /* poll DMA channel's status register for end of DMA transfer */ for (waiting = 100000; waiting > 0; waiting--) /* hope this is long enough ... */ { /* read Channel Status Register to find out status of DMA transfer */ tmp = DCSR (chan); if (tmp & (DCSR_STOPSTATE | DCSR_BUSERR)) { if (tmp & DCSR_BUSERR) { PrintkError ("Bus error, DMA transfer failed"); /* andrayk Mar 24 2006: DMA transfer failed, find way to let MTD know this */ } else { /* DMA transfer successful */ } return; } } PrintkError ("DMA transfer timed out");}/*-----------------------------------------------------------------------* * *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -