📄 cachelib.c
字号:
2: void * pBuf; /@ buffer pointer parameter @/ {5: if (pBuf != NULL) {7: /@ no cache coherency problems with buffer passed to driver @/ } else {11: pBuf = cacheDmaMalloc (BUF_SIZE);13: if (pBuf == NULL)14: return (ERROR); /@ memory allocator failed @/ }17: /@ other driver initialization and buffer filling @/19: CACHE_DMA_FLUSH (pBuf, BUF_SIZE);20: drvWrite (pBuf); /@ output data to device @/22: /@ more driver code @/24: drvWait (); /@ wait for device data @/25: CACHE_DMA_INVALIDATE (pBuf, BUF_SIZE);27: /@ handle input data from device @/29: cacheDmaFree (pBuf); /@ return buffer to memory pool @/30: return (OK); }.CEDo not use CACHE_DMA_FLUSH or CACHE_DMA_INVALIDATE without first callingcacheDmaMalloc(), otherwise the function pointers may not beinitialized correctly. Note that this driver scheme assumes all cachecoherency modes have been set before driver initialization, and thatthe modes do not change after driver initialization. The cacheFlush() andcacheInvalidate() functions can be used at any time throughout the systemsince they are affiliated with the hardware, not the malloc/free buffer.A call to cacheLibInit() in write-through mode makes the flush functionpointers NULL. Setting the caches in copyback mode (if supported) shouldset the pointer to and call an architecture-specific flush routine. Theinvalidate and flush macros may be NULLified if the hardware provides bussnooping and there are no cache coherency problems..SH "Example 3"The next example shows a more complex driver that requires addresstranslations to assist in the cache coherency scheme. The previousexample had `a priori' knowledge of the system memory map and/or the deviceinteraction with the memory system. This next driver demonstrates a case in which the virtual address returned by cacheDmaMalloc() might differ from the physical address seen by the device. It uses the CACHE_DMA_VIRT_TO_PHYS and CACHE_DMA_PHYS_TO_VIRT macros in addition to the CACHE_DMA_FLUSH andCACHE_DMA_INVALIDATE macros.The cacheDmaMalloc() routine initializes the buffer pointer (line 3). Ifthe memory allocator fails (line 5), the driver will typically returnERROR (line 6) and quit. The driver fills the output buffer withinitialization information, device commands, and data (line 8), and isprepared to pass the buffer to the device. Before doing so, the drivermust flush the data cache (line 10) to ensure that the buffer is inmemory, not hidden in the cache. The flush is based on the virtualaddress since the processor filled in the buffer. The drvWrite() routinelets the device know that the data is ready and where in memory it islocated (line 11). Note that the CACHE_DMA_VIRT_TO_PHYS macro convertsthe buffer's virtual address to the corresponding physical address for thedevice.More driver code is executed (line 13), and the driver is then ready toreceive data that the device has placed in the buffer in memory (line15). Note the use of the CACHE_DMA_PHYS_TO_VIRT macro on the bufferpointer received from the device. Before the driver cache can workwith the incoming data, it must invalidate the data cache entries (line16) that correspond to the input buffer's data in order to eliminate stale entries. That done, it is safe for the driver to handle the input data (line 17), which it retrieves from memory. Remember to free (line19) the buffer acquired from the memory allocator. The driver will returnOK (line 20) to distinguish a successful from an unsuccessful operation..CSSTATUS drvExample3 () /@ complex driver - great performance @/ {3: void * pBuf = cacheDmaMalloc (BUF_SIZE);5: if (pBuf == NULL)6: return (ERROR); /@ memory allocator failed @/8: /@ other driver initialization and buffer filling @/10: CACHE_DMA_FLUSH (pBuf, BUF_SIZE);11: drvWrite (CACHE_DMA_VIRT_TO_PHYS (pBuf));13: /@ more driver code @/15: pBuf = CACHE_DMA_PHYS_TO_VIRT (drvRead ());16: CACHE_DMA_INVALIDATE (pBuf, BUF_SIZE);17: /@ handle input data from device @/19: cacheDmaFree (pBuf); /@ return buffer to memory pool @/20: return (OK); }.CE.SH "Driver Summary"The virtual-to-physical and physical-to-virtual function pointersassociated with cacheDmaMalloc() are supplements to a cache-safe buffer.Since the processor operates on virtual addresses and the devices accessphysical addresses, discrepant addresses can occur and might preventDMA-type devices from being able to access the allocated buffer.Typically, the MMU is used to return a buffer that has pages marked as non-cacheable. An MMU is used to translate virtual addresses into physicaladdresses, but it is not guaranteed that this will be a "transparent"translation.When cacheDmaMalloc() does something that makes the virtual addressdifferent from the physical address needed by the device, it provides thetranslation procedures. This is often the case when using translationlookaside buffers (TLB) or a segmented address space to inhibit caching(e.g., by creating a different virtual address for the same physicalspace.) If the virtual address returned by cacheDmaMalloc() is the sameas the physical address, the function pointers are made NULL so that no callsare made when the macros are expanded..SH "Board Support Packages"Each board for an architecture with more than one cache implementation hasthe potential for a different cache system. Hence the BSP for selectingthe appropriate cache library. The function pointer `sysCacheLibInit' isset to cacheXxxLibInit() ("Xxx" refers to the chip-specific name of alibrary or function) so that the function pointers for that cache systemwill be initialized and the linker will pull in only the desired cachelibrary. Below is an example of cacheXxxLib being linked in by sysLib.c.For systems without caches and for those architectures with only one cachedesign, there is no need for the `sysCacheLibInit' variable..CS FUNCPTR sysCacheLibInit = (FUNCPTR) cacheXxxLibInit;.CEFor cache systems with bus snooping, the flush and invalidate macrosshould be NULLified to enhance system and driver performance in sysHwInit()..CS void sysHwInit () { ... cacheLib.flushRtn = NULL; /@ no flush necessary @/ cacheLib.invalidateRtn = NULL; /@ no invalidate necessary @/ ... }.CEThere may be some drivers that require numerous cache calls, so many that they interfere with the code clarity. Additional checking can bedone at the initialization stage to determine if cacheDmaMalloc() returneda buffer in non-cacheable space. Remember that it will return acache-safe buffer by virtue of the function pointers. Ideally, these areNULL, since the MMU was used to mark the pages as non-cacheable. Themacros CACHE_Xxx_IS_WRITE_COHERENT and CACHE_Xxx_IS_READ_COHERENTcan be used to check the flush and invalidate function pointers,respectively.Write buffers are used to allow the processor to continue execution whilethe bus interface unit moves the data to the external device. In theory,the write buffer should be smart enough to flush itself when there is awrite to non-cacheable space or a read of an item that is in the buffer.In those cases where the hardware does not support this, the software mustflush the buffer manually. This often is accomplished by a read tonon-cacheable space or a NOP instruction that serializes the chip'spipelines and buffers. This is not really a caching issue; however, thecache library provides a CACHE_PIPE_FLUSH macro. External write buffersmay still need to be handled in a board-specific manner.INTERNAL The manipulation of the cache and/or cache registers should be done inthe most efficient way possible to maintain driver performance. Someof the code may have to be written in assembly language depending onthe cache design. Allowing different granularities for the cacheoperations helps reduce the overhead associated with the cachecoherency software. This may be applicable to all the cache calls,and will vary with each architecture. Examples are entry, line, set,page, segment, region, context. MMU support is needed to selectivelyenable and disable parts of the address space, and is typically doneon a "page" basis. Board-specific and some secondary cache operationsshould be part of the BSP. The inclusion of routines that assist indebugging (cache tag dumps) is desirable.The memory allocator must round addresses down to a cache lineboundary, and return a number of bytes that is a multiple of the cacheline size to prevent shared cache lines. Cache operations on addressranges must be rounded down and up to the appropriate boundaries(line, page, etc.). _CACHE_ALIGN_SIZE may be used to force alignmentwhen using memalign().The atomicity of the cache operations is preserved by lockinginterrupts and disabling caching. Interrupts should be locked outwhile the cache is disabled since interrupt handling and other taskswould be run with caching disabled until the preempted task isswitched back in, if it is ever switched back in. The cache must bedisabled while performing most of these operations. For example, thecache should not be loading new entries during an invalidate operationand lose critical data such as stack entries.cacheDmaMalloc() returns the memalign() return value, or NULL if thereis some procedure-specific error in cache<Xxx>DmaMalloc(). The flushand invalidate function pointers should be set as follows: NO DATA CACHE cacheDrv.flushRtn = NULL cacheDrv.invalidateRtn = NULL DATA CACHE DISABLED cacheDrv.flushRtn = NULL cacheDrv.invalidateRtn = NULL DATA CACHING INHIBITED cacheDrv.flushRtn = NULL cacheDrv.invalidateRtn = NULL BUS SNOOPING HARDWARE cacheDrv.flushRtn = NULL cacheDrv.invalidateRtn = NULL WRITE-THROUGH DATA CACHE cacheDrv.flushRtn = NULL cacheDrv.invalidate = cache<Xxx>Invalidate() COPYBACK DATA CACHE cacheDrv.flushRtn = cache<Xxx>Flush() cacheDrv.invalidate = cache<Xxx>Invalidate() RETURN NULL BUFFER POINTER cacheDrv.flushRtn = cache<Xxx>Flush() cacheDrv.invalidate = cache<Xxx>Invalidate()The setting of the flush function pointer may not be NULL if the system has write buffers that need to be flushed.INCLUDE FILES: cacheLib.hSEE ALSO: Architecture-specific cache-management libraries (cacheXxxLib), vmLib,.pG "I/O System"*/#include "cacheLib.h"#include "stdlib.h"#include "private/vmLibP.h"/* globals */FUNCPTR cacheDmaMallocRtn = NULL; /* malloc dma memory if MMU */FUNCPTR cacheDmaFreeRtn = NULL; /* free dma memory if MMU */CACHE_MODE cacheDataMode = CACHE_DISABLED; /* data cache mode */BOOL cacheDataEnabled = FALSE; /* data cache disabled */BOOL cacheMmuAvailable = FALSE; /* MMU support available *//* externals */IMPORT FUNCPTR sysCacheLibInit; /* Board-specific cache library *//**************************************************************************** cacheLibInit - initialize the cache library for a processor architecture** This routine initializes the function pointers for the appropriate cache * library. For architectures with more than one cache implementation, the* board support package must select the appropriate cache library with * `sysCacheLibInit'. Systems without cache coherency problems (i.e., bus * snooping) should NULLify the flush and invalidate function pointers in * the cacheLib structure to enhance driver and overall system performance.* This can be done in sysHwInit().* * RETURNS: OK, or ERROR if there is no cache library installed.*/STATUS cacheLibInit ( CACHE_MODE instMode, /* inst cache mode */ CACHE_MODE dataMode /* data cache mode */ ) {#if _ARCH_MULTIPLE_CACHELIB /* BSP selection of cache library */ return ((STATUS) (sysCacheLibInit == NULL) ? ERROR : (*sysCacheLibInit) (instMode, dataMode));#else /* Single cache library for arch */ return (cacheArchLibInit (instMode, dataMode));#endif /* _ARCH_MULTIPLE_CACHELIB */ }/**************************************************************************** cacheEnable - enable the specified cache** This routine invalidates the cache tags and enables the instruction or * data cache.** RETURNS: OK, or ERROR if the cache type is invalid or the cache control* is not supported.*/STATUS cacheEnable ( CACHE_TYPE cache /* cache to enable */ ) { return ((cacheLib.enableRtn == NULL) ? ERROR : (cacheLib.enableRtn) (cache)); }/**************************************************************************** cacheDisable - disable the specified cache** This routine flushes the cache and disables the instruction or data cache.** RETURNS: OK, or ERROR if the cache type is invalid or the cache control* is not supported.*/STATUS cacheDisable ( CACHE_TYPE cache /* cache to disable */ ) { return ((cacheLib.disableRtn == NULL) ? ERROR : (cacheLib.disableRtn) (cache)); }/**************************************************************************** cacheLock - lock all or part of a specified cache** This routine locks all (global) or some (local) entries in the specified * cache. Cache locking is useful in real-time systems. Not all caches can * perform locking.** RETURNS: OK, or ERROR if the cache type is invalid or the cache control* is not supported.*/STATUS cacheLock (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -