1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40 41 42 43/** 44 * @file 45 * 46 * cvmx-tlb supplies per core TLB access functions for simple executive 47 * applications. 48 * 49 * <hr>$Revision: 41586 $<hr> 50 */ 51#include "cvmx.h" 52#include "cvmx-tlb.h" 53#include "cvmx-core.h" 54#include <math.h> 55 56extern __uint32_t __log2(__uint32_t); 57//#define DEBUG 58 59/** 60 * @INTERNAL 61 * issue the tlb read instruction 62 */ 63static inline void __tlb_read(void){ 64 CVMX_EHB; 65 CVMX_TLBR; 66 CVMX_EHB; 67} 68 69/** 70 * @INTERNAL 71 * issue the tlb write instruction 72 */ 73static inline void __tlb_write(void){ 74 75 CVMX_EHB; 76 CVMX_TLBWI; 77 CVMX_EHB; 78} 79 80/** 81 * @INTERNAL 82 * issue the tlb read instruction 83 */ 84static inline int __tlb_probe(uint64_t hi){ 85 int index; 86 CVMX_EHB; 87 CVMX_MT_ENTRY_HIGH(hi); 88 CVMX_TLBP; 89 CVMX_EHB; 90 91 CVMX_MF_TLB_INDEX(index); 92 93 if (index < 0) index = -1; 94 95 return index; 96} 97 98/** 99 * @INTERNAL 100 * read a single tlb entry 101 * 102 * return 0: tlb entry is read 103 * -1: index is invalid 104 */ 105static inline int __tlb_read_index(uint32_t tlbi){ 106 107 if (tlbi >= (uint32_t)cvmx_core_get_tlb_entries()) { 108 return -1; 109 } 110 111 CVMX_MT_TLB_INDEX(tlbi); 112 __tlb_read(); 113 114 return 0; 115} 116 117/** 118 * @INTERNAL 119 * write a single tlb entry 120 * 121 * return 0: tlb entry is read 122 * -1: index is invalid 123 */ 124static inline int __tlb_write_index(uint32_t tlbi, 125 uint64_t hi, uint64_t lo0, 126 uint64_t lo1, uint64_t pagemask) 127{ 128 129 if (tlbi >= (uint32_t)cvmx_core_get_tlb_entries()) { 130 return -1; 131 } 132 133#ifdef DEBUG 134 cvmx_dprintf("cvmx-tlb-dbg: " 135 "write TLB %d: hi %lx, lo0 %lx, lo1 %lx, pagemask %lx \n", 136 tlbi, hi, lo0, lo1, pagemask); 137#endif 138 139 CVMX_MT_TLB_INDEX(tlbi); 140 CVMX_MT_ENTRY_HIGH(hi); 141 CVMX_MT_ENTRY_LO_0(lo0); 142 CVMX_MT_ENTRY_LO_1(lo1); 143 CVMX_MT_PAGEMASK(pagemask); 144 __tlb_write(); 145 146 return 0; 147} 148 149/** 150 * @INTERNAL 151 * Determine if a TLB entry is free to use 152 */ 153static inline int __tlb_entry_is_free(uint32_t tlbi) { 154 int ret = 0; 155 uint64_t lo0 = 0, lo1 = 0; 156 157 if (tlbi < (uint32_t)cvmx_core_get_tlb_entries()) { 158 159 __tlb_read_index(tlbi); 160 161 /* Unused entries have neither even nor odd page mapped */ 162 CVMX_MF_ENTRY_LO_0(lo0); 163 CVMX_MF_ENTRY_LO_1(lo1); 164 165 if ( !(lo0 & TLB_VALID) && !(lo1 & TLB_VALID)) { 166 ret = 1; 167 } 168 } 169 170 return ret; 171} 172 173 174/** 175 * @INTERNAL 176 * dump a single tlb entry 177 */ 178static inline void __tlb_dump_index(uint32_t tlbi) 179{ 180 if (tlbi < (uint32_t)cvmx_core_get_tlb_entries()) { 181 182 if (__tlb_entry_is_free(tlbi)) { 183#ifdef DEBUG 184 cvmx_dprintf("Index: %3d Free \n", tlbi); 185#endif 186 } else { 187 uint64_t lo0, lo1, pgmask; 188 uint32_t hi; 189#ifdef DEBUG 190 uint32_t c0, c1; 191 int width = 13; 192#endif 193 194 __tlb_read_index(tlbi); 195 196 CVMX_MF_ENTRY_HIGH(hi); 197 CVMX_MF_ENTRY_LO_0(lo0); 198 CVMX_MF_ENTRY_LO_1(lo1); 199 CVMX_MF_PAGEMASK(pgmask); 200 201#ifdef DEBUG 202 c0 = ( lo0 >> 3 ) & 7; 203 c1 = ( lo1 >> 3 ) & 7; 204 205 cvmx_dprintf("va=%0*lx asid=%02x\n", 206 width, (hi & ~0x1fffUL), hi & 0xff); 207 208 cvmx_dprintf("\t[pa=%0*lx c=%d d=%d v=%d g=%d] ", 209 width, 210 (lo0 << 6) & PAGE_MASK, c0, 211 (lo0 & 4) ? 1 : 0, 212 (lo0 & 2) ? 1 : 0, 213 (lo0 & 1) ? 1 : 0); 214 cvmx_dprintf("[pa=%0*lx c=%d d=%d v=%d g=%d]\n", 215 width, 216 (lo1 << 6) & PAGE_MASK, c1, 217 (lo1 & 4) ? 1 : 0, 218 (lo1 & 2) ? 1 : 0, 219 (lo1 & 1) ? 1 : 0); 220 221#endif 222 } 223 } 224} 225 226/** 227 * @INTERNAL 228 * dump a single tlb entry 229 */ 230static inline uint32_t __tlb_wired_index() { 231 uint32_t tlbi; 232 233 CVMX_MF_TLB_WIRED(tlbi); 234 return tlbi; 235} 236 237/** 238 * Find a free entry that can be used for share memory mapping. 239 * 240 * @return -1: no free entry found 241 * @return : a free entry 242 */ 243int cvmx_tlb_allocate_runtime_entry(void) 244{ 245 uint32_t i, ret = -1; 246 247 for (i = __tlb_wired_index(); i< (uint32_t)cvmx_core_get_tlb_entries(); i++) { 248 249 /* Check to make sure the index is free to use */ 250 if (__tlb_entry_is_free(i)) { 251 /* Found and return */ 252 ret = i; 253 break; 254 } 255 } 256 257 return ret; 258} 259 260/** 261 * Invalidate the TLB entry. Remove previous mapping if one was set up 262 */ 263void cvmx_tlb_free_runtime_entry(uint32_t tlbi) 264{ 265 /* Invalidate an unwired TLB entry */ 266 if ((tlbi < (uint32_t)cvmx_core_get_tlb_entries()) && (tlbi >= __tlb_wired_index())) { 267 __tlb_write_index(tlbi, 0xffffffff80000000ULL, 0, 0, 0); 268 } 269} 270 271 272/** 273 * Program a single TLB entry to enable the provided vaddr to paddr mapping. 274 * 275 * @param index Index of the TLB entry 276 * @param vaddr The virtual address for this mapping 277 * @param paddr The physical address for this mapping 278 * @param size Size of the mapping 279 * @param tlb_flags Entry mapping flags 280 */ 281 282void cvmx_tlb_write_entry(int index, uint64_t vaddr, uint64_t paddr, 283 uint64_t size, uint64_t tlb_flags) { 284 uint64_t lo0, lo1, hi, pagemask; 285 286 if ( __is_power_of_two(size) ) { 287 if ( (__log2(size) & 1 ) == 0) { 288 /* size is not power of 4, we only need to map 289 one page, figure out even or odd page to map */ 290 if ((vaddr >> __log2(size) & 1)) { 291 lo0 = 0; 292 lo1 = ((paddr >> 12) << 6) | tlb_flags; 293 hi = ((vaddr - size) >> 12) << 12; 294 }else { 295 lo0 = ((paddr >> 12) << 6) | tlb_flags; 296 lo1 = 0; 297 hi = ((vaddr) >> 12) << 12; 298 } 299 pagemask = (size - 1) & (~1<<11); 300 }else { 301 lo0 = ((paddr >> 12)<< 6) | tlb_flags; 302 lo1 = (((paddr + size /2) >> 12) << 6) | tlb_flags; 303 hi = ((vaddr) >> 12) << 12; 304 pagemask = ((size/2) -1) & (~1<<11); 305 } 306 307 308 __tlb_write_index(index, hi, lo0, lo1, pagemask); 309 310 } 311} 312 313 314/** 315 * Program a single TLB entry to enable the provided vaddr to paddr mapping. 316 * This version adds a wired entry that should not be changed at run time 317 * 318 * @param vaddr The virtual address for this mapping 319 * @param paddr The physical address for this mapping 320 * @param size Size of the mapping 321 * @param tlb_flags Entry mapping flags 322 * @return -1: TLB out of entries 323 * 0: fixed entry added 324 */ 325int cvmx_tlb_add_fixed_entry( uint64_t vaddr, uint64_t paddr, uint64_t size, uint64_t tlb_flags) { 326 327 uint64_t index; 328 int ret = 0; 329 330 CVMX_MF_TLB_WIRED(index); 331 332 /* Check to make sure if the index is free to use */ 333 if (index < (uint32_t)cvmx_core_get_tlb_entries() && __tlb_entry_is_free(index) ) { 334 cvmx_tlb_write_entry(index, vaddr, paddr, size, tlb_flags); 335 336 if (!__tlb_entry_is_free(index)) { 337 /* Bump up the wired register*/ 338 CVMX_MT_TLB_WIRED(index + 1); 339 ret = 1; 340 } 341 } 342 return ret; 343} 344 345 346/** 347 * Program a single TLB entry to enable the provided vaddr to paddr mapping. 348 * This version writes a runtime entry. It will check the index to make sure 349 * not to overwrite any fixed entries. 350 * 351 * @param index Index of the TLB entry 352 * @param vaddr The virtual address for this mapping 353 * @param paddr The physical address for this mapping 354 * @param size Size of the mapping 355 * @param tlb_flags Entry mapping flags 356 */ 357void cvmx_tlb_write_runtime_entry(int index, uint64_t vaddr, uint64_t paddr, 358 uint64_t size, uint64_t tlb_flags) 359{ 360 361 int wired_index; 362 CVMX_MF_TLB_WIRED(wired_index); 363 364 if (index >= wired_index) { 365 cvmx_tlb_write_entry(index, vaddr, paddr, size, tlb_flags); 366 } 367 368} 369 370 371 372/** 373 * Find the TLB index of a given virtual address 374 * 375 * @param vaddr The virtual address to look up 376 * @return -1 not TLB mapped 377 * >=0 TLB TLB index 378 */ 379int cvmx_tlb_lookup(uint64_t vaddr) { 380 uint64_t hi= (vaddr >> 13 ) << 13; /* We always use ASID 0 */ 381 382 return __tlb_probe(hi); 383} 384 385/** 386 * Debug routine to show all shared memory mapping 387 */ 388void cvmx_tlb_dump_shared_mapping(void) { 389 uint32_t tlbi; 390 391 for ( tlbi = __tlb_wired_index(); tlbi<(uint32_t)cvmx_core_get_tlb_entries(); tlbi++ ) { 392 __tlb_dump_index(tlbi); 393 } 394} 395 396/** 397 * Debug routine to show all TLB entries of this core 398 * 399 */ 400void cvmx_tlb_dump_all(void) { 401 402 uint32_t tlbi; 403 404 for (tlbi = 0; tlbi<= (uint32_t)cvmx_core_get_tlb_entries(); tlbi++ ) { 405 __tlb_dump_index(tlbi); 406 } 407} 408 409