Index: head/sys/mips/rmi/rmi_mips_exts.h =================================================================== --- head/sys/mips/rmi/rmi_mips_exts.h (revision 212365) +++ head/sys/mips/rmi/rmi_mips_exts.h (revision 212366) @@ -1,451 +1,455 @@ /*- * Copyright (c) 2003-2009 RMI Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of RMI Corporation, 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 IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * RMI_BSD * $FreeBSD$ */ #ifndef __MIPS_EXTS_H__ -#define __MIPS_EXTS_H__ +#define __MIPS_EXTS_H__ -#define CPU_BLOCKID_IFU 0 -#define CPU_BLOCKID_ICU 1 -#define CPU_BLOCKID_IEU 2 -#define CPU_BLOCKID_LSU 3 -#define CPU_BLOCKID_MMU 4 -#define CPU_BLOCKID_PRF 5 +#define CPU_BLOCKID_IFU 0 +#define CPU_BLOCKID_ICU 1 +#define CPU_BLOCKID_IEU 2 +#define CPU_BLOCKID_LSU 3 +#define CPU_BLOCKID_MMU 4 +#define CPU_BLOCKID_PRF 5 -#define LSU_CERRLOG_REGID 9 +#define LSU_CERRLOG_REGID 9 -static __inline__ unsigned int read_32bit_phnx_ctrl_reg(int block, int reg) +#if defined(__mips_n64) || defined(__mips_n32) +static __inline uint64_t +read_xlr_ctrl_register(int block, int reg) { - unsigned int __res; + uint64_t res; - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\tnoreorder\n\t" - "move $9, %1\n" - /* "mfcr\t$8, $9\n\t" */ - ".word 0x71280018\n" - "move %0, $8\n" - ".set\tpop" - : "=r" (__res) : "r"((block<<8)|reg) - : "$8", "$9" - ); - return __res; + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + "move $9, %1\n\t" + ".word 0x71280018\n\t" /* mfcr $8, $9 */ + "move %0, $8\n\t" + ".set pop\n" + : "=r" (res) : "r"((block << 8) | reg) + : "$8", "$9" + ); + return (res); } -static __inline__ void write_32bit_phnx_ctrl_reg(int block, int reg, unsigned int value) +static __inline void +write_xlr_ctrl_register(int block, int reg, uint64_t value) { - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\tnoreorder\n\t" - "move $8, %0\n" - "move $9, %1\n" - /* "mtcr\t$8, $9\n\t" */ - ".word 0x71280019\n" - ".set\tpop" - : - : "r" (value), "r"((block<<8)|reg) - : "$8", "$9" - ); + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + "move $8, %0\n" + "move $9, %1\n" + ".word 0x71280019\n" /* mtcr $8, $9 */ + ".set pop\n" + : + : "r" (value), "r" ((block << 8) | reg) + : "$8", "$9" + ); } -static __inline__ unsigned long long read_64bit_phnx_ctrl_reg(int block, int reg) +#else /* !(defined(__mips_n64) || defined(__mips_n32)) */ + +static __inline uint64_t +read_xlr_ctrl_register(int block, int reg) { - unsigned int high, low; - - __asm__ __volatile__( - ".set\tmips64\n\t" - "move $9, %2\n" - /* "mfcr $8, $9\n" */ - ".word 0x71280018\n" - "dsrl32 %0, $8, 0\n\t" - "dsll32 $8, $8, 0\n\t" - "dsrl32 %1, $8, 0\n\t" - ".set mips0" - : "=r" (high), "=r"(low) - : "r"((block<<8)|reg) - : "$8", "$9" - ); - - return ( (((unsigned long long)high)<<32) | low); + uint32_t high, low; + + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set mips64\n\t" + "move $9, %2\n" + ".word 0x71280018\n" /* "mfcr $8, $9\n" */ + "dsra32 %0, $8, 0\n\t" + "sll %1, $8, 0\n\t" + ".set pop" + : "=r" (high), "=r"(low) + : "r" ((block << 8) | reg) + : "$8", "$9"); + + return ( (((uint64_t)high) << 32) | low); } -static __inline__ void write_64bit_phnx_ctrl_reg(int block, int reg,unsigned long long value) +static __inline void +write_xlr_ctrl_register(int block, int reg, uint64_t value) { - __uint32_t low, high; + uint32_t low, high; high = value >> 32; low = value & 0xffffffff; __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set mips4\n\t" - /* Set up "rs" */ - "move $9, %0\n" + ".set push\n\t" + ".set noreorder\n\t" + ".set mips64\n\t" + "dsll32 $9, %0, 0\n\t" + "dsll32 $8, %1, 0\n\t" + "dsrl32 $8, $8, 0\n\t" + "or $8, $9, $8\n\t" + "move $9, %2\n\t" + ".word 0x71280019\n\t" /* mtcr $8, $9 */ + ".set pop\n" + : /* No outputs */ + : "r" (high), "r" (low), "r"((block << 8) | reg) + : "$8", "$9"); +} +#endif /* defined(__mips_n64) || defined(__mips_n32) */ - /* Store 64 bit value in "rt" */ - "dsll32 $10, %1, 0 \n\t" - "dsll32 $8, %2, 0 \n\t" - "dsrl32 $8, $8, 0 \n\t" - "or $10, $8, $8 \n\t" +/* + * 32 bit read write for c0 + */ +#define read_c0_register32(reg, sel) \ +({ \ + uint32_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mfc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) - ".word 0x71280019\n" /* mtcr $8, $9 */ +#define write_c0_register32(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mtc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); - ".set pop\n" +#define read_c2_register32(reg, sel) \ +({ \ + uint32_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mfc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) - : /* No outputs */ - : "r"((block<<8)|reg), "r" (high), "r" (low) - : "$8", "$9", "$10" - ); -} +#define write_c2_register32(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mtc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); -#define read_c0_register32(reg, sel) \ -({ unsigned int __rv; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mfc0\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : "=r" (__rv) : "i" (reg), "i" (sel) ); \ - __rv;}) +#if defined(__mips_n64) || defined(__mips_n32) +/* + * On 64 bit compilation, the operations are simple + */ +#define read_c0_register64(reg, sel) \ +({ \ + uint64_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmfc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) -#define write_c0_register32(reg, sel, value) \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mtc0\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : : "r" (value), "i" (reg), "i" (sel) ); +#define write_c0_register64(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmtc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); -#define read_c0_register64(reg, sel) \ - ({ unsigned int __high, __low; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips64\n\t" \ - "dmfc0\t $8, $%2, %3\n\t" \ - "dsrl32\t%0, $8, 0\n\t" \ - "dsll32\t$8, $8, 0\n\t" \ - "dsrl32\t%1, $8, 0\n\t" \ - ".set\tpop" \ - : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel): "$8" );\ - (((unsigned long long)__high << 32) | __low);}) +#define read_c2_register64(reg, sel) \ +({ \ + uint64_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmfc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) -#define write_c0_register64(reg, sel, value) \ - do{ \ - unsigned int __high = val>>32; \ - unsigned int __low = val & 0xffffffff; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips64\n\t" \ - "dsll32\t$8, %1, 0\n\t" \ - "dsll32\t$9, %0, 0\n\t" \ - "or\t $8, $8, $9\n\t" \ - "dmtc0\t $8, $%2, %3\n\t" \ - ".set\tpop" \ - :: "r"(high), "r"(low), "i"(reg), "i"(sel):"$8", "$9");\ - } while(0) +#define write_c2_register64(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmtc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); -#define read_c2_register32(reg, sel) \ -({ unsigned int __rv; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mfc2\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : "=r" (__rv) : "i" (reg), "i" (sel) ); \ - __rv;}) +#else /* ! (defined(__mips_n64) || defined(__mips_n32)) */ -#define write_c2_register32(reg, sel, value) \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mtc2\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : : "r" (value), "i" (reg), "i" (sel) ); +/* + * 32 bit compilation, 64 bit values has to split + */ +#define read_c0_register64(reg, sel) \ +({ \ + uint32_t __high, __low; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dmfc0 $8, $%2, %3\n\t" \ + "dsra32 %0, $8, 0\n\t" \ + "sll %1, $8, 0\n\t" \ + ".set pop\n" \ + : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ + : "$8"); \ + ((uint64_t)__high << 32) | __low; \ +}) -#define read_c2_register64(reg, sel) \ - ({ unsigned int __high, __low; \ - __asm__ __volatile__( \ - ".set mips64\n\t" \ - "dmfc2\t $8, $%2, %3\n\t" \ - "dsrl32\t%0, $8, 0\n\t" \ - "dsll32\t$8, $8, 0\n\t" \ - "dsrl32\t%1, $8, 0\n\t" \ - ".set\tmips0" \ - : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel): "$8" );\ - (((unsigned long long)__high << 32) | __low);}) +#define write_c0_register64(reg, sel, value) \ +do { \ + uint32_t __high = value >> 32; \ + uint32_t __low = value & 0xffffffff; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dsll32 $8, %1, 0\n\t" \ + "dsll32 $9, %0, 0\n\t" \ + "dsrl32 $8, $8, 0\n\t" \ + "or $8, $8, $9\n\t" \ + "dmtc0 $8, $%2, %3\n\t" \ + ".set pop" \ + :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ + :"$8", "$9"); \ +} while(0) -#define write_c2_register64(reg, sel, value) \ - do{ \ - unsigned int __high = value>>32; \ - unsigned int __low = value & 0xffffffff; \ - __asm__ __volatile__( \ - ".set mips64\n\t" \ - "dsll32\t$8, %1, 0\n\t" \ - "dsll32\t$9, %0, 0\n\t" \ - "dsrl32\t$8, $8, 0\n\t" \ - "or\t $8, $8, $9\n\t" \ - "dmtc2\t $8, $%2, %3\n\t" \ - ".set\tmips0" \ - :: "r"(__high), "r"(__low), \ - "i"(reg), "i"(sel) \ - :"$8", "$9"); \ - } while(0) +#define read_c2_register64(reg, sel) \ +({ \ + uint32_t __high, __low; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dmfc2 $8, $%2, %3\n\t" \ + "dsra32 %0, $8, 0\n\t" \ + "sll %1, $8, 0\n\t" \ + ".set pop\n" \ + : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ + : "$8"); \ + ((uint64_t)__high << 32) | __low; \ +}) -#define xlr_cpu_id() \ -({int __id; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - "mfc0 $8, $15, 1\n" \ - "andi %0, $8, 0x1f\n" \ - ".set pop\n" \ - : "=r" (__id) : : "$8"); \ - __id;}) +#define write_c2_register64(reg, sel, value) \ +do { \ + uint32_t __high = value >> 32; \ + uint32_t __low = value & 0xffffffff; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dsll32 $8, %1, 0\n\t" \ + "dsll32 $9, %0, 0\n\t" \ + "dsrl32 $8, $8, 0\n\t" \ + "or $8, $8, $9\n\t" \ + "dmtc2 $8, $%2, %3\n\t" \ + ".set pop" \ + :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ + :"$8", "$9"); \ +} while(0) -#define xlr_core_id() \ -({int __id; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - "mfc0 $8, $15, 1\n" \ - "andi %0, $8, 0x1f\n" \ - ".set pop\n" \ - : "=r" (__id) : : "$8"); \ - __id/4;}) +#endif /* defined(__mips_n64) || defined(__mips_n32) */ -#define xlr_thr_id() \ -({int __id; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - "mfc0 $8, $15, 1\n" \ - "andi %0, $8, 0x3\n" \ - ".set pop\n" \ - : "=r" (__id) : : "$8"); \ - __id;}) +static __inline int +xlr_cpu_id(void) +{ + return (read_c0_register32(15, 1) & 0x1f); +} -/* Additional registers on the XLR */ -#define MIPS_COP_0_OSSCRATCH 22 +static __inline int +xlr_core_id(void) +{ -#define XLR_CACHELINE_SIZE 32 + return (xlr_cpu_id() / 4); +} -#define XLR_MAX_CORES 8 +static __inline int +xlr_thr_id(void) +{ + return (read_c0_register32(15, 1) & 0x3); +} + +/* Additional registers on the XLR */ +#define MIPS_COP_0_OSSCRATCH 22 +#define XLR_CACHELINE_SIZE 32 +#define XLR_MAX_CORES 8 + /* functions to write to and read from the extended * cp0 registers. * EIRR : Extended Interrupt Request Register * cp0 register 9 sel 6 * bits 0...7 are same as cause register 8...15 * EIMR : Extended Interrupt Mask Register * cp0 register 9 sel 7 * bits 0...7 are same as status register 8...15 */ - -static inline uint64_t +static __inline uint64_t read_c0_eirr64(void) { - __uint32_t high, low; - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n" - - ".word 0x40214806 \n\t" - "nop \n\t" - "dsra32 %0, $1, 0 \n\t" - "sll %1, $1, 0 \n\t" - - ".set pop\n" - - : "=r"(high), "=r"(low) - ); - - return (((__uint64_t) high) << 32) | low; + return (read_c0_register64(9, 6)); } -static inline __uint64_t -read_c0_eimr64(void) +static __inline void +write_c0_eirr64(uint64_t val) { - __uint32_t high, low; - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n" - - ".word 0x40214807 \n\t" - "nop \n\t" - "dsra32 %0, $1, 0 \n\t" - "sll %1, $1, 0 \n\t" - - ".set pop\n" - - : "=r"(high), "=r"(low) - ); - - return (((__uint64_t) high) << 32) | low; + write_c0_register64(9, 6, val); } -static inline void -write_c0_eirr64(__uint64_t value) +static __inline uint64_t +read_c0_eimr64(void) { - __uint32_t low, high; - high = value >> 32; - low = value & 0xffffffff; - - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n\t" - - "dsll32 $2, %1, 0 \n\t" - "dsll32 $1, %0, 0 \n\t" - "dsrl32 $2, $2, 0 \n\t" - "or $1, $1, $2 \n\t" - ".word 0x40a14806 \n\t" - "nop \n\t" - - ".set pop\n" - - : - : "r"(high), "r"(low) - : "$1", "$2"); + return (read_c0_register64(9, 7)); } -static inline void -write_c0_eimr64(__uint64_t value) +static __inline void +write_c0_eimr64(uint64_t val) { - __uint32_t low, high; - high = value >> 32; - low = value & 0xffffffff; - - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n\t" - - "dsll32 $2, %1, 0 \n\t" - "dsll32 $1, %0, 0 \n\t" - "dsrl32 $2, $2, 0 \n\t" - "or $1, $1, $2 \n\t" - ".word 0x40a14807 \n\t" - "nop \n\t" - - ".set pop\n" - - : - : "r"(high), "r"(low) - : "$1", "$2"); + write_c0_register64(9, 7, val); } static __inline__ int xlr_test_and_set(int *lock) { int oldval = 0; - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - "move $9, %2\n" - "li $8, 1\n" + __asm__ __volatile__( + ".set push\n" + ".set noreorder\n" + "move $9, %2\n" + "li $8, 1\n" // "swapw $8, $9\n" - ".word 0x71280014\n" - "move %1, $8\n" - ".set pop\n" - : "+m"(*lock), "=r"(oldval) - : "r"((unsigned long)lock) - : "$8", "$9" + ".word 0x71280014\n" + "move %1, $8\n" + ".set pop\n" + : "+m"(*lock), "=r"(oldval) + : "r"((unsigned long)lock) + : "$8", "$9" ); return (oldval == 0 ? 1 /* success */ : 0 /* failure */ ); } static __inline__ uint32_t xlr_mfcr(uint32_t reg) { uint32_t val; __asm__ __volatile__( - "move $8, %1\n" - ".word 0x71090018\n" - "move %0, $9\n" - : "=r"(val) - : "r"(reg):"$8", "$9"); + "move $8, %1\n" + ".word 0x71090018\n" + "move %0, $9\n" + : "=r"(val) + : "r"(reg):"$8", "$9"); return val; } static __inline__ void xlr_mtcr(uint32_t reg, uint32_t val) { __asm__ __volatile__( - "move $8, %1\n" - "move $9, %0\n" - ".word 0x71090019\n" - :: "r"(val), "r"(reg) - : "$8", "$9"); + "move $8, %1\n" + "move $9, %0\n" + ".word 0x71090019\n" + :: "r"(val), "r"(reg) + : "$8", "$9"); } +#if defined(__mips_n64) static __inline__ uint32_t xlr_paddr_lw(uint64_t paddr) { - uint32_t high, low, tmp; + + paddr |= 0x9800000000000000ULL; + return (*(uint32_t *)(uintptr_t)paddr); +} - high = 0x98000000 | (paddr >> 32); - low = paddr & 0xffffffff; +#elif defined(__mips_n32) +static __inline__ uint32_t +xlr_paddr_lw(uint64_t paddr) +{ + uint32_t val; - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 %1, %1, 0 \n\t" - "dsll32 %2, %2, 0 \n\t" /* get rid of the */ - "dsrl32 %2, %2, 0 \n\t" /* sign extend */ - "or %1, %1, %2 \n\t" - "lw %0, 0(%1) \n\t" - ".set pop \n" - : "=r"(tmp) - : "r"(high), "r"(low)); + paddr |= 0x9800000000000000ULL; + __asm__ __volatile__( + ".set push \n\t" + ".set mips64 \n\t" + "lw %0, 0(%1) \n\t" + ".set pop \n" + : "=r"(val) + : "r"(paddr)); + return (val); +} +#else +static __inline__ uint32_t +xlr_paddr_lw(uint64_t paddr) +{ + uint32_t high, low, tmp; + + high = 0x98000000 | (paddr >> 32); + low = paddr & 0xffffffff; + + __asm__ __volatile__( + ".set push \n\t" + ".set mips64 \n\t" + "dsll32 %1, %1, 0 \n\t" + "dsll32 %2, %2, 0 \n\t" /* get rid of the */ + "dsrl32 %2, %2, 0 \n\t" /* sign extend */ + "or %1, %1, %2 \n\t" + "lw %0, 0(%1) \n\t" + ".set pop \n" + : "=r"(tmp) + : "r"(high), "r"(low)); + return tmp; } +#endif /* for cpuid to hardware thread id mapping */ extern uint32_t xlr_hw_thread_mask; extern int xlr_cpuid_to_hwtid[]; extern int xlr_hwtid_to_cpuid[]; #endif Index: head/sys/mips/rmi/xlr_machdep.c =================================================================== --- head/sys/mips/rmi/xlr_machdep.c (revision 212365) +++ head/sys/mips/rmi/xlr_machdep.c (revision 212366) @@ -1,628 +1,628 @@ /*- * Copyright (c) 2006-2009 RMI Corporation * Copyright (c) 2002-2004 Juli Mallett * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include /* cinit() */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void mpwait(void); unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE); /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; int rmi_spin_mutex_safe=0; struct mtx xlr_pic_lock; /* * Parameters from boot loader */ struct boot1_info xlr_boot1_info; int xlr_run_mode; int xlr_argc; int32_t *xlr_argv, *xlr_envp; uint64_t cpu_mask_info; uint32_t xlr_online_cpumask; uint32_t xlr_core_cpu_mask = 0x1; /* Core 0 thread 0 is always there */ int xlr_shtlb_enabled; int xlr_ncores; int xlr_threads_per_core; uint32_t xlr_hw_thread_mask; int xlr_cpuid_to_hwtid[MAXCPU]; int xlr_hwtid_to_cpuid[MAXCPU]; static void xlr_setup_mmu_split(void) { - int mmu_setup; + uint64_t mmu_setup; int val = 0; if (xlr_threads_per_core == 4 && xlr_shtlb_enabled == 0) return; /* no change from boot setup */ switch (xlr_threads_per_core) { case 1: val = 0; break; case 2: val = 2; break; case 4: val = 3; break; } - mmu_setup = read_32bit_phnx_ctrl_reg(4, 0); + mmu_setup = read_xlr_ctrl_register(4, 0); mmu_setup = mmu_setup & ~0x06; mmu_setup |= (val << 1); /* turn on global mode */ if (xlr_shtlb_enabled) mmu_setup |= 0x01; - write_32bit_phnx_ctrl_reg(4, 0, mmu_setup); + write_xlr_ctrl_register(4, 0, mmu_setup); } static void xlr_parse_mmu_options(void) { #ifdef notyet char *hw_env, *start, *end; #endif uint32_t cpu_map; uint8_t core0_thr_mask, core_thr_mask; int i, j, k; /* First check for the shared TLB setup */ xlr_shtlb_enabled = 0; #ifdef notyet /* * We don't support sharing TLB per core - TODO */ xlr_shtlb_enabled = 0; if ((hw_env = getenv("xlr.shtlb")) != NULL) { start = hw_env; tmp = strtoul(start, &end, 0); if (start != end) xlr_shtlb_enabled = (tmp != 0); else printf("Bad value for xlr.shtlb [%s]\n", hw_env); freeenv(hw_env); } #endif /* * XLR supports splitting the 64 TLB entries across one, two or four * threads (split mode). XLR also allows the 64 TLB entries to be shared * across all threads in the core using a global flag (shared TLB mode). * We will support 1/2/4 threads in split mode or shared mode. * */ xlr_ncores = 1; cpu_map = xlr_boot1_info.cpu_online_map; core0_thr_mask = cpu_map & 0xf; switch (core0_thr_mask) { case 1: xlr_threads_per_core = 1; break; case 3: xlr_threads_per_core = 2; break; case 0xf: xlr_threads_per_core = 4; break; default: goto unsupp; } /* Verify other cores CPU masks */ for (i = 1; i < XLR_MAX_CORES; i++) { core_thr_mask = (cpu_map >> (i*4)) & 0xf; if (core_thr_mask) { if (core_thr_mask != core0_thr_mask) goto unsupp; xlr_ncores++; } } /* setup hardware processor id to cpu id mapping */ xlr_hw_thread_mask = xlr_boot1_info.cpu_online_map; for (i = 0; i< MAXCPU; i++) xlr_cpuid_to_hwtid[i] = xlr_hwtid_to_cpuid [i] = -1; for (i = 0, k = 0; i < XLR_MAX_CORES; i++) { if (((cpu_map >> (i*4)) & 0xf) == 0) continue; for (j = 0; j < xlr_threads_per_core; j++) { xlr_cpuid_to_hwtid[k] = i*4 + j; xlr_hwtid_to_cpuid[i*4 + j] = k; k++; } } /* setup for the startup core */ xlr_setup_mmu_split(); return; unsupp: printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n" "\tcore0 thread mask [%lx], boot cpu mask [%lx]\n" "\tUsing default, 16 TLB entries per CPU, split mode\n", (u_long)core0_thr_mask, (u_long)cpu_map); panic("Invalid CPU mask - halting.\n"); return; } static void xlr_set_boot_flags(void) { char *p; p = getenv("bootflags"); if (p == NULL) p = getenv("boot_flags"); /* old style */ if (p == NULL) return; for (; p && *p != '\0'; p++) { switch (*p) { case 'd': case 'D': boothowto |= RB_KDB; break; case 'g': case 'G': boothowto |= RB_GDB; break; case 'v': case 'V': boothowto |= RB_VERBOSE; break; case 's': /* single-user (default, supported for sanity) */ case 'S': boothowto |= RB_SINGLE; break; default: printf("Unrecognized boot flag '%c'.\n", *p); break; } } freeenv(p); return; } extern uint32_t _end; static void mips_init(void) { init_param1(); init_param2(physmem); mips_cpu_init(); cpuinfo.cache_coherent_dma = TRUE; pmap_bootstrap(); #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { kdb_enter("Boot flags requested debugger", NULL); } #endif mips_proc0_init(); mutex_init(); } u_int platform_get_timecount(struct timecounter *tc __unused) { return (0xffffffffU - pic_timer_count32(PIC_CLOCK_TIMER)); } static void xlr_pic_init(void) { struct timecounter pic_timecounter = { platform_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0U, /* counter_mask */ PIC_TIMER_HZ, /* frequency */ "XLRPIC", /* name */ 2000, /* quality (adjusted in code) */ }; xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); int i, irq; write_c0_eimr64(0ULL); mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN); xlr_write_reg(mmio, PIC_CTRL, 0); /* Initialize all IRT entries */ for (i = 0; i < PIC_NUM_IRTS; i++) { irq = PIC_INTR_TO_IRQ(i); /* * Disable all IRTs. Set defaults (local scheduling, high * polarity, level * triggered, and CPU irq) */ xlr_write_reg(mmio, PIC_IRT_1(i), (1 << 30) | (1 << 6) | irq); /* Bind all PIC irqs to cpu 0 */ xlr_write_reg(mmio, PIC_IRT_0(i), 0x01); } /* Setup timer 7 of PIC as a timestamp, no interrupts */ pic_init_timer(PIC_CLOCK_TIMER); pic_set_timer(PIC_CLOCK_TIMER, ~UINT64_C(0)); platform_timecounter = &pic_timecounter; } static void xlr_mem_init(void) { struct xlr_boot1_mem_map *boot_map; vm_size_t physsz = 0; int i, j; /* get physical memory info from boot loader */ boot_map = (struct xlr_boot1_mem_map *) (unsigned long)xlr_boot1_info.psb_mem_map; for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) { if (boot_map->physmem_map[i].type == BOOT1_MEM_RAM) { if (j == 14) { printf("*** ERROR *** memory map too large ***\n"); break; } if (j == 0) { /* TODO FIXME */ /* start after kernel end */ phys_avail[0] = (vm_paddr_t) MIPS_KSEG0_TO_PHYS(&_end) + 0x20000; /* boot loader start */ /* HACK to Use bootloaders memory region */ /* TODO FIXME */ if (boot_map->physmem_map[0].size == 0x0c000000) { boot_map->physmem_map[0].size = 0x0ff00000; } phys_avail[1] = boot_map->physmem_map[0].addr + boot_map->physmem_map[0].size; printf("First segment: addr:%p -> %p \n", (void *)phys_avail[0], (void *)phys_avail[1]); } else { /* * Can't use this code yet, because most of the fixed allocations happen from * the biggest physical area. If we have more than 512M memory the kernel will try * to map from the second are which is not in KSEG0 and not mapped */ phys_avail[j] = (vm_paddr_t) boot_map->physmem_map[i].addr; phys_avail[j + 1] = phys_avail[j] + boot_map->physmem_map[i].size; if (phys_avail[j + 1] < phys_avail[j] ) { /* Houston we have an issue. Memory is * larger than possible. Its probably in * 64 bit > 4Gig and we are in 32 bit mode. */ phys_avail[j + 1] = 0xfffff000; printf("boot map size was %jx\n", (intmax_t)boot_map->physmem_map[i].size); boot_map->physmem_map[i].size = phys_avail[j + 1] - phys_avail[j]; printf("reduced to %jx\n", (intmax_t)boot_map->physmem_map[i].size); } printf("Next segment : addr:%p -> %p \n", (void *)phys_avail[j], (void *)phys_avail[j+1]); } physsz += boot_map->physmem_map[i].size; } } /* FIXME XLR TODO */ phys_avail[j] = phys_avail[j + 1] = 0; realmem = physmem = btoc(physsz); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { int i; #ifdef SMP uint32_t tmp; void (*wakeup) (void *, void *, unsigned int); #endif /* XXX FIXME the code below is not 64 bit clean */ /* Save boot loader and other stuff from scratch regs */ xlr_boot1_info = *(struct boot1_info *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 0); cpu_mask_info = read_c0_register64(MIPS_COP_0_OSSCRATCH, 1); xlr_online_cpumask = read_c0_register32(MIPS_COP_0_OSSCRATCH, 2); xlr_run_mode = read_c0_register32(MIPS_COP_0_OSSCRATCH, 3); xlr_argc = read_c0_register32(MIPS_COP_0_OSSCRATCH, 4); /* * argv and envp are passed in array of 32bit pointers */ xlr_argv = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 5); xlr_envp = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 6); /* TODO: Verify the magic number here */ /* FIXMELATER: xlr_boot1_info.magic_number */ /* Initialize pcpu stuff */ mips_pcpu0_init(); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ /* clockrate used by delay, so initialize it here */ cpu_clock = xlr_boot1_info.cpu_frequency / 1000000; /* * Note the time counter on CPU0 runs not at system clock speed, but * at PIC time counter speed (which is returned by * platform_get_frequency(). Thus we do not use * xlr_boot1_info.cpu_frequency here. */ mips_timer_early_init(xlr_boot1_info.cpu_frequency); /* Init console please */ cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("Environment (from %d args):\n", xlr_argc - 1); if (xlr_argc == 1) printf("\tNone\n"); for (i = 1; i < xlr_argc; i++) { char *n, *arg; arg = (char *)(intptr_t)xlr_argv[i]; printf("\t%s\n", arg); n = strsep(&arg, "="); if (arg == NULL) setenv(n, "1"); else setenv(n, arg); } xlr_set_boot_flags(); xlr_parse_mmu_options(); xlr_mem_init(); /* Set up hz, among others. */ mips_init(); #ifdef SMP /* * If thread 0 of any core is not available then mark whole core as * not available */ tmp = xlr_boot1_info.cpu_online_map; for (i = 4; i < MAXCPU; i += 4) { if ((tmp & (0xf << i)) && !(tmp & (0x1 << i))) { /* * Oops.. thread 0 is not available. Disable whole * core */ tmp = tmp & ~(0xf << i); printf("WARNING: Core %d is disabled because thread 0" " of this core is not enabled.\n", i / 4); } } xlr_boot1_info.cpu_online_map = tmp; /* Wakeup Other cpus, and put them in bsd park code. */ wakeup = ((void (*) (void *, void *, unsigned int)) (unsigned long)(xlr_boot1_info.wakeup)); printf("Waking up CPUs 0x%jx.\n", (intmax_t)xlr_boot1_info.cpu_online_map & ~(0x1U)); if (xlr_boot1_info.cpu_online_map & ~(0x1U)) wakeup(mpwait, 0, (unsigned int)xlr_boot1_info.cpu_online_map); #endif /* xlr specific post initialization */ /* initialize other on chip stuff */ xlr_board_info_setup(); xlr_msgring_config(); xlr_pic_init(); xlr_msgring_cpu_init(); mips_timer_init_params(xlr_boot1_info.cpu_frequency, 0); printf("Platform specific startup now completes\n"); } void platform_cpu_init() { } void platform_identify(void) { printf("Board [%d:%d], processor 0x%08x\n", (int)xlr_boot1_info.board_major_version, (int)xlr_boot1_info.board_minor_version, mips_rd_prid()); } /* * XXX Maybe return the state of the watchdog in enter, and pass it to * exit? Like spl(). */ void platform_trap_enter(void) { } void platform_reset(void) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); /* write 1 to GPIO software reset register */ xlr_write_reg(mmio, 8, 1); } void platform_trap_exit(void) { } #ifdef SMP int xlr_ap_release[MAXCPU]; int platform_start_ap(int cpuid) { int hwid = xlr_cpuid_to_hwtid[cpuid]; if (xlr_boot1_info.cpu_online_map & (1< __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #define pci_cfg_offset(bus,slot,devfn,where) (((bus)<<16) + ((slot) << 11)+((devfn)<<8)+(where)) #define PCIE_LINK_STATE 0x4000 #define LSU_CFG0_REGID 0 #define LSU_CERRLOG_REGID 9 #define LSU_CERROVF_REGID 10 #define LSU_CERRINT_REGID 11 /* MSI support */ #define MSI_MIPS_ADDR_DEST 0x000ff000 #define MSI_MIPS_ADDR_RH 0x00000008 #define MSI_MIPS_ADDR_RH_OFF 0x00000000 #define MSI_MIPS_ADDR_RH_ON 0x00000008 #define MSI_MIPS_ADDR_DM 0x00000004 #define MSI_MIPS_ADDR_DM_PHYSICAL 0x00000000 #define MSI_MIPS_ADDR_DM_LOGICAL 0x00000004 /* Fields in data for Intel MSI messages. */ #define MSI_MIPS_DATA_TRGRMOD 0x00008000 /* Trigger mode */ #define MSI_MIPS_DATA_TRGREDG 0x00000000 /* edge */ #define MSI_MIPS_DATA_TRGRLVL 0x00008000 /* level */ #define MSI_MIPS_DATA_LEVEL 0x00004000 /* Polarity. */ #define MSI_MIPS_DATA_DEASSERT 0x00000000 #define MSI_MIPS_DATA_ASSERT 0x00004000 #define MSI_MIPS_DATA_DELMOD 0x00000700 /* Delivery Mode */ #define MSI_MIPS_DATA_DELFIXED 0x00000000 /* fixed */ #define MSI_MIPS_DATA_DELLOPRI 0x00000100 /* lowest priority */ #define MSI_MIPS_DATA_INTVEC 0x000000ff /* * Build Intel MSI message and data values from a source. AMD64 systems * seem to be compatible, so we use the same function for both. */ #define MIPS_MSI_ADDR(cpu) \ (MSI_MIPS_ADDR_BASE | (cpu) << 12 | \ MSI_MIPS_ADDR_RH_OFF | MSI_MIPS_ADDR_DM_PHYSICAL) #define MIPS_MSI_DATA(irq) \ (MSI_MIPS_DATA_TRGRLVL | MSI_MIPS_DATA_DELFIXED | \ MSI_MIPS_DATA_ASSERT | (irq)) #define DEBUG #ifdef DEBUG #define dbg_devprintf device_printf #else #define dbg_devprintf(dev, fmt, ...) #endif struct xlr_pcib_softc { int junk; /* no softc */ }; static devclass_t pcib_devclass; static void *xlr_pci_config_base; static struct rman irq_rman, port_rman, mem_rman; static void xlr_pci_init_resources(void) { irq_rman.rm_start = 0; irq_rman.rm_end = 255; irq_rman.rm_type = RMAN_ARRAY; irq_rman.rm_descr = "PCI Mapped Interrupts"; if (rman_init(&irq_rman) || rman_manage_region(&irq_rman, 0, 255)) panic("pci_init_resources irq_rman"); port_rman.rm_start = 0; port_rman.rm_end = ~0u; port_rman.rm_type = RMAN_ARRAY; port_rman.rm_descr = "I/O ports"; if (rman_init(&port_rman) || rman_manage_region(&port_rman, 0x10000000, 0x1fffffff)) panic("pci_init_resources port_rman"); mem_rman.rm_start = 0; mem_rman.rm_end = ~0u; mem_rman.rm_type = RMAN_ARRAY; mem_rman.rm_descr = "I/O memory"; if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0xd0000000, 0xdfffffff)) panic("pci_init_resources mem_rman"); } static int xlr_pcib_probe(device_t dev) { if (xlr_board_info.is_xls) device_set_desc(dev, "XLS PCIe bus"); else device_set_desc(dev, "XLR PCI bus"); xlr_pci_init_resources(); xlr_pci_config_base = (void *)MIPS_PHYS_TO_KSEG1(DEFAULT_PCI_CONFIG_BASE); return (0); } static int xlr_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = 0; return (0); } return (ENOENT); } static int xlr_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { switch (which) { case PCIB_IVAR_DOMAIN: return (EINVAL); case PCIB_IVAR_BUS: return (EINVAL); } return (ENOENT); } static int xlr_pcib_maxslots(device_t dev) { return (PCI_SLOTMAX); } static __inline__ void disable_and_clear_cache_error(void) { uint64_t lsu_cfg0; - lsu_cfg0 = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID); + lsu_cfg0 = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID); lsu_cfg0 = lsu_cfg0 & ~0x2e; - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); /* Clear cache error log */ - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); } static __inline__ void clear_and_enable_cache_error(void) { uint64_t lsu_cfg0 = 0; /* first clear the cache error logging register */ - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERROVF_REGID, 0); - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRINT_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERROVF_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRINT_REGID, 0); - lsu_cfg0 = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID); + lsu_cfg0 = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID); lsu_cfg0 = lsu_cfg0 | 0x2e; - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); } static uint32_t pci_cfg_read_32bit(uint32_t addr) { uint32_t temp = 0; uint32_t *p = (uint32_t *)xlr_pci_config_base + addr / sizeof(uint32_t); uint64_t cerr_cpu_log = 0; disable_and_clear_cache_error(); temp = bswap32(*p); /* Read cache err log */ - cerr_cpu_log = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, + cerr_cpu_log = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID); if (cerr_cpu_log) { /* Device don't exist. */ temp = ~0x0; } clear_and_enable_cache_error(); return (temp); } static u_int32_t xlr_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) { uint32_t data = 0; if ((width == 2) && (reg & 1)) return 0xFFFFFFFF; else if ((width == 4) && (reg & 3)) return 0xFFFFFFFF; data = pci_cfg_read_32bit(pci_cfg_offset(b, s, f, reg)); if (width == 1) return ((data >> ((reg & 3) << 3)) & 0xff); else if (width == 2) return ((data >> ((reg & 3) << 3)) & 0xffff); else return (data); } static void xlr_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, u_int32_t val, int width) { uint32_t cfgaddr = pci_cfg_offset(b, s, f, reg); uint32_t data = 0, *p; if ((width == 2) && (reg & 1)) return; else if ((width == 4) && (reg & 3)) return; if (width == 1) { data = pci_cfg_read_32bit(cfgaddr); data = (data & ~(0xff << ((reg & 3) << 3))) | (val << ((reg & 3) << 3)); } else if (width == 2) { data = pci_cfg_read_32bit(cfgaddr); data = (data & ~(0xffff << ((reg & 3) << 3))) | (val << ((reg & 3) << 3)); } else { data = val; } p = (uint32_t *)xlr_pci_config_base + cfgaddr / sizeof(uint32_t); *p = bswap32(data); return; } static int xlr_pcib_attach(device_t dev) { device_add_child(dev, "pci", 0); bus_generic_attach(dev); return (0); } static void xlr_pcib_identify(driver_t * driver, device_t parent) { if (xlr_board_info.is_xls) { xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET); xlr_reg_t reg_link0 = xlr_read_reg(pcie_mmio_le, (0x80 >> 2)); xlr_reg_t reg_link1 = xlr_read_reg(pcie_mmio_le, (0x84 >> 2)); if ((uint16_t) reg_link0 & PCIE_LINK_STATE) { device_printf(parent, "Link 0 up\n"); } if ((uint16_t) reg_link1 & PCIE_LINK_STATE) { device_printf(parent, "Link 1 up\n"); } } BUS_ADD_CHILD(parent, 0, "pcib", 0); } /* * XLS PCIe can have upto 4 links, and each link has its on IRQ * Find the link on which the device is on */ static int xls_pcie_link(device_t pcib, device_t dev) { device_t parent, tmp; /* find the lane on which the slot is connected to */ printf("xls_pcie_link : bus %s dev %s\n", device_get_nameunit(pcib), device_get_nameunit(dev)); tmp = dev; while (1) { parent = device_get_parent(tmp); if (parent == NULL || parent == pcib) { device_printf(dev, "Cannot find parent bus\n"); return (-1); } if (strcmp(device_get_nameunit(parent), "pci0") == 0) break; tmp = parent; } return (pci_get_slot(tmp)); } /* * Find the IRQ for the link, each link has a different interrupt * at the XLS pic */ static int xls_pcie_link_irq(int link) { switch (link) { case 0: return (PIC_PCIE_LINK0_IRQ); case 1: return (PIC_PCIE_LINK1_IRQ); case 2: return (PIC_PCIE_LINK2_IRQ); case 3: return (PIC_PCIE_LINK3_IRQ); } return (-1); } static int xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { int i, link; /* * Each link has 32 MSIs that can be allocated, but for now * we only support one device per link. * msi_alloc() equivalent is needed when we start supporting * bridges on the PCIe link. */ link = xls_pcie_link(pcib, dev); if (link == -1) return (ENXIO); /* * encode the irq so that we know it is a MSI interrupt when we * setup interrupts */ for (i = 0; i < count; i++) irqs[i] = 64 + link * 32 + i; device_printf(dev, "Alloc MSI count %d maxcount %d irq %d link %d\n", count, maxcount, i, link); return (0); } static int xlr_release_msi(device_t pcib, device_t dev, int count, int *irqs) { device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib), count); return (0); } static int xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { int msi; device_printf(dev, "MAP MSI irq %d\n", irq); if (irq >= 64) { msi = irq - 64; *addr = MIPS_MSI_ADDR(0); *data = MIPS_MSI_DATA(msi); return (0); } else { device_printf(dev, "%s: map_msi for irq %d - ignored", device_get_nameunit(pcib), irq); return (ENXIO); } } static void bridge_pcix_ack(int irq) { xlr_read_reg(xlr_io_mmio(XLR_IO_PCIX_OFFSET), 0x140 >> 2); } static void bridge_pcie_ack(int irq) { uint32_t reg; xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET); switch (irq) { case PIC_PCIE_LINK0_IRQ: reg = PCIE_LINK0_MSI_STATUS; break; case PIC_PCIE_LINK1_IRQ: reg = PCIE_LINK1_MSI_STATUS; break; case PIC_PCIE_LINK2_IRQ: reg = PCIE_LINK2_MSI_STATUS; break; case PIC_PCIE_LINK3_IRQ: reg = PCIE_LINK3_MSI_STATUS; break; default: return; } xlr_write_reg(pcie_mmio_le, reg>>2, 0xffffffff); } static int mips_platform_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { int error = 0; int xlrirq; error = rman_activate_resource(irq); if (error) return error; if (rman_get_start(irq) != rman_get_end(irq)) { device_printf(dev, "Interrupt allocation %lu != %lu\n", rman_get_start(irq), rman_get_end(irq)); return (EINVAL); } xlrirq = rman_get_start(irq); device_printf(dev, "%s: setup intr %d\n", device_get_nameunit(child), xlrirq); if (strcmp(device_get_name(dev), "pcib") != 0) return (0); if (xlr_board_info.is_xls == 0) { xlr_establish_intr(device_get_name(child), filt, intr, arg, PIC_PCIX_IRQ, flags, cookiep, bridge_pcix_ack); pic_setup_intr(PIC_IRT_PCIX_INDEX, PIC_PCIX_IRQ, 0x1, 1); } else { /* * temporary hack for MSI, we support just one device per * link, and assign the link interrupt to the device interrupt */ if (xlrirq >= 64) { xlrirq -= 64; if (xlrirq % 32 != 0) return (0); xlrirq = xls_pcie_link_irq(xlrirq / 32); if (xlrirq == -1) return (EINVAL); } xlr_establish_intr(device_get_name(child), filt, intr, arg, xlrirq, flags, cookiep, bridge_pcie_ack); pic_setup_intr(xlrirq - PIC_IRQ_BASE, xlrirq, 0x1, 1); } return (bus_generic_setup_intr(dev, child, irq, flags, filt, intr, arg, cookiep)); } static int mips_platform_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { if (strcmp(device_get_name(child), "pci") == 0) { /* if needed reprogram the pic to clear pcix related entry */ device_printf(dev, "teardown intr\n"); } return (bus_generic_teardown_intr(dev, child, irq, cookie)); } static struct resource * xlr_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct rman *rm; struct resource *rv; vm_offset_t va; int needactivate = flags & RF_ACTIVE; device_printf(child, "Alloc res type %d, rid %d, start %lx, end %lx, count %lx flags %u\n", type, *rid, start, end, count, flags); switch (type) { case SYS_RES_IRQ: rm = &irq_rman; break; case SYS_RES_IOPORT: rm = &port_rman; break; case SYS_RES_MEMORY: rm = &mem_rman; break; default: return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == 0) return (0); rman_set_rid(rv, *rid); if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { va = (vm_offset_t)pmap_mapdev(start, count); rman_set_bushandle(rv, va); /* bushandle is same as virtual addr */ rman_set_virtual(rv, (void *)va); rman_set_bustag(rv, rmi_pci_bus_space); } if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int xlr_pci_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_release_resource(r)); } static int xlr_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_activate_resource(r)); } static int xlr_pci_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_deactivate_resource(r)); } static int mips_pci_route_interrupt(device_t bus, device_t dev, int pin) { int irq, link; /* * Validate requested pin number. */ device_printf(dev, "route intr pin %d (bus %d, slot %d)\n", pin, pci_get_bus(dev), pci_get_slot(dev)); if ((pin < 1) || (pin > 4)) return (255); if (xlr_board_info.is_xls) { link = xls_pcie_link(bus, dev); irq = xls_pcie_link_irq(link); if (irq != -1) return (irq); } else { if (pin == 1) return (PIC_PCIX_IRQ); } return (255); } static device_method_t xlr_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_identify, xlr_pcib_identify), DEVMETHOD(device_probe, xlr_pcib_probe), DEVMETHOD(device_attach, xlr_pcib_attach), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_read_ivar, xlr_pcib_read_ivar), DEVMETHOD(bus_write_ivar, xlr_pcib_write_ivar), DEVMETHOD(bus_alloc_resource, xlr_pci_alloc_resource), DEVMETHOD(bus_release_resource, xlr_pci_release_resource), DEVMETHOD(bus_activate_resource, xlr_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, xlr_pci_deactivate_resource), DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr), DEVMETHOD(bus_teardown_intr, mips_platform_pci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, xlr_pcib_maxslots), DEVMETHOD(pcib_read_config, xlr_pcib_read_config), DEVMETHOD(pcib_write_config, xlr_pcib_write_config), DEVMETHOD(pcib_route_interrupt, mips_pci_route_interrupt), DEVMETHOD(pcib_alloc_msi, xlr_alloc_msi), DEVMETHOD(pcib_release_msi, xlr_release_msi), DEVMETHOD(pcib_map_msi, xlr_map_msi), {0, 0} }; static driver_t xlr_pcib_driver = { "pcib", xlr_pcib_methods, sizeof(struct xlr_pcib_softc), }; DRIVER_MODULE(pcib, iodi, xlr_pcib_driver, pcib_devclass, 0, 0);