1#ifndef _ASM_HW_IRQ_H
2#define _ASM_HW_IRQ_H
3
4/*
5 *	linux/include/asm/hw_irq.h
6 *
7 *	(C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
8 *
9 *	moved some of the old arch/i386/kernel/irq.h to here. VY
10 *
11 *	IRQ/IPI changes taken from work by Thomas Radke
12 *	<tomsoft@informatik.tu-chemnitz.de>
13 *
14 *	hacked by Andi Kleen for x86-64.
15 *
16 *  $Id: hw_irq.h,v 1.1.1.1 2008/10/15 03:29:18 james26_jang Exp $
17 */
18
19#include <linux/config.h>
20#include <asm/atomic.h>
21#include <asm/irq.h>
22
23/*
24 * IDT vectors usable for external interrupt sources start
25 * at 0x20:
26 */
27#define FIRST_EXTERNAL_VECTOR	0x20
28
29#define IA32_SYSCALL_VECTOR	0x80
30#define KDBENTER_VECTOR		0x81
31
32
33/*
34 * Vectors 0x20-0x2f are used for ISA interrupts.
35 */
36
37/*
38 * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
39 *
40 *  some of the following vectors are 'rare', they are merged
41 *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
42 *  TLB, reschedule and local APIC vectors are performance-critical.
43 *
44 *  Vectors 0xf0-0xf9 are free (reserved for future Linux use).
45 */
46#define SPURIOUS_APIC_VECTOR	0xff
47#define ERROR_APIC_VECTOR	0xfe
48#define INVALIDATE_TLB_VECTOR	0xfd
49#define RESCHEDULE_VECTOR	0xfc
50#define KDB_VECTOR		0xfa
51#define CALL_FUNCTION_VECTOR	0xfb
52#define KDB_VECTOR              0xfa
53
54/*
55 * Local APIC timer IRQ vector is on a different priority level,
56 * to work around the 'lost local interrupt if more than 2 IRQ
57 * sources per level' errata.
58 */
59#define LOCAL_TIMER_VECTOR	0xef
60
61/*
62 * First APIC vector available to drivers: (vectors 0x30-0xee)
63 * we start at 0x31 to spread out vectors evenly between priority
64 * levels. (0x80 is the syscall vector)
65 */
66#define FIRST_DEVICE_VECTOR	0x31
67#define FIRST_SYSTEM_VECTOR	0xef
68
69extern int irq_vector[NR_IRQS];
70#define IO_APIC_VECTOR(irq)	irq_vector[irq]
71
72/*
73 * Various low-level irq details needed by irq.c, process.c,
74 * time.c, io_apic.c and smp.c
75 *
76 * Interrupt entry/exit code at both C and assembly level
77 */
78
79extern void mask_irq(unsigned int irq);
80extern void unmask_irq(unsigned int irq);
81extern void disable_8259A_irq(unsigned int irq);
82extern void enable_8259A_irq(unsigned int irq);
83extern int i8259A_irq_pending(unsigned int irq);
84extern void make_8259A_irq(unsigned int irq);
85extern void init_8259A(int aeoi);
86extern void FASTCALL(send_IPI_self(int vector));
87extern void init_VISWS_APIC_irqs(void);
88extern void setup_IO_APIC(void);
89extern void disable_IO_APIC(void);
90extern void print_IO_APIC(void);
91extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
92extern void send_IPI(int dest, int vector);
93
94extern unsigned long io_apic_irqs;
95
96extern atomic_t irq_err_count;
97extern atomic_t irq_mis_count;
98
99extern char _stext, _etext;
100
101#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
102
103#define __STR(x) #x
104#define STR(x) __STR(x)
105
106#include <asm/ptrace.h>
107#ifndef ASM_OFFSET_H
108#include <asm/offset.h>
109#endif
110
111/* IF:off, stack contains irq number on origrax */
112#define IRQ_ENTER								\
113"	cld ;"									\
114"	pushq %rdi ;"								\
115"	pushq %rsi ;"								\
116"	pushq %rdx ;"								\
117"	pushq %rcx ;"								\
118"	pushq %rax ;"								\
119"	pushq %r8 ;"								\
120"	pushq %r9 ;"								\
121"	pushq %r10 ;"								\
122"	pushq %r11 ;"								\
123"	leaq -48(%rsp),%rdi	;"						\
124"	testl $3,136(%rdi)	;"						\
125"	je 1f ;"								\
126"	swapgs ;"								\
127"1:	addl $1,%gs: " STR(pda_irqcount) ";"					\
128"	movq %gs: " STR(pda_irqstackptr) ",%rax ;"				\
129"	cmoveq %rax,%rsp ;"							\
130"	pushq %rdi ;"
131
132#define IRQ_NAME2(nr) nr##_interrupt(void)
133#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
134
135/*
136 *	SMP has a few special interrupts for IPI messages
137 */
138
139	/* there is a second layer of macro just to get the symbolic
140	   name for the vector evaluated. This change is for RTLinux */
141#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
142#define XBUILD_SMP_INTERRUPT(x,v)\
143asmlinkage void x(void); \
144asmlinkage void call_##x(void); \
145__asm__( \
146"\n"__ALIGN_STR"\n" \
147SYMBOL_NAME_STR(x) ":\n\t" \
148	"push $" #v "-256;" \
149	IRQ_ENTER \
150	"call " SYMBOL_NAME_STR(smp_##x) " ; " \
151	"jmp ret_from_intr")
152
153#define BUILD_COMMON_IRQ()
154
155#define BUILD_IRQ(nr) \
156asmlinkage void IRQ_NAME(nr); \
157__asm__( \
158"\n"__ALIGN_STR "\n" \
159SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
160	"push $" #nr "-256 ; " \
161	"jmp common_interrupt");
162
163extern unsigned long prof_cpu_mask;
164extern unsigned int * prof_buffer;
165extern unsigned long prof_len;
166extern unsigned long prof_shift;
167
168/*
169 * x86 profiling function, SMP safe. We might want to do this in
170 * assembly totally?
171 */
172static inline void x86_do_profile (unsigned long eip)
173{
174	if (!prof_buffer)
175		return;
176
177	/*
178	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
179	 * (default is all CPUs.)
180	 */
181	if (!((1<<smp_processor_id()) & prof_cpu_mask))
182		return;
183
184	eip -= (unsigned long) &_stext;
185	eip >>= prof_shift;
186	/*
187	 * Don't ignore out-of-bounds EIP values silently,
188	 * put them into the last histogram slot, so if
189	 * present, they will show up as a sharp peak.
190	 */
191	if (eip > prof_len-1)
192		eip = prof_len-1;
193	atomic_inc((atomic_t *)&prof_buffer[eip]);
194}
195
196#ifdef CONFIG_SMP     /*more of this file should probably be ifdefed SMP */
197static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
198	if (IO_APIC_IRQ(i))
199		send_IPI_self(IO_APIC_VECTOR(i));
200}
201#else
202static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
203#endif
204
205#endif /* _ASM_HW_IRQ_H */
206