entry-armv.S 37 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
/*
 *  linux/arch/arm/kernel/entry-armv.S
 *
 *  Copyright (C) 1996,1997,1998 Russell King.
 *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
 *
 * 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.
 *
 *  Low-level vector interface routines
 *
 *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
 *  it to save wrong values...  Be aware!
 */
Linus Torvalds's avatar
Linus Torvalds committed
16
#include <linux/config.h>
Russell King's avatar
Russell King committed
17
#include <linux/init.h>
18

19
#include <asm/thread_info.h>
20
#include <asm/glue.h>
21
#include <asm/ptrace.h>
Linus Torvalds's avatar
Linus Torvalds committed
22

23
#include "entry-header.S"
Linus Torvalds's avatar
Linus Torvalds committed
24

Linus Torvalds's avatar
Linus Torvalds committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#ifdef IOC_BASE
/* IOC / IOMD based hardware */
#include <asm/hardware/iomd.h>

		.equ	ioc_base_high, IOC_BASE & 0xff000000
		.equ	ioc_base_low, IOC_BASE & 0x00ff0000
		.macro	disable_fiq
		mov	r12, #ioc_base_high
		.if	ioc_base_low
		orr	r12, r12, #ioc_base_low
		.endif
		strb	r12, [r12, #0x38]	@ Disable FIQ register
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		mov	r4, #ioc_base_high		@ point at IOC
		.if	ioc_base_low
		orr	r4, r4, #ioc_base_low
		.endif
Linus Torvalds's avatar
Linus Torvalds committed
44 45
		ldrb	\irqstat, [r4, #IOMD_IRQREQB]	@ get high priority first
		ldr	\base, =irq_prio_h
Linus Torvalds's avatar
Linus Torvalds committed
46 47
		teq	\irqstat, #0
#ifdef IOMD_BASE
Linus Torvalds's avatar
Linus Torvalds committed
48 49
		ldreqb	\irqstat, [r4, #IOMD_DMAREQ]	@ get dma
		addeq	\base, \base, #256		@ irq_prio_h table size
Linus Torvalds's avatar
Linus Torvalds committed
50
		teqeq	\irqstat, #0
Linus Torvalds's avatar
Linus Torvalds committed
51
		bne	2406f
Linus Torvalds's avatar
Linus Torvalds committed
52
#endif
Linus Torvalds's avatar
Linus Torvalds committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66
		ldreqb	\irqstat, [r4, #IOMD_IRQREQA]	@ get low priority
		addeq	\base, \base, #256		@ irq_prio_d table size
		teqeq	\irqstat, #0
#ifdef IOMD_IRQREQC
		ldreqb	\irqstat, [r4, #IOMD_IRQREQC]
		addeq	\base, \base, #256		@ irq_prio_l table size
		teqeq	\irqstat, #0
#endif
#ifdef IOMD_IRQREQD
		ldreqb	\irqstat, [r4, #IOMD_IRQREQD]
		addeq	\base, \base, #256		@ irq_prio_lc table size
		teqeq	\irqstat, #0
#endif
2406:		ldrneb	\irqnr, [\base, \irqstat]	@ get IRQ number
Linus Torvalds's avatar
Linus Torvalds committed
67 68 69
		.endm

/*
Linus Torvalds's avatar
Linus Torvalds committed
70 71
 * Interrupt table (incorporates priority).  Please note that we
 * rely on the order of these tables (see above code).
Linus Torvalds's avatar
Linus Torvalds committed
72 73
 */
		.macro	irq_prio_table
Linus Torvalds's avatar
Linus Torvalds committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
irq_prio_h:	.byte	 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
Linus Torvalds's avatar
Linus Torvalds committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#ifdef IOMD_BASE
irq_prio_d:	.byte	 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
		.byte	21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
#endif
Linus Torvalds's avatar
Linus Torvalds committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
irq_prio_l:	.byte	 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
		.byte	 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
#ifdef IOMD_IRQREQC
irq_prio_lc:	.byte	24,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27
		.byte	28,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27
		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
		.byte	30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27
		.byte	30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27
		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
		.byte	29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
		.byte	31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
#endif
#ifdef IOMD_IRQREQD
irq_prio_ld:	.byte	40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43
		.byte	44,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43
		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
		.byte	46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43
		.byte	46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43
		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
		.byte	45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
		.byte	47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
#endif
Linus Torvalds's avatar
Linus Torvalds committed
160 161 162 163
		.endm

#elif defined(CONFIG_ARCH_EBSA110)

Linus Torvalds's avatar
Linus Torvalds committed
164 165
#define IRQ_STAT		0xff000000	/* read */

Linus Torvalds's avatar
Linus Torvalds committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, stat, base, tmp
		mov	\base, #IRQ_STAT
		ldrb	\stat, [\base]			@ get interrupts
		mov	\irqnr, #0
		tst	\stat, #15
		addeq	\irqnr, \irqnr, #4
		moveq	\stat, \stat, lsr #4
		tst	\stat, #3
		addeq	\irqnr, \irqnr, #2
		moveq	\stat, \stat, lsr #2
		tst	\stat, #1
		addeq	\irqnr, \irqnr, #1
		moveq	\stat, \stat, lsr #1
		tst	\stat, #1			@ bit 0 should be set
		.endm

		.macro	irq_prio_table
		.endm

#elif defined(CONFIG_ARCH_SHARK)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		mov	r4, #0xe0000000

		mov	\irqstat, #0x0C
Russell King's avatar
Russell King committed
197
		strb	\irqstat, [r4, #0x20]		@outb(0x0C, 0x20) /* Poll command */
198
		ldrb	\irqnr, [r4, #0x20]		@irq = inb(0x20) & 7
Linus Torvalds's avatar
Linus Torvalds committed
199 200 201 202 203 204 205
		and	\irqstat, \irqnr, #0x80
		teq	\irqstat, #0
		beq	43f
		and	\irqnr, \irqnr, #7
		teq	\irqnr, #2
		bne	44f
43:		mov	\irqstat, #0x0C
Russell King's avatar
Russell King committed
206 207
		strb	\irqstat, [r4, #0xa0]		@outb(0x0C, 0xA0) /* Poll command */
		ldrb	\irqnr, [r4, #0xa0]		@irq = (inb(0xA0) & 7) + 8
Linus Torvalds's avatar
Linus Torvalds committed
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
		and	\irqstat, \irqnr, #0x80
		teq	\irqstat, #0
		beq	44f
		and	\irqnr, \irqnr, #7
		add	\irqnr, \irqnr, #8
44:		teq	\irqstat, #0
		.endm

		.macro	irq_prio_table
		.endm

#elif defined(CONFIG_FOOTBRIDGE)
#include <asm/hardware/dec21285.h>

		.macro	disable_fiq
		.endm

		.equ	dc21285_high, ARMCSR_BASE & 0xff000000
		.equ	dc21285_low, ARMCSR_BASE & 0x00ffffff

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		mov	r4, #dc21285_high
		.if	dc21285_low
		orr	r4, r4, #dc21285_low
		.endif
		ldr	\irqstat, [r4, #0x180]		@ get interrupts

		mov	\irqnr, #IRQ_SDRAMPARITY
		tst	\irqstat, #IRQ_MASK_SDRAMPARITY
		bne	1001f

		tst	\irqstat, #IRQ_MASK_UART_RX
		movne	\irqnr, #IRQ_CONRX
		bne	1001f

		tst	\irqstat, #IRQ_MASK_DMA1
		movne	\irqnr, #IRQ_DMA1
		bne	1001f

		tst	\irqstat, #IRQ_MASK_DMA2
		movne	\irqnr, #IRQ_DMA2
		bne	1001f

		tst	\irqstat, #IRQ_MASK_IN0
		movne	\irqnr, #IRQ_IN0
		bne	1001f

		tst	\irqstat, #IRQ_MASK_IN1
		movne	\irqnr, #IRQ_IN1
		bne	1001f

		tst	\irqstat, #IRQ_MASK_IN2
		movne	\irqnr, #IRQ_IN2
		bne	1001f

		tst	\irqstat, #IRQ_MASK_IN3
		movne	\irqnr, #IRQ_IN3
		bne	1001f

		tst	\irqstat, #IRQ_MASK_PCI
		movne	\irqnr, #IRQ_PCI
		bne	1001f

		tst	\irqstat, #IRQ_MASK_DOORBELLHOST
		movne	\irqnr, #IRQ_DOORBELLHOST
		bne     1001f
	
		tst	\irqstat, #IRQ_MASK_I2OINPOST
		movne	\irqnr, #IRQ_I2OINPOST
		bne	1001f

		tst	\irqstat, #IRQ_MASK_TIMER1
		movne	\irqnr, #IRQ_TIMER1
		bne	1001f

		tst	\irqstat, #IRQ_MASK_TIMER2
		movne	\irqnr, #IRQ_TIMER2
		bne	1001f

		tst	\irqstat, #IRQ_MASK_TIMER3
		movne	\irqnr, #IRQ_TIMER3
		bne	1001f

		tst	\irqstat, #IRQ_MASK_UART_TX
		movne	\irqnr, #IRQ_CONTX
		bne	1001f

		tst	\irqstat, #IRQ_MASK_PCI_ABORT
		movne	\irqnr, #IRQ_PCI_ABORT
		bne	1001f

		tst	\irqstat, #IRQ_MASK_PCI_SERR
		movne	\irqnr, #IRQ_PCI_SERR
		bne	1001f

		tst	\irqstat, #IRQ_MASK_DISCARD_TIMER
		movne	\irqnr, #IRQ_DISCARD_TIMER
		bne	1001f

		tst	\irqstat, #IRQ_MASK_PCI_DPERR
		movne	\irqnr, #IRQ_PCI_DPERR
		bne	1001f

		tst	\irqstat, #IRQ_MASK_PCI_PERR
		movne	\irqnr, #IRQ_PCI_PERR
1001:
		.endm

		.macro	irq_prio_table
		.endm

#elif defined(CONFIG_ARCH_NEXUSPCI)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		ldr	\irqstat, =INTCONT_BASE
		ldr	\base, =soft_irq_mask
		ldr	\irqstat, [\irqstat]		@ get interrupts
		ldr	\base, [\base]
		mov	\irqnr, #0
		and	\irqstat, \irqstat, \base	@ mask out disabled ones
1001:		tst	\irqstat, #1
		addeq	\irqnr, \irqnr, #1
		moveq	\irqstat, \irqstat, lsr #1
		tsteq	\irqnr, #32
		beq	1001b
		teq	\irqnr, #32
		.endm

		.macro	irq_prio_table
		.ltorg
		.bss
ENTRY(soft_irq_mask)
		.word	0
		.text
		.endm

#elif defined(CONFIG_ARCH_TBOX)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		ldr	\irqstat, =0xffff7000
		ldr	\irqstat, [\irqstat]		@ get interrupts
		ldr	\base, =soft_irq_mask
		ldr	\base, [\base]
		mov	\irqnr, #0
		and	\irqstat, \irqstat, \base	@ mask out disabled ones
1001:		tst	\irqstat, #1
		addeq	\irqnr, \irqnr, #1
		moveq	\irqstat, \irqstat, lsr #1
		tsteq	\irqnr, #32
		beq	1001b
		teq	\irqnr, #32
		.endm

		.macro	irq_prio_table
		.ltorg
		.bss
ENTRY(soft_irq_mask)
		.word	0
		.text
		.endm

#elif defined(CONFIG_ARCH_SA1100)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		mov	r4, #0xfa000000			@ ICIP = 0xfa050000
		add	r4, r4, #0x00050000
		ldr	\irqstat, [r4]			@ get irqs
		ldr	\irqnr, [r4, #4]		@ ICMR = 0xfa050004
		ands	\irqstat, \irqstat, \irqnr
		mov	\irqnr, #0
		beq	1001f
		tst	\irqstat, #0xff
		moveq	\irqstat, \irqstat, lsr #8
		addeq	\irqnr, \irqnr, #8
		tsteq	\irqstat, #0xff
		moveq	\irqstat, \irqstat, lsr #8
		addeq	\irqnr, \irqnr, #8
		tsteq	\irqstat, #0xff
		moveq	\irqstat, \irqstat, lsr #8
		addeq	\irqnr, \irqnr, #8
		tst	\irqstat, #0x0f
		moveq	\irqstat, \irqstat, lsr #4
		addeq	\irqnr, \irqnr, #4
		tst	\irqstat, #0x03
		moveq	\irqstat, \irqstat, lsr #2
		addeq	\irqnr, \irqnr, #2
		tst	\irqstat, #0x01
		addeqs	\irqnr, \irqnr, #1
1001:
		.endm

		.macro	irq_prio_table
		.endm

#elif defined(CONFIG_ARCH_L7200)
Linus Torvalds's avatar
Linus Torvalds committed
412
#include <asm/hardware.h>
Linus Torvalds's avatar
Linus Torvalds committed
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
	
		.equ	irq_base_addr,	IO_BASE_2

		.macro  disable_fiq
		.endm
 
		.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
		mov     \irqstat, #irq_base_addr		@ Virt addr IRQ regs
		add	\irqstat, \irqstat, #0x00001000		@ Status reg
		ldr     \irqstat, [\irqstat, #0]		@ get interrupts
		mov     \irqnr, #0
1001:		tst     \irqstat, #1
		addeq   \irqnr, \irqnr, #1
		moveq   \irqstat, \irqstat, lsr #1
		tsteq   \irqnr, #32
		beq     1001b
		teq     \irqnr, #32
		.endm

		.macro  irq_prio_table
		.endm

#elif defined(CONFIG_ARCH_INTEGRATOR)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
/* FIXME: should not be using soo many LDRs here */
442 443 444 445 446 447 448
		ldr	\base, =IO_ADDRESS(INTEGRATOR_IC_BASE)
		mov	\irqnr, #IRQ_PIC_START
		ldr	\irqstat, [\base, #IRQ_STATUS]		@ get masked status
		ldr	\base, =IO_ADDRESS(INTEGRATOR_HDR_BASE)
		teq	\irqstat, #0
		ldreq	\irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
		moveq	\irqnr, #IRQ_CIC_START
Linus Torvalds's avatar
Linus Torvalds committed
449

450
1001:		tst	\irqstat, #15
Linus Torvalds's avatar
Linus Torvalds committed
451
		bne	1002f
452 453 454 455 456
		add	\irqnr, \irqnr, #4
		movs	\irqstat, \irqstat, lsr #4
		bne	1001b
1002:		tst	\irqstat, #1
		bne	1003f
Linus Torvalds's avatar
Linus Torvalds committed
457
		add	\irqnr, \irqnr, #1
458 459 460
		movs	\irqstat, \irqstat, lsr #1
		bne	1002b
1003:		/* EQ will be set if no irqs pending */
Linus Torvalds's avatar
Linus Torvalds committed
461 462 463 464 465
		.endm

		.macro	irq_prio_table
		.endm

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
#elif defined(CONFIG_ARCH_VERSATILE_PB)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		ldr	\base, =IO_ADDRESS(VERSATILE_VIC_BASE)
		ldr	\irqstat, [\base, #VIC_IRQ_STATUS]	@ get masked status
		mov	\irqnr, #0
		teq	\irqstat, #0
		beq	1003f

1001:		tst	\irqstat, #15
		bne	1002f
		add	\irqnr, \irqnr, #4
		movs	\irqstat, \irqstat, lsr #4
		bne	1001b
1002:		tst	\irqstat, #1
		bne	1003f
		add	\irqnr, \irqnr, #1
		movs	\irqstat, \irqstat, lsr #1
		bne	1002b
1003:		/* EQ will be set if no irqs pending */

@		clz	\irqnr, \irqstat
@1003:		/* EQ will be set if we reach MAXIRQNUM */
		.endm

		.macro	irq_prio_table
		.endm

Linus Torvalds's avatar
Linus Torvalds committed
497 498 499
#elif defined(CONFIG_ARCH_CLPS711X)

#include <asm/hardware/clps7111.h>
Linus Torvalds's avatar
Linus Torvalds committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541

		.macro	disable_fiq
		.endm

#if (INTSR2 - INTSR1) != (INTMR2 - INTMR1)
#error INTSR stride != INTMR stride
#endif

		.macro	get_irqnr_and_base, irqnr, stat, base, mask
		mov	\base, #CLPS7111_BASE
		ldr	\stat, [\base, #INTSR1]
		ldr	\mask, [\base, #INTMR1]
		mov	\irqnr, #4
		mov	\mask, \mask, lsl #16
		and	\stat, \stat, \mask, lsr #16
		movs	\stat, \stat, lsr #4
		bne	1001f

		add	\base, \base, #INTSR2 - INTSR1
		ldr	\stat, [\base, #INTSR1]
		ldr	\mask, [\base, #INTMR1]
		mov	\irqnr, #16
		mov	\mask, \mask, lsl #16
		and	\stat, \stat, \mask, lsr #16

1001:		tst	\stat, #255
		addeq	\irqnr, \irqnr, #8
		moveq	\stat, \stat, lsr #8
		tst	\stat, #15
		addeq	\irqnr, \irqnr, #4
		moveq	\stat, \stat, lsr #4
		tst	\stat, #3
		addeq	\irqnr, \irqnr, #2
		moveq	\stat, \stat, lsr #2
		tst	\stat, #1
		addeq	\irqnr, \irqnr, #1
		moveq	\stat, \stat, lsr #1
		tst	\stat, #1			@ bit 0 should be set
		.endm

		.macro	irq_prio_table
		.endm
Linus Torvalds's avatar
Linus Torvalds committed
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
	
#elif defined (CONFIG_ARCH_CAMELOT)
#include <asm/arch/platform.h>
#undef IRQ_MODE /* same name defined in asm/proc/ptrace.h */
#include <asm/arch/int_ctrl00.h>
	
		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
	
		ldr	\irqstat, =INT_ID(IO_ADDRESS(EXC_INT_CTRL00_BASE))
		ldr	\irqnr,[\irqstat]		
		cmp	\irqnr,#0
		subne	\irqnr,\irqnr,#1

	
		.endm

		.macro	irq_prio_table
		.endm
Linus Torvalds's avatar
Linus Torvalds committed
563

Linus Torvalds's avatar
Linus Torvalds committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
#elif defined(CONFIG_ARCH_IOP310) || defined(CONFIG_ARCH_ADIFCC)

		.macro	disable_fiq
		.endm

        	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        	mrc p13, 0, \irqstat, c4, c0, 0 @ get INTSRC
        	mrc p13, 0, \base, c0, c0, 0    @ get INTCTL

        	tst \irqstat, #(1<<29)      @ if INTSRC_BI
        	tstne   \base, #(1<<3)          @ and INTCTL_BM
        	movne   \irqnr, #IRQ_XS80200_BCU
        	bne 1001f

        	tst \irqstat, #(1<<28)      @ if INTSRC_PI
        	tstne   \base, #(1<<2)          @ and INTCTL_PM
        	movne   \irqnr, #IRQ_XS80200_PMU
        	bne 1001f

        	tst \irqstat, #(1<<31)      @ if INTSRC_FI
        	tstne   \base, #(1<<0)          @ and INTCTL_FM
        	movne   \irqnr, #IRQ_XS80200_EXTFIQ
        	bne 1001f

        	tst \irqstat, #(1<<30)      @ if INTSRC_II
        	tstne   \base, #(1<<1)          @ and INTCTL_IM
        	movne   \irqnr, #IRQ_XS80200_EXTIRQ

1001:
  		.endm

  		.macro	irq_prio_table
 		.endm
597

598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
#elif defined(CONFIG_ARCH_IOP321)
		.macro  disable_fiq
		.endm

		/*
		 * Note: only deal with normal interrupts, not FIQ
		 */
		.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
		mov     \irqnr, #0
		mrc     p6, 0, \irqstat, c8, c0, 0      @ Read IINTSRC
		cmp     \irqstat, #0
		beq     1001f
		clz     \irqnr, \irqstat
		mov     \base, #31
		subs    \irqnr,\base,\irqnr
		add     \irqnr,\irqnr,#IRQ_IOP321_DMA0_EOT
1001:
		.endm

		.macro  irq_prio_table
		.endm

620 621 622 623 624 625
#elif defined(CONFIG_ARCH_PXA)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
626
		mov	\base, #io_p2v(0x40000000)	@ IIR Ctl = 0x40d00000
627 628 629
		add	\base, \base, #0x00d00000
		ldr	\irqstat, [\base, #0]		@ ICIP
		ldr	\irqnr, [\base, #4]		@ ICMR
630
		ands	\irqnr, \irqstat, \irqnr
631
		beq	1001f
632 633 634
		rsb	\irqstat, \irqnr, #0
		and	\irqstat, \irqstat, \irqnr
		clz	\irqnr, \irqstat
635
		rsb	\irqnr, \irqnr, #(31 - PXA_IRQ_SKIP)
636 637 638 639 640 641
1001:
		.endm

		.macro	irq_prio_table
		.endm

642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
#elif defined(CONFIG_ARCH_OMAP)

		.macro	disable_fiq
		.endm

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
		ldr	\base, =IO_ADDRESS(OMAP_IH1_BASE)
		ldr	\irqnr, [\base, #IRQ_ITR]
		ldr	\tmp, [\base, #IRQ_MIR]
		mov	\irqstat, #0xffffffff
		bic	\tmp, \irqstat, \tmp
		tst	\irqnr, \tmp
		beq	1510f

		ldr	\irqnr, [\base, #IRQ_SIR_FIQ]
		cmp	\irqnr, #0
		ldreq	\irqnr, [\base, #IRQ_SIR_IRQ]
		cmpeq	\irqnr, #INT_IH2_IRQ
		ldreq	\base, =IO_ADDRESS(OMAP_IH2_BASE)
		ldreq	\irqnr, [\base, #IRQ_SIR_IRQ]
		addeqs	\irqnr, \irqnr, #32
1510:
		.endm

		.macro	irq_prio_table
		.endm

669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
#elif defined(CONFIG_ARCH_S3C2410)
		/* S3C2410X IRQ Handler, <ben@simtec.co.uk> */

		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp

30000:
		mov	\tmp, #S3C2410_VA_IRQ
		ldr	\irqnr, [ \tmp, #0x14 ]		@ get irq no
		teq	\irqnr, #4
		teqne	\irqnr, #5
		beq	1002f				@ external irq reg
		teq	\irqnr, #16
		beq	1003f				@ lcd controller

		@ debug check to see if interrupt reported is the same
		@ as the offset....

		teq	\irqnr, #0
		beq	20002f
		ldr	\irqstat, [ \tmp, #0x10 ]	@ INTPND
		mov	\irqstat, \irqstat, lsr \irqnr
		tst	\irqstat, #1
		bne	20002f

#if 1
		stmfd	r13!, { r0 - r4 , r14 }
		ldr	r1,	[ \tmp, #0x14 ]		@ intoffset
		ldr	r2,	[ \tmp, #0x10 ]		@ INTPND
		ldr	r3,	[ \tmp, #0x00 ]		@ SRCPND
		adr	r0, 20003f
		bl	printk
		b	20004f
#endif
20003:
		.ascii	"<7>irq: err - bad offset %d, intpnd=%08x, srcpnd=%08x\n"
		.byte	0
		.align	4
20004:
		mov	r1, #1
		mov	\tmp, #S3C2410_VA_IRQ
		ldmfd	r13!, { r0 - r4 , r14 }

		@ try working out interript number for ourselves
		mov	\irqnr, #0
		ldr	\irqstat, [ \tmp, #0x10 ]	@ INTPND
10021:
		movs	\irqstat, \irqstat, lsr#1
		bcs	30000b		@ try and re-start the proccess
		add	\irqnr, \irqnr, #1
		cmp	\irqnr, #32
		ble	10021b

		@ found no interrupt, set Z flag and leave
		movs	\irqnr, #0
		b	1001f

20005:
20002:		@ exit
		@ we base the s3c2410x interrupts at 16 and above to allow
		@ isa peripherals to have their standard interrupts, also
		@ ensure that Z flag is un-set on exit

		@ note, we cannot be sure if we get IRQ_EINT0 (0) that
		@ there is simply no interrupt pending, so in all other
		@ cases we jump to say we have found something, otherwise
		@ we check to see if the interrupt really is assrted
		adds	\irqnr, \irqnr, #IRQ_EINT0
		teq	\irqnr, #IRQ_EINT0
		bne	1001f				@ exit
		ldr	\irqstat, [ \tmp, #0x10 ]	@ INTPND
		teq	\irqstat, #0
		moveq	\irqnr, #0
		b	1001f

		@ we get here from no main or external interrupts pending
1002:
		add	\tmp, \tmp, #S3C2410_VA_GPIO - S3C2410_VA_IRQ
		ldr	\irqstat, [ \tmp, # 0xa8 ]	@ EXTINTPEND
		ldr	\irqnr, [ \tmp, # 0xa4 ]	@ EXTINTMASK

		bic	\irqstat, \irqstat, \irqnr	@ clear masked irqs

		mov	\irqnr, #IRQ_EINT4		@ start extint nos
		mov	\irqstat, \irqstat, lsr#4	@ ignore bottom 4 bits
10021:
		movs	\irqstat, \irqstat, lsr#1
		bcs	1004f
		add	\irqnr, \irqnr, #1
		cmp	\irqnr, #IRQ_EINT23
		ble	10021b

		@ found no interrupt, set Z flag and leave
		movs	\irqnr, #0
		b	1001f

1003:
		@ lcd interrupt has been asserted...
		add	\tmp, \tmp, #S3C2410_VA_LCD - S3C2410_VA_IRQ
		ldr	\irqstat, [ \tmp, # 0x54 ]	@ lcd int pending

		tst	\irqstat, #2
		movne	\irqnr, #IRQ_LCD_FRAME
		tst	\irqstat, #1
		movne	\irqnr, #IRQ_LCD_FIFO

		@ fall through to exit with flags updated

1004:		@ ensure Z flag clear in case our MOVS shifted out the last bit
		teq	\irqnr, #0
1001:
		@ exit irq routine
		.endm


		/* currently don't need an disable_fiq macro */

		.macro	disable_fiq
		.endm

		/* we don't have an irq priority table */
		.macro irq_prio_table
		.endm

Linus Torvalds's avatar
Linus Torvalds committed
792 793
#else
#error Unknown architecture
Linus Torvalds's avatar
Linus Torvalds committed
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
#endif

/*
 * Invalid mode handlers
 */
__pabt_invalid:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
		stmia	sp, {r0 - lr}			@ Save XXX r0 - lr
		ldr	r4, .LCabt
		mov	r1, #BAD_PREFETCH
		b	1f

__dabt_invalid:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - lr}			@ Save SVC r0 - lr [lr *should* be intact]
		ldr	r4, .LCabt
		mov	r1, #BAD_DATA
		b	1f

__irq_invalid:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate space on stack for frame
		stmfd	sp, {r0 - lr}			@ Save r0 - lr
		ldr	r4, .LCirq
		mov	r1, #BAD_IRQ
		b	1f

__und_invalid:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - lr}
		ldr	r4, .LCund
		mov	r1, #BAD_UNDEFINSTR		@ int reason

1:		zero_fp
		ldmia	r4, {r5 - r7}			@ Get XXX pc, cpsr, old_r0
		add	r4, sp, #S_PC
		stmia	r4, {r5 - r7}			@ Save XXX pc, cpsr, old_r0
		mov	r0, sp
		and	r2, r6, #31			@ int mode
828
		b	bad_mode
Linus Torvalds's avatar
Linus Torvalds committed
829 830 831 832 833 834 835 836 837 838 839 840 841 842

/*
 * SVC mode handlers
 */
		.align	5
__dabt_svc:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - r12}			@ save r0 - r12
		ldr	r2, .LCabt
		add	r0, sp, #S_FRAME_SIZE
		ldmia	r2, {r2 - r4}			@ get pc, cpsr
		add	r5, sp, #S_SP
		mov	r1, lr
		stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
		mrs	r9, cpsr			@ Enable interrupts if they were
Linus Torvalds's avatar
Linus Torvalds committed
843 844
		tst	r3, #PSR_I_BIT
		biceq	r9, r9, #PSR_I_BIT		@ previously
Linus Torvalds's avatar
Linus Torvalds committed
845 846 847
/*
 * This routine must not corrupt r9
 */
848
#ifdef MULTI_ABORT
849
		ldr	r4, .LCprocfns			@ pass r2, r3 to
Linus Torvalds's avatar
Linus Torvalds committed
850
		mov	lr, pc				@ processor code
Linus Torvalds's avatar
Linus Torvalds committed
851
		ldr	pc, [r4]			@ call processor specific code
Linus Torvalds's avatar
Linus Torvalds committed
852
#else
853
		bl	CPU_ABORT_HANDLER
Linus Torvalds's avatar
Linus Torvalds committed
854 855 856
#endif
		msr	cpsr_c, r9
		mov	r2, sp
857
		bl	do_DataAbort
858
		disable_irq r0
Linus Torvalds's avatar
Linus Torvalds committed
859 860 861 862 863 864 865 866 867 868 869 870 871
		ldr	r0, [sp, #S_PSR]
		msr	spsr, r0
		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr

		.align	5
__irq_svc:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - r12}			@ save r0 - r12
		ldr	r7, .LCirq
		add	r5, sp, #S_FRAME_SIZE
		ldmia	r7, {r7 - r9}
		add	r4, sp, #S_SP
		mov	r6, lr
		stmia	r4, {r5, r6, r7, r8, r9}	@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
872 873 874 875 876 877
#ifdef CONFIG_PREEMPT
		get_thread_info r8
		ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
		add	r7, r9, #1			@ increment it
		str	r7, [r8, #TI_PREEMPT]
#endif
Linus Torvalds's avatar
Linus Torvalds committed
878 879 880 881 882 883
1:		get_irqnr_and_base r0, r6, r5, lr
		movne	r1, sp
		@
		@ routine called with r0 = irq number, r1 = struct pt_regs *
		@
		adrsvc	ne, lr, 1b
884 885 886 887 888 889 890 891 892
		bne	asm_do_IRQ
#ifdef CONFIG_PREEMPT
		ldr	r0, [r8, #TI_FLAGS]		@ get flags
		tst	r0, #_TIF_NEED_RESCHED
		blne	svc_preempt
preempt_return:
		ldr	r0, [r8, #TI_PREEMPT]		@ read preempt value
		teq	r0, r7
		str	r9, [r8, #TI_PREEMPT]		@ restore preempt count
893
		strne	r0, [r0, -r0]			@ bug()
894
#endif
Linus Torvalds's avatar
Linus Torvalds committed
895 896 897 898
		ldr	r0, [sp, #S_PSR]		@ irqs are already disabled
		msr	spsr, r0
		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr

Russell King's avatar
Russell King committed
899 900
		.ltorg

901
#ifdef CONFIG_PREEMPT
902
svc_preempt:	teq	r9, #0				@ was preempt count = 0
Russell King's avatar
Russell King committed
903
		ldreq	r6, .LCirq_stat
904
		movne	pc, lr				@ no
905
		ldr	r0, [r6, #4]			@ local_irq_count
906
		ldr	r1, [r6, #8]			@ local_bh_count
907 908
		adds	r0, r0, r1
		movne	pc, lr
Russell King's avatar
Russell King committed
909 910
		mov	r7, #PREEMPT_ACTIVE
		str	r7, [r8, #TI_PREEMPT]		@ set PREEMPT_ACTIVE
911
1:		enable_irq r2				@ enable IRQs
912
		bl	schedule
913
		disable_irq r0				@ disable IRQs
Russell King's avatar
Russell King committed
914
		ldr	r0, [r8, #TI_FLAGS]		@ get new tasks TI_FLAGS
915
		tst	r0, #_TIF_NEED_RESCHED
Russell King's avatar
Russell King committed
916
		beq	preempt_return			@ go again
917
		b	1b
918 919
#endif

Linus Torvalds's avatar
Linus Torvalds committed
920 921 922
		.align	5
__und_svc:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - r12}			@ save r0 - r12
923 924 925 926 927 928
		ldr	r3, .LCund
		mov	r4, lr
		ldmia	r3, {r5 - r7}
		add	r3, sp, #S_FRAME_SIZE
		add	r2, sp, #S_SP
		stmia	r2, {r3 - r7}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
Linus Torvalds's avatar
Linus Torvalds committed
929

930 931 932
		ldr	r0, [r5, #-4]			@ r0 = instruction
		adrsvc	al, r9, 1f			@ r9 = normal FP return
		bl	call_fpe			@ lr = undefined instr return
Linus Torvalds's avatar
Linus Torvalds committed
933

934
		mov	r0, sp				@ struct pt_regs *regs
935
		bl	do_undefinstr
Linus Torvalds's avatar
Linus Torvalds committed
936

937
1:		disable_irq r0
Linus Torvalds's avatar
Linus Torvalds committed
938 939 940 941 942 943 944 945 946 947 948 949 950 951
		ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
		msr	spsr, lr
		ldmia	sp, {r0 - pc}^			@ Restore SVC registers

		.align	5
__pabt_svc:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - r12}			@ save r0 - r12
		ldr	r2, .LCabt
		add	r0, sp, #S_FRAME_SIZE
		ldmia	r2, {r2 - r4}			@ get pc, cpsr
		add	r5, sp, #S_SP
		mov	r1, lr
		stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
		mrs	r9, cpsr			@ Enable interrupts if they were
Linus Torvalds's avatar
Linus Torvalds committed
952 953
		tst	r3, #PSR_I_BIT
		biceq	r9, r9, #PSR_I_BIT		@ previously
Linus Torvalds's avatar
Linus Torvalds committed
954 955 956
		msr	cpsr_c, r9
		mov	r0, r2				@ address (pc)
		mov	r1, sp				@ regs
957
		bl	do_PrefetchAbort		@ call abort handler
958
		disable_irq r0
Linus Torvalds's avatar
Linus Torvalds committed
959 960 961 962 963 964 965 966
		ldr	r0, [sp, #S_PSR]
		msr	spsr, r0
		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr

		.align	5
.LCirq:		.word	__temp_irq
.LCund:		.word	__temp_und
.LCabt:		.word	__temp_abt
967
#ifdef MULTI_ABORT
968
.LCprocfns:	.word	processor
Linus Torvalds's avatar
Linus Torvalds committed
969
#endif
970
.LCfp:		.word	fp_enter
971
#ifdef CONFIG_PREEMPT
972
.LCirq_stat:	.word	irq_stat
973
#endif
Linus Torvalds's avatar
Linus Torvalds committed
974 975 976 977 978 979 980 981 982

		irq_prio_table

/*
 * User mode handlers
 */
		.align	5
__dabt_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
		stmia	sp, {r0 - r12}			@ save r0 - r12
Linus Torvalds's avatar
Linus Torvalds committed
983 984
		ldr	r7, .LCabt
		add	r5, sp, #S_PC
Linus Torvalds's avatar
Linus Torvalds committed
985 986
		ldmia	r7, {r2 - r4}			@ Get USR pc, cpsr
		stmia	r5, {r2 - r4}			@ Save USR pc, cpsr, old_r0
Linus Torvalds's avatar
Linus Torvalds committed
987 988
		stmdb	r5, {sp, lr}^
		alignment_trap r7, r7, __temp_abt
Linus Torvalds's avatar
Linus Torvalds committed
989
		zero_fp
990
#ifdef MULTI_ABORT
991
		ldr	r4, .LCprocfns			@ pass r2, r3 to
Linus Torvalds's avatar
Linus Torvalds committed
992
		mov	lr, pc				@ processor code
Linus Torvalds's avatar
Linus Torvalds committed
993
		ldr	pc, [r4]			@ call processor specific code
Linus Torvalds's avatar
Linus Torvalds committed
994
#else
995
		bl	CPU_ABORT_HANDLER
Linus Torvalds's avatar
Linus Torvalds committed
996
#endif
997
		enable_irq r2				@ Enable interrupts
Linus Torvalds's avatar
Linus Torvalds committed
998
		mov	r2, sp
Linus Torvalds's avatar
Linus Torvalds committed
999
		adrsvc	al, lr, ret_from_exception
1000
		b	do_DataAbort
Linus Torvalds's avatar
Linus Torvalds committed
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011

		.align	5
__irq_usr:	sub	sp, sp, #S_FRAME_SIZE
		stmia	sp, {r0 - r12}			@ save r0 - r12
		ldr	r4, .LCirq
		add	r8, sp, #S_PC
		ldmia	r4, {r5 - r7}			@ get saved PC, SPSR
		stmia	r8, {r5 - r7}			@ save pc, psr, old_r0
		stmdb	r8, {sp, lr}^
		alignment_trap r4, r7, __temp_irq
		zero_fp
1012 1013 1014 1015 1016 1017
#ifdef CONFIG_PREEMPT
		get_thread_info r8
		ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
		add	r7, r9, #1			@ increment it
		str	r7, [r8, #TI_PREEMPT]
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1018 1019 1020 1021 1022 1023
1:		get_irqnr_and_base r0, r6, r5, lr
		movne	r1, sp
		adrsvc	ne, lr, 1b
		@
		@ routine called with r0 = irq number, r1 = struct pt_regs *
		@
1024 1025 1026 1027 1028
		bne	asm_do_IRQ
#ifdef CONFIG_PREEMPT
		ldr	r0, [r8, #TI_PREEMPT]
		teq	r0, r7
		str	r9, [r8, #TI_PREEMPT]
1029
		strne	r0, [r0, -r0]
1030 1031 1032 1033
		mov	tsk, r8
#else
		get_thread_info tsk
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1034 1035
		mov	why, #0
		b	ret_to_user
Linus Torvalds's avatar
Linus Torvalds committed
1036

Russell King's avatar
Russell King committed
1037 1038
		.ltorg

Linus Torvalds's avatar
Linus Torvalds committed
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
		.align	5
__und_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
		stmia	sp, {r0 - r12}			@ Save r0 - r12
		ldr	r4, .LCund
		add	r8, sp, #S_PC
		ldmia	r4, {r5 - r7}
		stmia	r8, {r5 - r7}			@ Save USR pc, cpsr, old_r0
		stmdb	r8, {sp, lr}^			@ Save user sp, lr
		alignment_trap r4, r7, __temp_und
		zero_fp
1049
		tst	r6, #PSR_T_BIT			@ Thumb mode?
1050
		bne	fpundefinstr			@ ignore FP
1051 1052
		sub	r4, r5, #4
1:		ldrt	r0, [r4]			@ r0  = instruction
Linus Torvalds's avatar
Linus Torvalds committed
1053
		adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
Linus Torvalds's avatar
Linus Torvalds committed
1054 1055
		adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return

1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
/*
 * The out of line fixup for the ldrt above.
 */
		.section .fixup, "ax"
2:		mov	pc, r9
		.previous
		.section __ex_table,"a"
		.long	1b, 2b
		.previous

/*
 * r0 = instruction.
 *
 * Check whether the instruction is a co-processor instruction.
 * If yes, we need to call the relevant co-processor handler.
 *
 * Note that we don't do a full check here for the co-processor
 * instructions; all instructions with bit 27 set are well
 * defined.  The only instructions that should fault are the
 * co-processor instructions.  However, we have to watch out
 * for the ARM6/ARM7 SWI bug.
 *
1078 1079 1080
 * Emulators may wish to make use of the following registers:
 *  r0  - instruction opcode.
 *  r10 - this threads thread_info structure.
1081 1082 1083 1084
 */
call_fpe:	enable_irq r10				@ Enable interrupts
		tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC have bit 27
#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
1085 1086
		and	r8, r0, #0x0f000000		@ mask out op-code bits
		teqne	r8, #0x0f000000			@ SWI (ARM6/7 bug)?
1087 1088
#endif
		moveq	pc, lr
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
		get_thread_info r10			@ get current thread
		and	r8, r0, #0x00000f00		@ mask out CP number
		mov	r7, #1
		add	r6, r10, #TI_USED_CP
		strb	r7, [r6, r8, lsr #8]		@ set appropriate used_cp[]
		add	pc, pc, r8, lsr #6
		mov	r0, r0

		mov	pc, lr				@ CP#0
		b	do_fpe				@ CP#1 (FPE)
		b	do_fpe				@ CP#2 (FPE)
		mov	pc, lr				@ CP#3
		mov	pc, lr				@ CP#4
		mov	pc, lr				@ CP#5
		mov	pc, lr				@ CP#6
		mov	pc, lr				@ CP#7
		mov	pc, lr				@ CP#8
		mov	pc, lr				@ CP#9
		mov	pc, lr				@ CP#10 (VFP)
		mov	pc, lr				@ CP#11 (VFP)
		mov	pc, lr				@ CP#12
		mov	pc, lr				@ CP#13
		mov	pc, lr				@ CP#14 (Debug)
		mov	pc, lr				@ CP#15 (Control)

do_fpe:		ldr	r4, .LCfp
1115
		add	r10, r10, #TI_FPSTATE		@ r10 = workspace
Linus Torvalds's avatar
Linus Torvalds committed
1116
		ldr	pc, [r4]			@ Call FP module USR entry point
1117

1118 1119 1120 1121 1122 1123 1124 1125
/*
 * The FP module is called with these registers set:
 *  r0  = instruction
 *  r5  = PC
 *  r9  = normal "successful" return address
 *  r10 = FP workspace
 *  lr  = unrecognised FP instruction return address
 */
Linus Torvalds's avatar
Linus Torvalds committed
1126

1127 1128
		.data
ENTRY(fp_enter)
Russell King's avatar
Russell King committed
1129
		.word	fpundefinstr
1130 1131
		.text

1132
fpundefinstr:	mov	r0, sp
Linus Torvalds's avatar
Linus Torvalds committed
1133
		adrsvc	al, lr, ret_from_exception
1134
		b	do_undefinstr
Linus Torvalds's avatar
Linus Torvalds committed
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145

		.align	5
__pabt_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
		stmia	sp, {r0 - r12}			@ Save r0 - r12
		ldr	r4, .LCabt
		add	r8, sp, #S_PC
		ldmia	r4, {r5 - r7}			@ Get USR pc, cpsr
		stmia	r8, {r5 - r7}			@ Save USR pc, cpsr, old_r0
		stmdb	r8, {sp, lr}^			@ Save sp_usr lr_usr
		alignment_trap r4, r7, __temp_abt
		zero_fp
1146
		enable_irq r0				@ Enable interrupts
Linus Torvalds's avatar
Linus Torvalds committed
1147 1148
		mov	r0, r5				@ address (pc)
		mov	r1, sp				@ regs
1149
		bl	do_PrefetchAbort		@ call abort handler
Linus Torvalds's avatar
Linus Torvalds committed
1150 1151 1152 1153 1154
		/* fall through */
/*
 * This is the return code to user mode for abort handlers
 */
ENTRY(ret_from_exception)
1155
		get_thread_info tsk
Linus Torvalds's avatar
Linus Torvalds committed
1156 1157 1158
		mov	why, #0
		b	ret_to_user

Linus Torvalds's avatar
Linus Torvalds committed
1159 1160
/*
 * Register switch for ARMv3 and ARMv4 processors
1161
 * r0 = previous thread_info, r1 = next thread_info
Linus Torvalds's avatar
Linus Torvalds committed
1162 1163 1164
 * previous and next are guaranteed not to be the same.
 */
ENTRY(__switch_to)
1165 1166
		add	ip, r1, #TI_CPU_SAVE
		ldr	r3, [r2, #TI_CPU_DOMAIN]!
1167
		stmia	ip, {r4 - sl, fp, sp, lr}	@ Store most regs on stack
1168 1169
		mcr	p15, 0, r3, c3, c0, 0		@ Set domain register
		ldmib	r2, {r4 - sl, fp, sp, pc}	@ Load all regs saved previously
Linus Torvalds's avatar
Linus Torvalds committed
1170

Russell King's avatar
Russell King committed
1171
		__INIT
Linus Torvalds's avatar
Linus Torvalds committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
/*
 * Vector stubs.  NOTE that we only align 'vector_IRQ' to a cache line boundary,
 * and we rely on each stub being exactly 48 (1.5 cache lines) in size.  This
 * means that we only ever load two cache lines for this code, or one if we're
 * lucky.  We also copy this code to 0x200 so that we can use branches in the
 * vectors, rather than ldr's.
 */
		.align	5
__stubs_start:
/*
 * Interrupt dispatcher
 * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 */
vector_IRQ:	@
		@ save mode specific registers
		@
		ldr	r13, .LCsirq
		sub	lr, lr, #4
		str	lr, [r13]			@ save lr_IRQ
		mrs	lr, spsr
		str	lr, [r13, #4]			@ save spsr_IRQ
		@
1194
		@ now branch to the relevant MODE handling routine
Linus Torvalds's avatar
Linus Torvalds committed
1195
		@
1196 1197 1198 1199
		mrs	r13, cpsr
		bic	r13, r13, #MODE_MASK
		orr	r13, r13, #MODE_SVC
		msr	spsr, r13			@ switch to SVC_32 mode
Linus Torvalds's avatar
Linus Torvalds committed
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236

		and	lr, lr, #15
		ldr	lr, [pc, lr, lsl #2]
		movs	pc, lr				@ Changes mode and branches

.LCtab_irq:	.word	__irq_usr			@  0  (USR_26 / USR_32)
		.word	__irq_invalid			@  1  (FIQ_26 / FIQ_32)
		.word	__irq_invalid			@  2  (IRQ_26 / IRQ_32)
		.word	__irq_svc			@  3  (SVC_26 / SVC_32)
		.word	__irq_invalid			@  4
		.word	__irq_invalid			@  5
		.word	__irq_invalid			@  6
		.word	__irq_invalid			@  7
		.word	__irq_invalid			@  8
		.word	__irq_invalid			@  9
		.word	__irq_invalid			@  a
		.word	__irq_invalid			@  b
		.word	__irq_invalid			@  c
		.word	__irq_invalid			@  d
		.word	__irq_invalid			@  e
		.word	__irq_invalid			@  f

		.align	5

/*
 * Data abort dispatcher - dispatches it to the correct handler for the processor mode
 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 */
vector_data:	@
		@ save mode specific registers
		@
		ldr	r13, .LCsabt
		sub	lr, lr, #8
		str	lr, [r13]
		mrs	lr, spsr
		str	lr, [r13, #4]
		@
1237
		@ now branch to the relevant MODE handling routine
Linus Torvalds's avatar
Linus Torvalds committed
1238
		@
1239 1240 1241 1242
		mrs	r13, cpsr
		bic	r13, r13, #MODE_MASK
		orr	r13, r13, #MODE_SVC
		msr	spsr, r13			@ switch to SVC_32 mode
Linus Torvalds's avatar
Linus Torvalds committed
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280

		and	lr, lr, #15
		ldr	lr, [pc, lr, lsl #2]
		movs	pc, lr				@ Changes mode and branches

.LCtab_dabt:	.word	__dabt_usr			@  0  (USR_26 / USR_32)
		.word	__dabt_invalid			@  1  (FIQ_26 / FIQ_32)
		.word	__dabt_invalid			@  2  (IRQ_26 / IRQ_32)
		.word	__dabt_svc			@  3  (SVC_26 / SVC_32)
		.word	__dabt_invalid			@  4
		.word	__dabt_invalid			@  5
		.word	__dabt_invalid			@  6
		.word	__dabt_invalid			@  7
		.word	__dabt_invalid			@  8
		.word	__dabt_invalid			@  9
		.word	__dabt_invalid			@  a
		.word	__dabt_invalid			@  b
		.word	__dabt_invalid			@  c
		.word	__dabt_invalid			@  d
		.word	__dabt_invalid			@  e
		.word	__dabt_invalid			@  f

		.align	5

/*
 * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode
 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 */
vector_prefetch:
		@
		@ save mode specific registers
		@
		ldr	r13, .LCsabt
		sub	lr, lr, #4
		str	lr, [r13]			@ save lr_ABT
		mrs	lr, spsr
		str	lr, [r13, #4]			@ save spsr_ABT
		@
1281
		@ now branch to the relevant MODE handling routine
Linus Torvalds's avatar
Linus Torvalds committed
1282
		@
1283 1284 1285 1286
		mrs	r13, cpsr
		bic	r13, r13, #MODE_MASK
		orr	r13, r13, #MODE_SVC
		msr	spsr, r13			@ switch to SVC_32 mode
Linus Torvalds's avatar
Linus Torvalds committed
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323

		ands	lr, lr, #15
		ldr	lr, [pc, lr, lsl #2]
		movs	pc, lr

.LCtab_pabt:	.word	__pabt_usr			@  0 (USR_26 / USR_32)
		.word	__pabt_invalid			@  1 (FIQ_26 / FIQ_32)
		.word	__pabt_invalid			@  2 (IRQ_26 / IRQ_32)
		.word	__pabt_svc			@  3 (SVC_26 / SVC_32)
		.word	__pabt_invalid			@  4
		.word	__pabt_invalid			@  5
		.word	__pabt_invalid			@  6
		.word	__pabt_invalid			@  7
		.word	__pabt_invalid			@  8
		.word	__pabt_invalid			@  9
		.word	__pabt_invalid			@  a
		.word	__pabt_invalid			@  b
		.word	__pabt_invalid			@  c
		.word	__pabt_invalid			@  d
		.word	__pabt_invalid			@  e
		.word	__pabt_invalid			@  f

		.align	5

/*
 * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode
 * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 */
vector_undefinstr:
		@
		@ save mode specific registers
		@
		ldr	r13, .LCsund
		str	lr, [r13]			@ save lr_UND
		mrs	lr, spsr
		str	lr, [r13, #4]			@ save spsr_UND
		@
1324
		@ now branch to the relevant MODE handling routine
Linus Torvalds's avatar
Linus Torvalds committed
1325
		@
1326 1327 1328 1329
		mrs	r13, cpsr
		bic	r13, r13, #MODE_MASK
		orr	r13, r13, #MODE_SVC
		msr	spsr, r13			@ switch to SVC_32 mode
Linus Torvalds's avatar
Linus Torvalds committed
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433

		and	lr, lr, #15
		ldr	lr, [pc, lr, lsl #2]
		movs	pc, lr				@ Changes mode and branches

.LCtab_und:	.word	__und_usr			@  0 (USR_26 / USR_32)
		.word	__und_invalid			@  1 (FIQ_26 / FIQ_32)
		.word	__und_invalid			@  2 (IRQ_26 / IRQ_32)
		.word	__und_svc			@  3 (SVC_26 / SVC_32)
		.word	__und_invalid			@  4
		.word	__und_invalid			@  5
		.word	__und_invalid			@  6
		.word	__und_invalid			@  7
		.word	__und_invalid			@  8
		.word	__und_invalid			@  9
		.word	__und_invalid			@  a
		.word	__und_invalid			@  b
		.word	__und_invalid			@  c
		.word	__und_invalid			@  d
		.word	__und_invalid			@  e
		.word	__und_invalid			@  f

		.align	5

/*=============================================================================
 * Undefined FIQs
 *-----------------------------------------------------------------------------
 * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
 * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
 * Basically to switch modes, we *HAVE* to clobber one register...  brain
 * damage alert!  I don't think that we can execute any code in here in any
 * other mode than FIQ...  Ok you can switch to another mode, but you can't
 * get out of that mode without clobbering one register.
 */
vector_FIQ:	disable_fiq
		subs	pc, lr, #4

/*=============================================================================
 * Address exception handler
 *-----------------------------------------------------------------------------
 * These aren't too critical.
 * (they're not supposed to happen, and won't happen in 32-bit data mode).
 */

vector_addrexcptn:
		b	vector_addrexcptn

/*
 * We group all the following data together to optimise
 * for CPUs with separate I & D caches.
 */
		.align	5

.LCvswi:	.word	vector_swi

.LCsirq:	.word	__temp_irq
.LCsund:	.word	__temp_und
.LCsabt:	.word	__temp_abt

__stubs_end:

		.equ	__real_stubs_start, .LCvectors + 0x200

.LCvectors:	swi	SYS_ERROR0
		b	__real_stubs_start + (vector_undefinstr - __stubs_start)
		ldr	pc, __real_stubs_start + (.LCvswi - __stubs_start)
		b	__real_stubs_start + (vector_prefetch - __stubs_start)
		b	__real_stubs_start + (vector_data - __stubs_start)
		b	__real_stubs_start + (vector_addrexcptn - __stubs_start)
		b	__real_stubs_start + (vector_IRQ - __stubs_start)
		b	__real_stubs_start + (vector_FIQ - __stubs_start)

ENTRY(__trap_init)
		stmfd	sp!, {r4 - r6, lr}

		adr	r1, .LCvectors			@ set up the vectors
		ldmia	r1, {r1, r2, r3, r4, r5, r6, ip, lr}
		stmia	r0, {r1, r2, r3, r4, r5, r6, ip, lr}

		add	r2, r0, #0x200
		adr	r0, __stubs_start		@ copy stubs to 0x200
		adr	r1, __stubs_end
1:		ldr	r3, [r0], #4
		str	r3, [r2], #4
		cmp	r0, r1
		blt	1b
		LOADREGS(fd, sp!, {r4 - r6, pc})

		.data

/*
 * Do not reorder these, and do not insert extra data between...
 */

__temp_irq:	.word	0				@ saved lr_irq
		.word	0				@ saved spsr_irq
		.word	-1				@ old_r0
__temp_und:	.word	0				@ Saved lr_und
		.word	0				@ Saved spsr_und
		.word	-1				@ old_r0
__temp_abt:	.word	0				@ Saved lr_abt
		.word	0				@ Saved spsr_abt
		.word	-1				@ old_r0

1434 1435 1436
		.globl	cr_alignment
		.globl	cr_no_alignment
cr_alignment:
Linus Torvalds's avatar
Linus Torvalds committed
1437
		.space	4
1438
cr_no_alignment:
Linus Torvalds's avatar
Linus Torvalds committed
1439
		.space	4