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