system.h 5.26 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *  linux/include/asm-arm/proc-armv/system.h
 *
 *  Copyright (C) 1996 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H

#include <linux/config.h>

#define set_cr(x)					\
	__asm__ __volatile__(				\
17
	"mcr	p15, 0, %0, c1, c0, 0	@ set CR"	\
18
	: : "r" (x) : "cc")
Linus Torvalds's avatar
Linus Torvalds committed
19

20 21 22
#define get_cr()					\
	({						\
	unsigned int __val;				\
23 24
	__asm__ __volatile__(				\
	"mrc	p15, 0, %0, c1, c0, 0	@ get CR"	\
25 26 27
	: "=r" (__val) : : "cc");			\
	__val;						\
	})
28

Linus Torvalds's avatar
Linus Torvalds committed
29 30 31 32 33 34 35
#define CR_M	(1 << 0)	/* MMU enable				*/
#define CR_A	(1 << 1)	/* Alignment abort enable		*/
#define CR_C	(1 << 2)	/* Dcache enable			*/
#define CR_W	(1 << 3)	/* Write buffer enable			*/
#define CR_P	(1 << 4)	/* 32-bit exception handler		*/
#define CR_D	(1 << 5)	/* 32-bit data address range		*/
#define CR_L	(1 << 6)	/* Implementation defined		*/
36
#define CR_B	(1 << 7)	/* Big endian				*/
Linus Torvalds's avatar
Linus Torvalds committed
37
#define CR_S	(1 << 8)	/* System MMU protection		*/
38
#define CR_R	(1 << 9)	/* ROM MMU protection			*/
Linus Torvalds's avatar
Linus Torvalds committed
39 40 41 42 43
#define CR_F	(1 << 10)	/* Implementation defined		*/
#define CR_Z	(1 << 11)	/* Implementation defined		*/
#define CR_I	(1 << 12)	/* Icache enable			*/
#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
#define CR_RR	(1 << 14)	/* Round Robin cache replacement	*/
Russell King's avatar
Russell King committed
44 45 46 47 48 49 50 51
#define CR_L4	(1 << 15)	/* LDR pc can set T bit			*/
#define CR_DT	(1 << 16)
#define CR_IT	(1 << 18)
#define CR_ST	(1 << 19)
#define CR_FI	(1 << 21)
#define CR_U	(1 << 22)	/* Unaligned access operation		*/
#define CR_XP	(1 << 23)	/* Extended page tables			*/
#define CR_VE	(1 << 24)	/* Vectored interrupts			*/
Linus Torvalds's avatar
Linus Torvalds committed
52

Linus Torvalds's avatar
Linus Torvalds committed
53 54 55
extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
extern unsigned long cr_alignment;	/* defined in entry-armv.S */

Russell King's avatar
Russell King committed
56
#if __LINUX_ARM_ARCH__ >= 4
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60 61
#define vectors_base()	((cr_alignment & CR_V) ? 0xffff0000 : 0)
#else
#define vectors_base()	(0)
#endif

Linus Torvalds's avatar
Linus Torvalds committed
62 63 64
/*
 * Save the current interrupt enable state & disable IRQs
 */
65
#define local_irq_save(x)					\
Linus Torvalds's avatar
Linus Torvalds committed
66 67
	({							\
		unsigned long temp;				\
68
		(void) (&temp == &x);				\
Linus Torvalds's avatar
Linus Torvalds committed
69
	__asm__ __volatile__(					\
70
	"mrs	%0, cpsr		@ local_irq_save\n"	\
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73 74
"	orr	%1, %0, #128\n"					\
"	msr	cpsr_c, %1"					\
	: "=r" (x), "=r" (temp)					\
	:							\
75
	: "memory", "cc");					\
Linus Torvalds's avatar
Linus Torvalds committed
76 77 78 79 80
	})
	
/*
 * Enable IRQs
 */
81
#define local_irq_enable()					\
Linus Torvalds's avatar
Linus Torvalds committed
82 83 84
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
85
	"mrs	%0, cpsr		@ local_irq_enable\n"	\
Linus Torvalds's avatar
Linus Torvalds committed
86 87 88 89
"	bic	%0, %0, #128\n"					\
"	msr	cpsr_c, %0"					\
	: "=r" (temp)						\
	:							\
90
	: "memory", "cc");					\
Linus Torvalds's avatar
Linus Torvalds committed
91 92 93 94 95
	})

/*
 * Disable IRQs
 */
96
#define local_irq_disable()					\
Linus Torvalds's avatar
Linus Torvalds committed
97 98 99
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
100
	"mrs	%0, cpsr		@ local_irq_disable\n"	\
Linus Torvalds's avatar
Linus Torvalds committed
101 102 103 104
"	orr	%0, %0, #128\n"					\
"	msr	cpsr_c, %0"					\
	: "=r" (temp)						\
	:							\
105
	: "memory", "cc");					\
Linus Torvalds's avatar
Linus Torvalds committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119
	})

/*
 * Enable FIQs
 */
#define __stf()							\
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
	"mrs	%0, cpsr		@ stf\n"		\
"	bic	%0, %0, #64\n"					\
"	msr	cpsr_c, %0"					\
	: "=r" (temp)						\
	:							\
120
	: "memory", "cc");					\
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134
	})

/*
 * Disable FIQs
 */
#define __clf()							\
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
	"mrs	%0, cpsr		@ clf\n"		\
"	orr	%0, %0, #64\n"					\
"	msr	cpsr_c, %0"					\
	: "=r" (temp)						\
	:							\
135 136 137 138 139 140 141 142 143 144 145
	: "memory", "cc");					\
	})

/*
 * Save the current interrupt enable state.
 */
#define local_save_flags(x)					\
	({							\
	__asm__ __volatile__(					\
	"mrs	%0, cpsr		@ local_save_flags"	\
	: "=r" (x) : : "memory", "cc");				\
Linus Torvalds's avatar
Linus Torvalds committed
146 147 148 149 150
	})

/*
 * restore saved IRQ & FIQ state
 */
151
#define local_irq_restore(x)					\
Linus Torvalds's avatar
Linus Torvalds committed
152
	__asm__ __volatile__(					\
153
	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
Linus Torvalds's avatar
Linus Torvalds committed
154 155
	:							\
	: "r" (x)						\
156
	: "memory", "cc")
Linus Torvalds's avatar
Linus Torvalds committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
/*
 * On the StrongARM, "swp" is terminally broken since it bypasses the
 * cache totally.  This means that the cache becomes inconsistent, and,
 * since we use normal loads/stores as well, this is really bad.
 * Typically, this causes oopsen in filp_close, but could have other,
 * more disasterous effects.  There are two work-arounds:
 *  1. Disable interrupts and emulate the atomic swap
 *  2. Clean the cache, perform atomic swap, flush the cache
 *
 * We choose (1) since its the "easiest" to achieve here and is not
 * dependent on the processor type.
 */
#define swp_is_buggy
#endif

Linus Torvalds's avatar
Linus Torvalds committed
174
static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
Linus Torvalds's avatar
Linus Torvalds committed
175 176 177 178 179 180 181 182 183 184
{
	extern void __bad_xchg(volatile void *, int);
	unsigned long ret;
#ifdef swp_is_buggy
	unsigned long flags;
#endif

	switch (size) {
#ifdef swp_is_buggy
		case 1:
185
			local_irq_save(flags);
Linus Torvalds's avatar
Linus Torvalds committed
186 187
			ret = *(volatile unsigned char *)ptr;
			*(volatile unsigned char *)ptr = x;
188
			local_irq_restore(flags);
Linus Torvalds's avatar
Linus Torvalds committed
189 190 191
			break;

		case 4:
192
			local_irq_save(flags);
Linus Torvalds's avatar
Linus Torvalds committed
193 194
			ret = *(volatile unsigned long *)ptr;
			*(volatile unsigned long *)ptr = x;
195
			local_irq_restore(flags);
Linus Torvalds's avatar
Linus Torvalds committed
196 197 198
			break;
#else
		case 1:	__asm__ __volatile__ ("swpb %0, %1, [%2]"
199
					: "=&r" (ret)
Linus Torvalds's avatar
Linus Torvalds committed
200
					: "r" (x), "r" (ptr)
201
					: "memory", "cc");
Linus Torvalds's avatar
Linus Torvalds committed
202 203
			break;
		case 4:	__asm__ __volatile__ ("swp %0, %1, [%2]"
204
					: "=&r" (ret)
Linus Torvalds's avatar
Linus Torvalds committed
205
					: "r" (x), "r" (ptr)
206
					: "memory", "cc");
Linus Torvalds's avatar
Linus Torvalds committed
207 208
			break;
#endif
Russell King's avatar
Russell King committed
209
		default: __bad_xchg(ptr, size), ret = 0;
Linus Torvalds's avatar
Linus Torvalds committed
210 211 212 213 214 215
	}

	return ret;
}

#endif