📄 cachecw4011lib.c
字号:
/* silently ignore unsupported cache types */ if ((cache != DATA_CACHE) && (cache != INSTRUCTION_CACHE)) return (OK); cacheAttributesGet(cache, &cacheSize, &cacheLineMask, &cacheEnableSetMask); /* skip if no cache present */ if (cacheSize == 0) return (OK); /* line and end are the (inclusive) start and end cache line addresses */ line = ((ULONG) address) & cacheLineMask; end = (((ULONG) address) + bytes - 1) & cacheLineMask; /* determine the number of cache lines we need to (possibly) invalidate */ if ((bytes == ENTIRE_CACHE) || (bytes >= cacheSize) || ((line == end) && (bytes > CACHE_LINE_SIZE))) { /* Invalidate the entire cache */ line = 0; numLines = cacheSize / CACHE_LINE_SIZE; } else { numLines = (end >= line) ? (((end - line) / CACHE_LINE_SIZE) + 1) : (((cacheSize - (line - end)) / CACHE_LINE_SIZE) + 1); } /* * firstByte and lastByte are the (inclusive) endpoints of the memory * region which will have its cache lines flushed. firstByte is * rounded down to the lower cache line boundary, and lastByte is * rounded up to the upper cache line boundary. This allows the test * in the invalidate inner loop to avoid masking the lower bits of * each cache line tag. */ firstByte = (ULONG) address & ~(CACHE_LINE_SIZE - 1); lastByte = ((ULONG) address + bytes - 1) | (CACHE_LINE_SIZE - 1); /* the cache tags store physical addresses, so massage the range to match this. */ firstByte = K0_TO_PHYS (firstByte); lastByte = K0_TO_PHYS (lastByte); if (cache == INSTRUCTION_CACHE) { /* invalidate instruction cache set 0 (if present) */ if (cacheEnableSetMask & CCC_IE0) _cw4011Invalidate (CCC_IE0, cacheLineMask, line, numLines, firstByte, lastByte); /* invalidate instruction set 1 (if present) */ if (cacheEnableSetMask & CCC_IE1) _cw4011Invalidate (CCC_IE1, cacheLineMask, line, numLines, firstByte, lastByte); } else if (cache == DATA_CACHE) { /* invalidate data cache set 0 (if present) */ if (cacheEnableSetMask & CCC_DE0) _cw4011Invalidate (CCC_DE0, cacheLineMask, line, numLines, firstByte, lastByte); /* invalidate data set 1 (if present) */ if (cacheEnableSetMask & CCC_DE1) _cw4011Invalidate (CCC_DE1, cacheLineMask, line, numLines, firstByte, lastByte); } return (OK); }/**************************************************************************** cacheCW4011Flush - flush all or some entries in a cache** This routine flushes all or some of the entries in the specified cache.** RETURNS: OK. Unsupported requests are silently ignored.*/LOCAL STATUS cacheCW4011Flush ( CACHE_TYPE cache, /* Cache to Invalidate */ void * address, /* Virtual Address */ size_t bytes /* Number of Bytes to Invalidate */ ) { ULONG line; ULONG end; ULONG numLines; if (cache != DATA_CACHE) /* only data cache supports copyback */ return (OK); /* silently ignore regions which aren't cacheable or are empty */ if (IS_KSEG1(address) || (bytes == 0)) return (OK); if (dcacheSize == 0) /* skip if no cache present */ return (OK); /* line and end are the (inclusive) start and end cache line addresses */ line = ((ULONG) address) & dcacheLineMask; end = (((ULONG) address) + bytes - 1) & dcacheLineMask; /* determine the number of cache lines we need to (possibly) invalidate */ if ((bytes == ENTIRE_CACHE) || (bytes >= dcacheSize) || ((line == end) && (bytes > CACHE_LINE_SIZE))) { /* Invalidate the entire cache */ line = 0; numLines = dcacheSize / CACHE_LINE_SIZE; } else { numLines = (end >= line) ? (((end - line) / CACHE_LINE_SIZE) + 1) : (((dcacheSize - (line - end)) / CACHE_LINE_SIZE) + 1); } _cw4011Flush (dcacheEnableSetMask, dcacheLineMask, line, numLines); return (OK); }/**************************************************************************** cacheCW4011WriteBufferFlush - flush the write buffer** This routine forces a flush of the write buffer. Setting and then* using a volative variable is sufficient to generate assembly code* that will force a sequence point, and that will force the write back* buffer to flush.** RETURNS: OK** NOMANUAL*/LOCAL STATUS cacheCW4011WriteBufferFlush (void) { volatile STATUS x; /* The following is kludgy, but works... */ x = OK - 1; return (x + 1); }/**************************************************************************** cacheCW4011Malloc - allocate a cache-safe buffer, if possible** This routine will attempt to return a pointer to a section of memory* that will not experience any cache coherency problems.** INTERNAL* This function is complicated somewhat because the cache can operate in* copyback mode and we need to avoid problems from writebacks of adjacent* cached lines; we also need to remember the pointer returned by malloc so* that we can free it if required.** RETURNS: A pointer to the non-cached buffer, or NULL.*/LOCAL void * cacheCW4011Malloc ( size_t bytes ) { void * pBuffer; char * pDmaBuffer; int allocBytes; /* Round up the allocation size so that we can store a "back pointer" * to the allocated buffer, align the buffer on a cache line boundary * and pad the buffer to a cache line boundary. * sizeof(void *) for "back pointer" * CACHE_LINE_SIZE-1 for cache line alignment * CACHE_LINE_SIZE-1 for cache line padding */ allocBytes = sizeof (void *) + (CACHE_LINE_SIZE - 1) + bytes + (CACHE_LINE_SIZE - 1); if ((pBuffer = (void *)malloc (allocBytes)) == NULL) return (pBuffer); else { /* Flush any data that may be still sitting in the cache */ cacheCW4011Clear (DATA_CACHE, pBuffer, allocBytes); pDmaBuffer = (char *) pBuffer; /* allocate space for the back pointer */ pDmaBuffer += sizeof (void *); /* Now align to a cache line boundary */ pDmaBuffer = (char *) ROUND_UP (pDmaBuffer, CACHE_LINE_SIZE); /* Store "back pointer" in previous cache line using CACHED location */ *(((char **)pDmaBuffer)-1) = pBuffer; return ((void *)K0_TO_K1(pDmaBuffer)); } }/**************************************************************************** cacheCW4011Free - free the buffer acquired by cacheMalloc ()** This routine will attempt to return a pointer to a section of memory* that will not experience any cache coherency problems.** INTERNAL* This function is complicated somewhat because the cache operates in* copyback mode and we need to avoid problems from writebacks of adjacent* cached lines; we also need to remember the pointer returned by malloc so* that we can free it if required.** RETURNS: A pointer to the non-cached buffer, or NULL.*/LOCAL STATUS cacheCW4011Free ( void * pBuf ) { char *pCacheBuffer; pCacheBuffer = (char *)K1_TO_K0(pBuf); pCacheBuffer -= sizeof (void *); free (*(void **)pCacheBuffer); return (OK); }/**************************************************************************** cacheCW4011VirtToPhys - virtual-to-physical address translation** This routine may be attached to the CACHE_DRV structure virtToPhysRtn* function pointer by cacheCW4011Malloc(). This implies that the virtual* memory library is not installed, and that the "cache-safe" buffer has* been created through the use of the CW4011 K1 segment.** RETURNS: The physical address of the provided virtual address** NOMANUAL*/LOCAL void * cacheCW4011VirtToPhys ( void * address /* Virtual address */ ) { return ((void *) K1_TO_PHYS(address)); }/**************************************************************************** cacheCW4011PhysToVirt - physical-to-virtual address translation** This routine may be attached to the CACHE_DRV structure physToVirtRtn* function pointer by cacheCW4011Malloc(). This implies that the virtual* memory library is not installed, and that the "cache-safe" buffer has* been created through the use of the CW4011 K1 segment.** RETURNS: The virtual address of the provided physical address** NOMANUAL*/LOCAL void * cacheCW4011PhysToVirt ( void * address /* Physical address */ ) { return ((void *) PHYS_TO_K1(address)); }/**************************************************************************** cacheCW4011TextUpdate - invalidate updated text section** This routine invalidates the specified text section so that the* correct updated text is executed. Since writeback caching can* be enabled, a flush of the data cache is also required, in case* the newly-written instructions are still contained within a * dirty data cache line.** RETURNS: OK, or ERROR if an error occurs during processing.** NOMANUAL* */LOCAL STATUS cacheCW4011TextUpdate ( void * address, /* Physical address */ size_t bytes /* bytes to invalidate */ ) { STATUS status; if ((bytes != ENTIRE_CACHE) && ((address == NULL) || (bytes == 0) || IS_KSEG1(address))) return (OK); status = cacheCW4011Flush (DATA_CACHE, address, bytes); if (status != OK) return (status); return cacheCW4011Invalidate (INSTRUCTION_CACHE, address, bytes); }/**************************************************************************** cacheLineMaskGet - returns cache line mask based upon cache size.** This routine computes a bit mask which can be used to determine the * cache line address which corresponds to a memory address. A mask * value of "0" is returned if the cache size is not valid.* RETURNS: A cache line bitmask for the requested cache size.** NOMANUAL* */LOCAL ULONG cacheLineMaskGet ( ULONG cacheSize ) { switch (cacheSize) { case 1024: return (K0BASE | (0x1f << 5)); case 2048: return (K0BASE | (0x3f << 5)); case 4096: return (K0BASE | (0x7f << 5)); case 8192: return (K0BASE | (0xff << 5)); } return (0); /* unrecognized cache size */ }/**************************************************************************** cacheSizeDescGet - returns description bits for the requested cache size.** This routine compares the requested cache size with the sizes supported* by the CW4011, and returns the bitmask describing the cache size in the* lower bits of the return value. This mask must be appropriately shifted* by the caller before being loaded into the cache configuration register.** RETURNS: The two-bit configuration value for the requested cache size.** NOMANUAL* */LOCAL ULONG cacheSizeDescGet ( ULONG cacheSize ) { switch (cacheSize) { case 1024: return (CCC_SIZE_1K); case 2048: return (CCC_SIZE_2K); case 4096: return (CCC_SIZE_4K); case 8192: return (CCC_SIZE_8K); } return (0); /* unrecognized cache size */ }/**************************************************************************** cacheAttributesGet - returns (globally stored) cache attributes.** The globally stored cache attributes are returned to the caller via* data pointers, based upon the requested cache type.** RETURNS: N/A** NOMANUAL* */LOCAL void cacheAttributesGet ( CACHE_TYPE cache, ULONG *pCacheSize, ULONG *pCacheLineMask, ULONG *pCacheEnableSetMask ) { switch (cache) { case DATA_CACHE: *pCacheSize = dcacheSize; *pCacheLineMask = dcacheLineMask; *pCacheEnableSetMask = dcacheEnableSetMask; break; case INSTRUCTION_CACHE: *pCacheSize = icacheSize; *pCacheLineMask = icacheLineMask; *pCacheEnableSetMask = icacheEnableSetMask; break; default: *pCacheSize = 0; *pCacheLineMask = 0; *pCacheEnableSetMask = 0; break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -