rmi_mips_exts.h revision 213441
1/*- 2 * Copyright (c) 2003-2009 RMI Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of RMI Corporation, nor the names of its contributors, 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * RMI_BSD 30 * $FreeBSD: head/sys/mips/rmi/rmi_mips_exts.h 213441 2010-10-05 05:49:38Z jchandra $ 31 */ 32#ifndef __MIPS_EXTS_H__ 33#define __MIPS_EXTS_H__ 34 35#define CPU_BLOCKID_IFU 0 36#define CPU_BLOCKID_ICU 1 37#define CPU_BLOCKID_IEU 2 38#define CPU_BLOCKID_LSU 3 39#define CPU_BLOCKID_MMU 4 40#define CPU_BLOCKID_PRF 5 41 42#define LSU_CERRLOG_REGID 9 43 44#if defined(__mips_n64) || defined(__mips_n32) 45static __inline uint64_t 46read_xlr_ctrl_register(int block, int reg) 47{ 48 uint64_t res; 49 50 __asm__ __volatile__( 51 ".set push\n\t" 52 ".set noreorder\n\t" 53 "move $9, %1\n\t" 54 ".word 0x71280018\n\t" /* mfcr $8, $9 */ 55 "move %0, $8\n\t" 56 ".set pop\n" 57 : "=r" (res) : "r"((block << 8) | reg) 58 : "$8", "$9" 59 ); 60 return (res); 61} 62 63static __inline void 64write_xlr_ctrl_register(int block, int reg, uint64_t value) 65{ 66 __asm__ __volatile__( 67 ".set push\n\t" 68 ".set noreorder\n\t" 69 "move $8, %0\n" 70 "move $9, %1\n" 71 ".word 0x71280019\n" /* mtcr $8, $9 */ 72 ".set pop\n" 73 : 74 : "r" (value), "r" ((block << 8) | reg) 75 : "$8", "$9" 76 ); 77} 78 79#else /* !(defined(__mips_n64) || defined(__mips_n32)) */ 80 81static __inline uint64_t 82read_xlr_ctrl_register(int block, int reg) 83{ 84 uint32_t high, low; 85 86 __asm__ __volatile__( 87 ".set push\n\t" 88 ".set noreorder\n\t" 89 ".set mips64\n\t" 90 "move $9, %2\n" 91 ".word 0x71280018\n" /* "mfcr $8, $9\n" */ 92 "dsra32 %0, $8, 0\n\t" 93 "sll %1, $8, 0\n\t" 94 ".set pop" 95 : "=r" (high), "=r"(low) 96 : "r" ((block << 8) | reg) 97 : "$8", "$9"); 98 99 return ( (((uint64_t)high) << 32) | low); 100} 101 102static __inline void 103write_xlr_ctrl_register(int block, int reg, uint64_t value) 104{ 105 uint32_t low, high; 106 high = value >> 32; 107 low = value & 0xffffffff; 108 109 __asm__ __volatile__( 110 ".set push\n\t" 111 ".set noreorder\n\t" 112 ".set mips64\n\t" 113 "dsll32 $9, %0, 0\n\t" 114 "dsll32 $8, %1, 0\n\t" 115 "dsrl32 $8, $8, 0\n\t" 116 "or $8, $9, $8\n\t" 117 "move $9, %2\n\t" 118 ".word 0x71280019\n\t" /* mtcr $8, $9 */ 119 ".set pop\n" 120 : /* No outputs */ 121 : "r" (high), "r" (low), "r"((block << 8) | reg) 122 : "$8", "$9"); 123} 124#endif /* defined(__mips_n64) || defined(__mips_n32) */ 125 126/* 127 * 32 bit read write for c0 128 */ 129#define read_c0_register32(reg, sel) \ 130({ \ 131 uint32_t __rv; \ 132 __asm__ __volatile__( \ 133 ".set push\n\t" \ 134 ".set mips32\n\t" \ 135 "mfc0 %0, $%1, %2\n\t" \ 136 ".set pop\n" \ 137 : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 138 __rv; \ 139 }) 140 141#define write_c0_register32(reg, sel, value) \ 142 __asm__ __volatile__( \ 143 ".set push\n\t" \ 144 ".set mips32\n\t" \ 145 "mtc0 %0, $%1, %2\n\t" \ 146 ".set pop\n" \ 147 : : "r" (value), "i" (reg), "i" (sel) ); 148 149#define read_c2_register32(reg, sel) \ 150({ \ 151 uint32_t __rv; \ 152 __asm__ __volatile__( \ 153 ".set push\n\t" \ 154 ".set mips32\n\t" \ 155 "mfc2 %0, $%1, %2\n\t" \ 156 ".set pop\n" \ 157 : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 158 __rv; \ 159 }) 160 161#define write_c2_register32(reg, sel, value) \ 162 __asm__ __volatile__( \ 163 ".set push\n\t" \ 164 ".set mips32\n\t" \ 165 "mtc2 %0, $%1, %2\n\t" \ 166 ".set pop\n" \ 167 : : "r" (value), "i" (reg), "i" (sel) ); 168 169#if defined(__mips_n64) || defined(__mips_n32) 170/* 171 * On 64 bit compilation, the operations are simple 172 */ 173#define read_c0_register64(reg, sel) \ 174({ \ 175 uint64_t __rv; \ 176 __asm__ __volatile__( \ 177 ".set push\n\t" \ 178 ".set mips64\n\t" \ 179 "dmfc0 %0, $%1, %2\n\t" \ 180 ".set pop\n" \ 181 : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 182 __rv; \ 183 }) 184 185#define write_c0_register64(reg, sel, value) \ 186 __asm__ __volatile__( \ 187 ".set push\n\t" \ 188 ".set mips64\n\t" \ 189 "dmtc0 %0, $%1, %2\n\t" \ 190 ".set pop\n" \ 191 : : "r" (value), "i" (reg), "i" (sel) ); 192 193#define read_c2_register64(reg, sel) \ 194({ \ 195 uint64_t __rv; \ 196 __asm__ __volatile__( \ 197 ".set push\n\t" \ 198 ".set mips64\n\t" \ 199 "dmfc2 %0, $%1, %2\n\t" \ 200 ".set pop\n" \ 201 : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 202 __rv; \ 203 }) 204 205#define write_c2_register64(reg, sel, value) \ 206 __asm__ __volatile__( \ 207 ".set push\n\t" \ 208 ".set mips64\n\t" \ 209 "dmtc2 %0, $%1, %2\n\t" \ 210 ".set pop\n" \ 211 : : "r" (value), "i" (reg), "i" (sel) ); 212 213#else /* ! (defined(__mips_n64) || defined(__mips_n32)) */ 214 215/* 216 * 32 bit compilation, 64 bit values has to split 217 */ 218#define read_c0_register64(reg, sel) \ 219({ \ 220 uint32_t __high, __low; \ 221 __asm__ __volatile__( \ 222 ".set push\n\t" \ 223 ".set noreorder\n\t" \ 224 ".set mips64\n\t" \ 225 "dmfc0 $8, $%2, %3\n\t" \ 226 "dsra32 %0, $8, 0\n\t" \ 227 "sll %1, $8, 0\n\t" \ 228 ".set pop\n" \ 229 : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ 230 : "$8"); \ 231 ((uint64_t)__high << 32) | __low; \ 232}) 233 234#define write_c0_register64(reg, sel, value) \ 235do { \ 236 uint32_t __high = value >> 32; \ 237 uint32_t __low = value & 0xffffffff; \ 238 __asm__ __volatile__( \ 239 ".set push\n\t" \ 240 ".set noreorder\n\t" \ 241 ".set mips64\n\t" \ 242 "dsll32 $8, %1, 0\n\t" \ 243 "dsll32 $9, %0, 0\n\t" \ 244 "dsrl32 $8, $8, 0\n\t" \ 245 "or $8, $8, $9\n\t" \ 246 "dmtc0 $8, $%2, %3\n\t" \ 247 ".set pop" \ 248 :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ 249 :"$8", "$9"); \ 250} while(0) 251 252#define read_c2_register64(reg, sel) \ 253({ \ 254 uint32_t __high, __low; \ 255 __asm__ __volatile__( \ 256 ".set push\n\t" \ 257 ".set noreorder\n\t" \ 258 ".set mips64\n\t" \ 259 "dmfc2 $8, $%2, %3\n\t" \ 260 "dsra32 %0, $8, 0\n\t" \ 261 "sll %1, $8, 0\n\t" \ 262 ".set pop\n" \ 263 : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ 264 : "$8"); \ 265 ((uint64_t)__high << 32) | __low; \ 266}) 267 268#define write_c2_register64(reg, sel, value) \ 269do { \ 270 uint32_t __high = value >> 32; \ 271 uint32_t __low = value & 0xffffffff; \ 272 __asm__ __volatile__( \ 273 ".set push\n\t" \ 274 ".set noreorder\n\t" \ 275 ".set mips64\n\t" \ 276 "dsll32 $8, %1, 0\n\t" \ 277 "dsll32 $9, %0, 0\n\t" \ 278 "dsrl32 $8, $8, 0\n\t" \ 279 "or $8, $8, $9\n\t" \ 280 "dmtc2 $8, $%2, %3\n\t" \ 281 ".set pop" \ 282 :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ 283 :"$8", "$9"); \ 284} while(0) 285 286#endif /* defined(__mips_n64) || defined(__mips_n32) */ 287 288static __inline int 289xlr_cpu_id(void) 290{ 291 292 return (read_c0_register32(15, 1) & 0x1f); 293} 294 295static __inline int 296xlr_core_id(void) 297{ 298 299 return (xlr_cpu_id() / 4); 300} 301 302static __inline int 303xlr_thr_id(void) 304{ 305 306 return (read_c0_register32(15, 1) & 0x3); 307} 308 309/* Additional registers on the XLR */ 310#define MIPS_COP_0_OSSCRATCH 22 311#define XLR_CACHELINE_SIZE 32 312 313/* functions to write to and read from the extended 314 * cp0 registers. 315 * EIRR : Extended Interrupt Request Register 316 * cp0 register 9 sel 6 317 * bits 0...7 are same as cause register 8...15 318 * EIMR : Extended Interrupt Mask Register 319 * cp0 register 9 sel 7 320 * bits 0...7 are same as status register 8...15 321 */ 322static __inline uint64_t 323read_c0_eirr64(void) 324{ 325 326 return (read_c0_register64(9, 6)); 327} 328 329static __inline void 330write_c0_eirr64(uint64_t val) 331{ 332 333 write_c0_register64(9, 6, val); 334} 335 336static __inline uint64_t 337read_c0_eimr64(void) 338{ 339 340 return (read_c0_register64(9, 7)); 341} 342 343static __inline void 344write_c0_eimr64(uint64_t val) 345{ 346 347 write_c0_register64(9, 7, val); 348} 349 350static __inline int 351xlr_test_and_set(int *lock) 352{ 353 int oldval = 0; 354 355 __asm__ __volatile__( 356 ".set push\n" 357 ".set noreorder\n" 358 "move $9, %2\n" 359 "li $8, 1\n" 360 // "swapw $8, $9\n" 361 ".word 0x71280014\n" 362 "move %1, $8\n" 363 ".set pop\n" 364 : "+m"(*lock), "=r"(oldval) 365 : "r"((unsigned long)lock) 366 : "$8", "$9" 367 ); 368 369 return (oldval == 0 ? 1 /* success */ : 0 /* failure */); 370} 371 372static __inline uint32_t 373xlr_mfcr(uint32_t reg) 374{ 375 uint32_t val; 376 377 __asm__ __volatile__( 378 "move $8, %1\n" 379 ".word 0x71090018\n" 380 "move %0, $9\n" 381 : "=r"(val) 382 : "r"(reg):"$8", "$9"); 383 384 return val; 385} 386 387static __inline void 388xlr_mtcr(uint32_t reg, uint32_t val) 389{ 390 __asm__ __volatile__( 391 "move $8, %1\n" 392 "move $9, %0\n" 393 ".word 0x71090019\n" 394 :: "r"(val), "r"(reg) 395 : "$8", "$9"); 396} 397 398/* 399 * Atomic increment a unsigned int 400 */ 401static __inline unsigned int 402xlr_ldaddwu(unsigned int value, unsigned int *addr) 403{ 404 __asm__ __volatile__( 405 ".set push\n" 406 ".set noreorder\n" 407 "move $8, %2\n" 408 "move $9, %3\n" 409 ".word 0x71280011\n" /* ldaddwu $8, $9 */ 410 "move %0, $8\n" 411 ".set pop\n" 412 : "=&r"(value), "+m"(*addr) 413 : "0"(value), "r" ((unsigned long)addr) 414 : "$8", "$9"); 415 416 return (value); 417} 418 419#if defined(__mips_n64) 420static __inline uint32_t 421xlr_paddr_lw(uint64_t paddr) 422{ 423 424 paddr |= 0x9800000000000000ULL; 425 return (*(uint32_t *)(uintptr_t)paddr); 426} 427 428static __inline uint64_t 429xlr_paddr_ld(uint64_t paddr) 430{ 431 432 paddr |= 0x9800000000000000ULL; 433 return (*(uint64_t *)(uintptr_t)paddr); 434} 435 436#elif defined(__mips_n32) 437static __inline uint32_t 438xlr_paddr_lw(uint64_t paddr) 439{ 440 uint32_t val; 441 442 paddr |= 0x9800000000000000ULL; 443 __asm__ __volatile__( 444 ".set push \n\t" 445 ".set mips64 \n\t" 446 "lw %0, 0(%1) \n\t" 447 ".set pop \n" 448 : "=r"(val) 449 : "r"(paddr)); 450 451 return (val); 452} 453 454static __inline uint64_t 455xlr_paddr_ld(uint64_t paddr) 456{ 457 uint64_t val; 458 459 paddr |= 0x9800000000000000ULL; 460 __asm__ __volatile__( 461 ".set push \n\t" 462 ".set mips64 \n\t" 463 "ld %0, 0(%1) \n\t" 464 ".set pop \n" 465 : "=r"(val) 466 : "r"(paddr)); 467 468 return (val); 469} 470 471#else /* o32 compilation */ 472static __inline uint32_t 473xlr_paddr_lw(uint64_t paddr) 474{ 475 uint32_t addrh, addrl; 476 uint32_t val; 477 478 addrh = 0x98000000 | (paddr >> 32); 479 addrl = paddr & 0xffffffff; 480 481 __asm__ __volatile__( 482 ".set push \n\t" 483 ".set mips64 \n\t" 484 "dsll32 $8, %1, 0 \n\t" 485 "dsll32 $9, %2, 0 \n\t" /* get rid of the */ 486 "dsrl32 $9, $9, 0 \n\t" /* sign extend */ 487 "or $9, $8, $8 \n\t" 488 "lw %0, 0($9) \n\t" 489 ".set pop \n" 490 : "=r"(val) 491 : "r"(addrh), "r"(addrl) 492 : "$8", "$9"); 493 494 return (val); 495} 496 497static __inline uint64_t 498xlr_paddr_ld(uint64_t paddr) 499{ 500 uint32_t addrh, addrl; 501 uint32_t valh, vall; 502 503 addrh = 0x98000000 | (paddr >> 32); 504 addrl = paddr & 0xffffffff; 505 506 __asm__ __volatile__( 507 ".set push \n\t" 508 ".set mips64 \n\t" 509 "dsll32 %0, %2, 0 \n\t" 510 "dsll32 %1, %3, 0 \n\t" /* get rid of the */ 511 "dsrl32 %1, %1, 0 \n\t" /* sign extend */ 512 "or %0, %0, %1 \n\t" 513 "lw %1, 4(%0) \n\t" 514 "lw %0, 0(%0) \n\t" 515 ".set pop \n" 516 : "=&r"(valh), "=&r"(vall) 517 : "r"(addrh), "r"(addrl)); 518 519 return (((uint64_t)valh << 32) | vall); 520} 521#endif 522 523/* 524 * XXX: Not really needed in n32 or n64, retain for now 525 */ 526#if defined(__mips_n64) || defined(__mips_n32) 527static __inline uint32_t 528xlr_enable_kx(void) 529{ 530 531 return (0); 532} 533 534static __inline void 535xlr_restore_kx(uint32_t sr) 536{ 537} 538 539#else /* !defined(__mips_n64) && !defined(__mips_n32) */ 540/* 541 * o32 compilation, we will disable interrupts and enable 542 * the KX bit so that we can use XKPHYS to access any 40bit 543 * physical address 544 */ 545static __inline uint32_t 546xlr_enable_kx(void) 547{ 548 uint32_t sr = mips_rd_status(); 549 550 mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX); 551 return (sr); 552} 553 554static __inline void 555xlr_restore_kx(uint32_t sr) 556{ 557 558 mips_wr_status(sr); 559} 560#endif /* defined(__mips_n64) || defined(__mips_n32) */ 561 562/* 563 * XLR/XLS processors have maximum 8 cores, and maximum 4 threads 564 * per core 565 */ 566#define XLR_MAX_CORES 8 567#define XLR_NTHREADS 4 568 569/* 570 * FreeBSD can be started with few threads and cores turned off, 571 * so have a hardware thread id to FreeBSD cpuid mapping. 572 */ 573extern int xlr_ncores; 574extern int xlr_threads_per_core; 575extern uint32_t xlr_hw_thread_mask; 576extern int xlr_cpuid_to_hwtid[]; 577extern int xlr_hwtid_to_cpuid[]; 578 579#endif 580