rmi_mips_exts.h revision 212758
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 2003-2009 RMI Corporation 31556Srgrimes * All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 3. Neither the name of RMI Corporation, nor the names of its contributors, 141556Srgrimes * may be used to endorse or promote products derived from this software 151556Srgrimes * without specific prior written permission. 161556Srgrimes * 171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271556Srgrimes * SUCH DAMAGE. 281556Srgrimes * 291556Srgrimes * RMI_BSD 301556Srgrimes * $FreeBSD: head/sys/mips/rmi/rmi_mips_exts.h 212758 2010-09-16 19:13:55Z jchandra $ 311556Srgrimes */ 321556Srgrimes#ifndef __MIPS_EXTS_H__ 331556Srgrimes#define __MIPS_EXTS_H__ 341556Srgrimes 351556Srgrimes#define CPU_BLOCKID_IFU 0 361556Srgrimes#define CPU_BLOCKID_ICU 1 371556Srgrimes#define CPU_BLOCKID_IEU 2 3820420Ssteve#define CPU_BLOCKID_LSU 3 391556Srgrimes#define CPU_BLOCKID_MMU 4 401556Srgrimes#define CPU_BLOCKID_PRF 5 411556Srgrimes 421556Srgrimes#define LSU_CERRLOG_REGID 9 431556Srgrimes 4436049Scharnier#if defined(__mips_n64) || defined(__mips_n32) 4536049Scharnierstatic __inline uint64_t 4636049Scharnierread_xlr_ctrl_register(int block, int reg) 4736049Scharnier{ 4850471Speter uint64_t res; 491556Srgrimes 501556Srgrimes __asm__ __volatile__( 511556Srgrimes ".set push\n\t" 521556Srgrimes ".set noreorder\n\t" 531556Srgrimes "move $9, %1\n\t" 541556Srgrimes ".word 0x71280018\n\t" /* mfcr $8, $9 */ 5531664Seivind "move %0, $8\n\t" 561556Srgrimes ".set pop\n" 571556Srgrimes : "=r" (res) : "r"((block << 8) | reg) 581556Srgrimes : "$8", "$9" 591556Srgrimes ); 601556Srgrimes return (res); 611556Srgrimes} 621556Srgrimes 6350544Smharostatic __inline void 641556Srgrimeswrite_xlr_ctrl_register(int block, int reg, uint64_t value) 651556Srgrimes{ 661556Srgrimes __asm__ __volatile__( 671556Srgrimes ".set push\n\t" 6850544Smharo ".set noreorder\n\t" 691556Srgrimes "move $8, %0\n" 701556Srgrimes "move $9, %1\n" 711556Srgrimes ".word 0x71280019\n" /* mtcr $8, $9 */ 721556Srgrimes ".set pop\n" 731556Srgrimes : 741556Srgrimes : "r" (value), "r" ((block << 8) | reg) 751556Srgrimes : "$8", "$9" 761556Srgrimes ); 771556Srgrimes} 781556Srgrimes 791556Srgrimes#else /* !(defined(__mips_n64) || defined(__mips_n32)) */ 801556Srgrimes 811556Srgrimesstatic __inline uint64_t 821556Srgrimesread_xlr_ctrl_register(int block, int reg) 831556Srgrimes{ 8436785Simp uint32_t high, low; 851556Srgrimes 8650544Smharo __asm__ __volatile__( 871556Srgrimes ".set push\n\t" 881556Srgrimes ".set noreorder\n\t" 8914154Swosch ".set mips64\n\t" 9014166Swosch "move $9, %2\n" 911556Srgrimes ".word 0x71280018\n" /* "mfcr $8, $9\n" */ 921556Srgrimes "dsra32 %0, $8, 0\n\t" 931556Srgrimes "sll %1, $8, 0\n\t" 9414166Swosch ".set pop" 951556Srgrimes : "=r" (high), "=r"(low) 9650544Smharo : "r" ((block << 8) | reg) 9750544Smharo : "$8", "$9"); 9850544Smharo 991556Srgrimes return ( (((uint64_t)high) << 32) | low); 1001556Srgrimes} 1011556Srgrimes 10214305Swoschstatic __inline void 1031556Srgrimeswrite_xlr_ctrl_register(int block, int reg, uint64_t value) 1041556Srgrimes{ 1051556Srgrimes uint32_t low, high; 1061556Srgrimes high = value >> 32; 1071556Srgrimes low = value & 0xffffffff; 1081556Srgrimes 1091556Srgrimes __asm__ __volatile__( 1101556Srgrimes ".set push\n\t" 1111556Srgrimes ".set noreorder\n\t" 1121556Srgrimes ".set mips64\n\t" 1131556Srgrimes "dsll32 $9, %0, 0\n\t" 1141556Srgrimes "dsll32 $8, %1, 0\n\t" 1151556Srgrimes "dsrl32 $8, $8, 0\n\t" 1161556Srgrimes "or $8, $9, $8\n\t" 1171556Srgrimes "move $9, %2\n\t" 1181556Srgrimes ".word 0x71280019\n\t" /* mtcr $8, $9 */ 11936785Simp ".set pop\n" 12036785Simp : /* No outputs */ 1211556Srgrimes : "r" (high), "r" (low), "r"((block << 8) | reg) 1221556Srgrimes : "$8", "$9"); 1231556Srgrimes} 12436383Ssteve#endif /* defined(__mips_n64) || defined(__mips_n32) */ 12536383Ssteve 12636383Ssteve/* 12736383Ssteve * 32 bit read write for c0 1281556Srgrimes */ 12911298Sbde#define read_c0_register32(reg, sel) \ 13011298Sbde({ \ 13111298Sbde uint32_t __rv; \ 13211298Sbde __asm__ __volatile__( \ 13311298Sbde ".set push\n\t" \ 13411298Sbde ".set mips32\n\t" \ 13511298Sbde "mfc0 %0, $%1, %2\n\t" \ 13611298Sbde ".set pop\n" \ 13711298Sbde : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 13811298Sbde __rv; \ 1391556Srgrimes }) 1401556Srgrimes 1411556Srgrimes#define write_c0_register32(reg, sel, value) \ 1421556Srgrimes __asm__ __volatile__( \ 1431556Srgrimes ".set push\n\t" \ 1441556Srgrimes ".set mips32\n\t" \ 1451556Srgrimes "mtc0 %0, $%1, %2\n\t" \ 1461556Srgrimes ".set pop\n" \ 1471556Srgrimes : : "r" (value), "i" (reg), "i" (sel) ); 1481556Srgrimes 1491556Srgrimes#define read_c2_register32(reg, sel) \ 1501556Srgrimes({ \ 1511556Srgrimes uint32_t __rv; \ 1521556Srgrimes __asm__ __volatile__( \ 1531556Srgrimes ".set push\n\t" \ 1541556Srgrimes ".set mips32\n\t" \ 1551556Srgrimes "mfc2 %0, $%1, %2\n\t" \ 15629933Swosch ".set pop\n" \ 1571556Srgrimes : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 1581556Srgrimes __rv; \ 1591556Srgrimes }) 1601556Srgrimes 1611556Srgrimes#define write_c2_register32(reg, sel, value) \ 1621556Srgrimes __asm__ __volatile__( \ 1631556Srgrimes ".set push\n\t" \ 1641556Srgrimes ".set mips32\n\t" \ 16514166Swosch "mtc2 %0, $%1, %2\n\t" \ 16614166Swosch ".set pop\n" \ 16714166Swosch : : "r" (value), "i" (reg), "i" (sel) ); 16814305Swosch 16914305Swosch#if defined(__mips_n64) || defined(__mips_n32) 17014166Swosch/* 17130106Swosch * On 64 bit compilation, the operations are simple 17230106Swosch */ 1731556Srgrimes#define read_c0_register64(reg, sel) \ 1741556Srgrimes({ \ 17530106Swosch uint64_t __rv; \ 1761556Srgrimes __asm__ __volatile__( \ 1771556Srgrimes ".set push\n\t" \ 1781556Srgrimes ".set mips64\n\t" \ 17930106Swosch "dmfc0 %0, $%1, %2\n\t" \ 1801556Srgrimes ".set pop\n" \ 1811556Srgrimes : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 18230106Swosch __rv; \ 1831556Srgrimes }) 1841556Srgrimes 1851556Srgrimes#define write_c0_register64(reg, sel, value) \ 18629933Swosch __asm__ __volatile__( \ 18729933Swosch ".set push\n\t" \ 18829933Swosch ".set mips64\n\t" \ 18930106Swosch "dmtc0 %0, $%1, %2\n\t" \ 19030106Swosch ".set pop\n" \ 1911556Srgrimes : : "r" (value), "i" (reg), "i" (sel) ); 19230106Swosch 1931556Srgrimes#define read_c2_register64(reg, sel) \ 1941556Srgrimes({ \ 19550544Smharo uint64_t __rv; \ 19650544Smharo __asm__ __volatile__( \ 19750544Smharo ".set push\n\t" \ 1981556Srgrimes ".set mips64\n\t" \ 19950544Smharo "dmfc2 %0, $%1, %2\n\t" \ 2001556Srgrimes ".set pop\n" \ 20131664Seivind : "=r" (__rv) : "i" (reg), "i" (sel) ); \ 20231664Seivind __rv; \ 20331664Seivind }) 20431664Seivind 20531664Seivind#define write_c2_register64(reg, sel, value) \ 20631664Seivind __asm__ __volatile__( \ 20731664Seivind ".set push\n\t" \ 20831664Seivind ".set mips64\n\t" \ 20931664Seivind "dmtc2 %0, $%1, %2\n\t" \ 21031664Seivind ".set pop\n" \ 21131664Seivind : : "r" (value), "i" (reg), "i" (sel) ); 21231664Seivind 21331664Seivind#else /* ! (defined(__mips_n64) || defined(__mips_n32)) */ 21431664Seivind 2151556Srgrimes/* 2161556Srgrimes * 32 bit compilation, 64 bit values has to split 2171556Srgrimes */ 2181556Srgrimes#define read_c0_register64(reg, sel) \ 2191556Srgrimes({ \ 2201556Srgrimes uint32_t __high, __low; \ 2211556Srgrimes __asm__ __volatile__( \ 2221556Srgrimes ".set push\n\t" \ 2231556Srgrimes ".set noreorder\n\t" \ 22462963Sdwmalone ".set mips64\n\t" \ 2251556Srgrimes "dmfc0 $8, $%2, %3\n\t" \ 2261556Srgrimes "dsra32 %0, $8, 0\n\t" \ 2271556Srgrimes "sll %1, $8, 0\n\t" \ 2281556Srgrimes ".set pop\n" \ 2291556Srgrimes : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ 2301556Srgrimes : "$8"); \ 2311556Srgrimes ((uint64_t)__high << 32) | __low; \ 2321556Srgrimes}) 2331556Srgrimes 2341556Srgrimes#define write_c0_register64(reg, sel, value) \ 2351556Srgrimesdo { \ 2361556Srgrimes uint32_t __high = value >> 32; \ 2371556Srgrimes uint32_t __low = value & 0xffffffff; \ 2381556Srgrimes __asm__ __volatile__( \ 2391556Srgrimes ".set push\n\t" \ 24023525Sguido ".set noreorder\n\t" \ 2411556Srgrimes ".set mips64\n\t" \ 2421556Srgrimes "dsll32 $8, %1, 0\n\t" \ 2431556Srgrimes "dsll32 $9, %0, 0\n\t" \ 2441556Srgrimes "dsrl32 $8, $8, 0\n\t" \ 2451556Srgrimes "or $8, $8, $9\n\t" \ 2461556Srgrimes "dmtc0 $8, $%2, %3\n\t" \ 24723525Sguido ".set pop" \ 24823525Sguido :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ 24923525Sguido :"$8", "$9"); \ 25023525Sguido} while(0) 25123525Sguido 25223525Sguido#define read_c2_register64(reg, sel) \ 25323525Sguido({ \ 25423525Sguido uint32_t __high, __low; \ 25523525Sguido __asm__ __volatile__( \ 25623525Sguido ".set push\n\t" \ 25723525Sguido ".set noreorder\n\t" \ 25823525Sguido ".set mips64\n\t" \ 25923525Sguido "dmfc2 $8, $%2, %3\n\t" \ 26023525Sguido "dsra32 %0, $8, 0\n\t" \ 2611556Srgrimes "sll %1, $8, 0\n\t" \ 2621556Srgrimes ".set pop\n" \ 2631556Srgrimes : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ 2641556Srgrimes : "$8"); \ 2651556Srgrimes ((uint64_t)__high << 32) | __low; \ 2661556Srgrimes}) 2671556Srgrimes 2681556Srgrimes#define write_c2_register64(reg, sel, value) \ 2691556Srgrimesdo { \ 2701556Srgrimes uint32_t __high = value >> 32; \ 2711556Srgrimes uint32_t __low = value & 0xffffffff; \ 2721556Srgrimes __asm__ __volatile__( \ 2731556Srgrimes ".set push\n\t" \ 2741556Srgrimes ".set noreorder\n\t" \ 2751556Srgrimes ".set mips64\n\t" \ 2761556Srgrimes "dsll32 $8, %1, 0\n\t" \ 2771556Srgrimes "dsll32 $9, %0, 0\n\t" \ 2781556Srgrimes "dsrl32 $8, $8, 0\n\t" \ 2791556Srgrimes "or $8, $8, $9\n\t" \ 28023525Sguido "dmtc2 $8, $%2, %3\n\t" \ 28123525Sguido ".set pop" \ 28237245Sbde :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ 28337245Sbde :"$8", "$9"); \ 28423525Sguido} while(0) 28523525Sguido 28623525Sguido#endif /* defined(__mips_n64) || defined(__mips_n32) */ 28723525Sguido 28823525Sguidostatic __inline int 28923525Sguidoxlr_cpu_id(void) 29023525Sguido{ 2911556Srgrimes 29223525Sguido return (read_c0_register32(15, 1) & 0x1f); 2931556Srgrimes} 2941556Srgrimes 2951556Srgrimesstatic __inline int 2961556Srgrimesxlr_core_id(void) 2971556Srgrimes{ 2981556Srgrimes 2991556Srgrimes return (xlr_cpu_id() / 4); 3001556Srgrimes} 3011556Srgrimes 3021556Srgrimesstatic __inline int 3031556Srgrimesxlr_thr_id(void) 3041556Srgrimes{ 3051556Srgrimes 3061556Srgrimes return (read_c0_register32(15, 1) & 0x3); 3071556Srgrimes} 3081556Srgrimes 30950544Smharo/* Additional registers on the XLR */ 31050544Smharo#define MIPS_COP_0_OSSCRATCH 22 3111556Srgrimes#define XLR_CACHELINE_SIZE 32 3121556Srgrimes#define XLR_MAX_CORES 8 3131556Srgrimes 3141556Srgrimes/* functions to write to and read from the extended 3151556Srgrimes * cp0 registers. 3161556Srgrimes * EIRR : Extended Interrupt Request Register 3171556Srgrimes * cp0 register 9 sel 6 3181556Srgrimes * bits 0...7 are same as cause register 8...15 3191556Srgrimes * EIMR : Extended Interrupt Mask Register 32040301Sdes * cp0 register 9 sel 7 32150544Smharo * bits 0...7 are same as status register 8...15 3221556Srgrimes */ 3231556Srgrimesstatic __inline uint64_t 3241556Srgrimesread_c0_eirr64(void) 3251556Srgrimes{ 3261556Srgrimes 3271556Srgrimes return (read_c0_register64(9, 6)); 3281556Srgrimes} 3291556Srgrimes 3301556Srgrimesstatic __inline void 3311556Srgrimeswrite_c0_eirr64(uint64_t val) 3321556Srgrimes{ 3331556Srgrimes 3341556Srgrimes write_c0_register64(9, 6, val); 3351556Srgrimes} 3361556Srgrimes 3371556Srgrimesstatic __inline uint64_t 3381556Srgrimesread_c0_eimr64(void) 3391556Srgrimes{ 3401556Srgrimes 3411556Srgrimes return (read_c0_register64(9, 7)); 3421556Srgrimes} 3431556Srgrimes 3441556Srgrimesstatic __inline void 3451556Srgrimeswrite_c0_eimr64(uint64_t val) 3461556Srgrimes{ 3471556Srgrimes 3481556Srgrimes write_c0_register64(9, 7, val); 3491556Srgrimes} 3501556Srgrimes 3511556Srgrimesstatic __inline int 3521556Srgrimesxlr_test_and_set(int *lock) 3531556Srgrimes{ 3541556Srgrimes int oldval = 0; 3551556Srgrimes 3561556Srgrimes __asm__ __volatile__( 3571556Srgrimes ".set push\n" 3581556Srgrimes ".set noreorder\n" 3591556Srgrimes "move $9, %2\n" 3601556Srgrimes "li $8, 1\n" 3611556Srgrimes // "swapw $8, $9\n" 36250544Smharo ".word 0x71280014\n" 36314305Swosch "move %1, $8\n" 36450544Smharo ".set pop\n" 36550544Smharo : "+m"(*lock), "=r"(oldval) 36650544Smharo : "r"((unsigned long)lock) 3671556Srgrimes : "$8", "$9" 368 ); 369 370 return (oldval == 0 ? 1 /* success */ : 0 /* failure */); 371} 372 373static __inline uint32_t 374xlr_mfcr(uint32_t reg) 375{ 376 uint32_t val; 377 378 __asm__ __volatile__( 379 "move $8, %1\n" 380 ".word 0x71090018\n" 381 "move %0, $9\n" 382 : "=r"(val) 383 : "r"(reg):"$8", "$9"); 384 385 return val; 386} 387 388static __inline void 389xlr_mtcr(uint32_t reg, uint32_t val) 390{ 391 __asm__ __volatile__( 392 "move $8, %1\n" 393 "move $9, %0\n" 394 ".word 0x71090019\n" 395 :: "r"(val), "r"(reg) 396 : "$8", "$9"); 397} 398 399/* 400 * Atomic increment a unsigned int 401 */ 402static __inline unsigned int 403xlr_ldaddwu(unsigned int value, unsigned int *addr) 404{ 405 __asm__ __volatile__( 406 ".set push\n" 407 ".set noreorder\n" 408 "move $8, %2\n" 409 "move $9, %3\n" 410 ".word 0x71280011\n" /* ldaddwu $8, $9 */ 411 "move %0, $8\n" 412 ".set pop\n" 413 : "=&r"(value), "+m"(*addr) 414 : "0"(value), "r" ((unsigned long)addr) 415 : "$8", "$9"); 416 417 return (value); 418} 419 420#if defined(__mips_n64) 421static __inline uint64_t 422xlr_paddr_ld(uint64_t paddr) 423{ 424 425 paddr |= 0x9800000000000000ULL; 426 return (*(uint64_t *)(uintptr_t)paddr); 427} 428 429#elif defined(__mips_n32) 430static __inline uint64_t 431xlr_paddr_ld(uint64_t paddr) 432{ 433 uint64_t val; 434 435 paddr |= 0x9800000000000000ULL; 436 __asm__ __volatile__( 437 ".set push \n\t" 438 ".set mips64 \n\t" 439 "ld %0, 0(%1) \n\t" 440 ".set pop \n" 441 : "=r"(val) 442 : "r"(paddr)); 443 444 return (val); 445} 446#else 447static __inline uint32_t 448xlr_paddr_ld(uint64_t paddr) 449{ 450 uint32_t addrh, addrl; 451 uint32_t valh, vall; 452 453 addrh = 0x98000000 | (paddr >> 32); 454 addrl = paddr & 0xffffffff; 455 456 __asm__ __volatile__( 457 ".set push \n\t" 458 ".set mips64 \n\t" 459 "dsll32 %2, %2, 0 \n\t" 460 "dsll32 %3, %3, 0 \n\t" /* get rid of the */ 461 "dsrl32 %3, %3, 0 \n\t" /* sign extend */ 462 "or %2, %2, %3 \n\t" 463 "lw %0, 0(%2) \n\t" 464 "lw %1, 4(%2) \n\t" 465 ".set pop \n" 466 : "=&r"(valh), "=r"(vall) 467 : "r"(addrh), "r"(addrl)); 468 469 return (((uint64_t)valh << 32) | vall); 470} 471#endif 472 473/* 474 * XXX: Not really needed in n32 or n64, retain for now 475 */ 476#if defined(__mips_n64) || defined(__mips_n32) 477static __inline uint32_t 478xlr_enable_kx(void) 479{ 480 481 return (0); 482} 483 484static __inline void 485xlr_restore_kx(uint32_t sr) 486{ 487} 488#else 489static __inline uint32_t 490xlr_enable_kx(void) 491{ 492 uint32_t sr = mips_rd_status(); 493 494 mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX); 495 return (sr); 496} 497 498static __inline void 499xlr_restore_kx(uint32_t sr) 500{ 501 502 mips_wr_status(sr); 503} 504#endif 505 506/* for cpuid to hardware thread id mapping */ 507extern uint32_t xlr_hw_thread_mask; 508extern int xlr_cpuid_to_hwtid[]; 509extern int xlr_hwtid_to_cpuid[]; 510 511#endif 512