diff options
Diffstat (limited to 'cvmx-tlb.c')
| -rw-r--r-- | cvmx-tlb.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/cvmx-tlb.c b/cvmx-tlb.c new file mode 100644 index 000000000000..08c5e28c7436 --- /dev/null +++ b/cvmx-tlb.c @@ -0,0 +1,470 @@ +/***********************license start*************** + * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + + * * Neither the name of Cavium Networks nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + + * This Software, including technical data, may be subject to U.S. export control + * laws, including the U.S. Export Administration Act and its associated + * regulations, and may be subject to export or import regulations in other + * countries. + + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO + * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR + * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM + * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, + * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF + * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. + ***********************license end**************************************/ + + + + +/** + * @file + * + * cvmx-tlb supplies per core TLB access functions for simple executive + * applications. + * + * <hr>$Revision: 41586 $<hr> + */ +#include "cvmx.h" +#include "cvmx-tlb.h" + +//#define DEBUG + +/** + * @INTERNAL + * Convert page mask to string + */ +static inline const char* __mask_to_str(uint64_t mask) +{ + /* Most OCTEON processor does not support 1K page sizes */ + uint64_t non_1k_mask = mask + CVMX_TLB_PAGEMASK_4K; + + switch (non_1k_mask) { + case CVMX_TLB_PAGEMASK_4K: return "4kb"; + case CVMX_TLB_PAGEMASK_16K: return "16kb"; + case CVMX_TLB_PAGEMASK_64K: return "64kb"; + case CVMX_TLB_PAGEMASK_256K: return "256kb"; + case CVMX_TLB_PAGEMASK_1M: return "1Mb"; + case CVMX_TLB_PAGEMASK_4M: return "4Mb"; + case CVMX_TLB_PAGEMASK_16M: return "16Mb"; + case CVMX_TLB_PAGEMASK_64M: return "64Mb"; + case CVMX_TLB_PAGEMASK_256M: return "256Mb"; + } + + return ""; +} + +/** + * @INTERNAL + * issue the tlb read instruction + */ +static inline void __tlb_read(void){ + CVMX_EHB; + CVMX_TLBR; + CVMX_EHB; +} + +/** + * @INTERNAL + * issue the tlb write instruction + */ +static inline void __tlb_write(void){ + + CVMX_EHB; + CVMX_TLBWI; + CVMX_EHB; +} + +/** + * @INTERNAL + * issue the tlb read instruction + */ +static inline int __tlb_probe(uint64_t hi){ + int index; + CVMX_EHB; + CVMX_MT_ENTRY_HIGH(hi); + CVMX_TLBP; + CVMX_EHB; + + CVMX_MF_TLB_INDEX(index); + + if (index < 0) index = -1; + + return index; +} + +/** + * @INTERNAL + * read a single tlb entry + * + * return 0: tlb entry is read + * -1: index is invalid + */ +static inline int __tlb_read_index(uint32_t tlbi){ + + if (tlbi >= cvmx_tlb_size_limit()) { + return -1; + } + + CVMX_MT_TLB_INDEX(tlbi); + __tlb_read(); + + return 0; +} + +/** + * @INTERNAL + * write a single tlb entry + * + * return 0: tlb entry is read + * -1: index is invalid + */ +static inline int __tlb_write_index(uint32_t tlbi, + uint64_t hi, uint64_t lo0, + uint64_t lo1, uint64_t pagemask) +{ + + if (tlbi >= cvmx_tlb_size_limit()) { + return -1; + } + +#ifdef DEBUG + cvmx_dprintf("cvmx-tlb-dbg: " + "write TLB %d: hi %lx, lo0 %lx, lo1 %lx, pagemask %lx \n", + tlbi, hi, lo0, lo1, pagemask); +#endif + + CVMX_MT_TLB_INDEX(tlbi); + CVMX_MT_ENTRY_HIGH(hi); + CVMX_MT_ENTRY_LO_0(lo0); + CVMX_MT_ENTRY_LO_1(lo1); + CVMX_MT_PAGEMASK(pagemask); + __tlb_write(); + + return 0; +} + +/** + * @INTERNAL + * Determine if a TLB entry is free to use + */ +static inline int __tlb_entry_is_free(uint32_t tlbi) { + int ret = 0; + uint64_t lo0 = 0, lo1 = 0; + + if (tlbi < cvmx_tlb_size_limit()) { + + __tlb_read_index(tlbi); + + /* Unused entries have neither even nor odd page mapped */ + CVMX_MF_ENTRY_LO_0(lo0); + CVMX_MF_ENTRY_LO_1(lo1); + + if ( !(lo0 & TLB_VALID) && !(lo1 & TLB_VALID)) { + ret = 1; + } + } + + return ret; +} + + +/** + * @INTERNAL + * dump a single tlb entry + */ +static inline void __tlb_dump_index(uint32_t tlbi) +{ + if (tlbi < cvmx_tlb_size_limit()) { + + if (__tlb_entry_is_free(tlbi)) { +#ifdef DEBUG + cvmx_dprintf("Index: %3d Free \n", tlbi); +#endif + } else { + uint64_t lo0, lo1, pgmask; + uint32_t hi, c0, c1; +#ifdef DEBUG + int width = 13; +#endif + + __tlb_read_index(tlbi); + + CVMX_MF_ENTRY_HIGH(hi); + CVMX_MF_ENTRY_LO_0(lo0); + CVMX_MF_ENTRY_LO_1(lo1); + CVMX_MF_PAGEMASK(pgmask); + + +#ifdef DEBUG + cvmx_dprintf("Index: %3d pgmask=%s ", tlbi, __mask_to_str(pgmask)); +#endif + + c0 = ( lo0 >> 3 ) & 7; + c1 = ( lo1 >> 3 ) & 7; + +#ifdef DEBUG + cvmx_dprintf("va=%0*lx asid=%02x\n", + width, (hi & ~0x1fffUL), hi & 0xff); + + cvmx_dprintf("\t[pa=%0*lx c=%d d=%d v=%d g=%d] ", + width, + (lo0 << 6) & PAGE_MASK, c0, + (lo0 & 4) ? 1 : 0, + (lo0 & 2) ? 1 : 0, + (lo0 & 1) ? 1 : 0); + cvmx_dprintf("[pa=%0*lx c=%d d=%d v=%d g=%d]\n", + width, + (lo1 << 6) & PAGE_MASK, c1, + (lo1 & 4) ? 1 : 0, + (lo1 & 2) ? 1 : 0, + (lo1 & 1) ? 1 : 0); + +#endif + } + } +} + +/** + * @INTERNAL + * dump a single tlb entry + */ +static inline uint32_t __tlb_wired_index() { + uint32_t tlbi; + + CVMX_MF_TLB_WIRED(tlbi); + return tlbi; +} + +/** + * Set up a wired entry. This function is designed to be used by Simple + * Executive to set up its virtual to physical address mapping at start up + * time. After the mapping is set up, the remaining unused TLB entries can + * be use for run time shared memory mapping. + * + * Calling this function causes the C0 wired index register to increase. + * Wired index register points to the separation between fixed TLB mapping + * and run time shared memory mapping. + * + * @param hi Entry Hi + * @param lo0 Entry Low0 + * @param lo1 Entry Low1 + * @param pagemask Pagemask + * + * @return 0: the entry is added + * @return -1: out of TLB entry + */ +int cvmx_tlb_add_wired_entry( uint64_t hi, uint64_t lo0, + uint64_t lo1, uint64_t pagemask) +{ + uint64_t index; + int ret = -1; + + index = __tlb_wired_index(); + + /* Check to make sure if the index is free to use */ + if (index < cvmx_tlb_size_limit() && __tlb_entry_is_free(index) ) { + /* increase the wired index by 1*/ + __tlb_write_index(index, hi, lo0, lo1, pagemask); + CVMX_MT_TLB_WIRED(index + 1); + ret = 0; + } + + return ret; +} + +/** + * Find a free entry that can be used for share memory mapping. + * + * @return -1: no free entry found + * @return : a free entry + */ +int cvmx_tlb_allocate_runtime_entry(void) +{ + uint32_t i, ret = -1; + + for (i = __tlb_wired_index(); i< cvmx_tlb_size_limit(); i++) { + + /* Check to make sure the index is free to use */ + if (__tlb_entry_is_free(i)) { + /* Found and return */ + ret = i; + break; + } + } + + return ret; +} + +/** + * Invalidate the TLB entry. Remove previous mapping if one was set up + */ +void cvmx_tlb_free_runtime_entry(uint32_t tlbi) +{ + /* Invalidate an unwired TLB entry */ + if ((tlbi < cvmx_tlb_size_limit()) && (tlbi >= __tlb_wired_index())) { + __tlb_write_index(tlbi, 0xffffffff80000000ULL, 0, 0, 0); + } +} + + +/** + * Program a single TLB entry to enable the provided vaddr to paddr mapping. + * + * @param index Index of the TLB entry + * @param vaddr The virtual address for this mapping + * @param paddr The physical address for this mapping + * @param size Size of the mapping + * @param tlb_flags Entry mapping flags + */ + +void cvmx_tlb_write_entry(int index, uint64_t vaddr, uint64_t paddr, + uint64_t size, uint64_t tlb_flags) { + uint64_t lo0, lo1, hi, pagemask; + + if ( __is_power_of_two(size) ) { + if ( (__log2(size) & 1 ) == 0) { + /* size is not power of 4, we only need to map + one page, figure out even or odd page to map */ + if ((vaddr >> __log2(size) & 1)) { + lo0 = 0; + lo1 = ((paddr >> 12) << 6) | tlb_flags; + hi = ((vaddr - size) >> 12) << 12; + }else { + lo0 = ((paddr >> 12) << 6) | tlb_flags; + lo1 = 0; + hi = ((vaddr) >> 12) << 12; + } + pagemask = (size - 1) & (~1<<11); + }else { + lo0 = ((paddr >> 12)<< 6) | tlb_flags; + lo1 = (((paddr + size /2) >> 12) << 6) | tlb_flags; + hi = ((vaddr) >> 12) << 12; + pagemask = ((size/2) -1) & (~1<<11); + } + + + __tlb_write_index(index, hi, lo0, lo1, pagemask); + + } +} + + +/** + * Program a single TLB entry to enable the provided vaddr to paddr mapping. + * This version adds a wired entry that should not be changed at run time + * + * @param vaddr The virtual address for this mapping + * @param paddr The physical address for this mapping + * @param size Size of the mapping + * @param tlb_flags Entry mapping flags + * @return -1: TLB out of entries + * 0: fixed entry added + */ +int cvmx_tlb_add_fixed_entry( uint64_t vaddr, uint64_t paddr, uint64_t size, uint64_t tlb_flags) { + + uint64_t index; + int ret = 0; + + CVMX_MF_TLB_WIRED(index); + + /* Check to make sure if the index is free to use */ + if (index < cvmx_tlb_size_limit() && __tlb_entry_is_free(index) ) { + cvmx_tlb_write_entry(index, vaddr, paddr, size, tlb_flags); + + if (!__tlb_entry_is_free(index)) { + /* Bump up the wired register*/ + CVMX_MT_TLB_WIRED(index + 1); + ret = 1; + } + } + return ret; +} + + +/** + * Program a single TLB entry to enable the provided vaddr to paddr mapping. + * This version writes a runtime entry. It will check the index to make sure + * not to overwrite any fixed entries. + * + * @param index Index of the TLB entry + * @param vaddr The virtual address for this mapping + * @param paddr The physical address for this mapping + * @param size Size of the mapping + * @param tlb_flags Entry mapping flags + */ +void cvmx_tlb_write_runtime_entry(int index, uint64_t vaddr, uint64_t paddr, + uint64_t size, uint64_t tlb_flags) +{ + + int wired_index; + CVMX_MF_TLB_WIRED(wired_index); + + if (index >= wired_index) { + cvmx_tlb_write_entry(index, vaddr, paddr, size, tlb_flags); + } + +} + + + +/** + * Find the TLB index of a given virtual address + * + * @param vaddr The virtual address to look up + * @return -1 not TLB mapped + * >=0 TLB TLB index + */ +int cvmx_tlb_lookup(uint64_t vaddr) { + uint64_t hi= (vaddr >> 12 ) << 12; /* We always use ASID 0 */ + + return __tlb_probe(hi); +} + +/** + * Debug routine to show all shared memory mapping + */ +void cvmx_tlb_dump_shared_mapping(void) { + uint32_t tlbi; + + for ( tlbi = __tlb_wired_index(); tlbi<cvmx_tlb_size_limit(); tlbi++ ) { + __tlb_dump_index(tlbi); + } +} + +/** + * Debug routine to show all TLB entries of this core + * + */ +void cvmx_tlb_dump_all(void) { + + uint32_t tlbi; + + for (tlbi = 0; tlbi<= cvmx_tlb_size_limit(); tlbi++ ) { + __tlb_dump_index(tlbi); + } +} + |
