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 
15 #include <linux/config.h>
16 #include <asm/atomic.h>
17 #include <asm/irq.h>
18 
19 /*
20  * IDT vectors usable for external interrupt sources start
21  * at 0x20:
22  */
23 #define FIRST_EXTERNAL_VECTOR	0x20
24 
25 #define SYSCALL_VECTOR		0x80
26 
27 /*
28  * Vectors 0x20-0x2f are used for ISA interrupts.
29  */
30 
31 /*
32  * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
33  *
34  *  some of the following vectors are 'rare', they are merged
35  *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
36  *  TLB, reschedule and local APIC vectors are performance-critical.
37  *
38  *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
39  */
40 #define SPURIOUS_APIC_VECTOR	0xff
41 #define ERROR_APIC_VECTOR	0xfe
42 #define INVALIDATE_TLB_VECTOR	0xfd
43 #define RESCHEDULE_VECTOR	0xfc
44 #define CALL_FUNCTION_VECTOR	0xfb
45 
46 /*
47  * Local APIC timer IRQ vector is on a different priority level,
48  * to work around the 'lost local interrupt if more than 2 IRQ
49  * sources per level' errata.
50  */
51 #define LOCAL_TIMER_VECTOR	0xef
52 
53 /*
54  * First APIC vector available to drivers: (vectors 0x30-0xee)
55  * we start at 0x31 to spread out vectors evenly between priority
56  * levels. (0x80 is the syscall vector)
57  */
58 #define FIRST_DEVICE_VECTOR	0x31
59 #define FIRST_SYSTEM_VECTOR	0xef
60 
61 extern int irq_vector[NR_IRQS];
62 #define IO_APIC_VECTOR(irq)	irq_vector[irq]
63 
64 /*
65  * Various low-level irq details needed by irq.c, process.c,
66  * time.c, io_apic.c and smp.c
67  *
68  * Interrupt entry/exit code at both C and assembly level
69  */
70 
71 extern void mask_irq(unsigned int irq);
72 extern void unmask_irq(unsigned int irq);
73 extern void disable_8259A_irq(unsigned int irq);
74 extern void enable_8259A_irq(unsigned int irq);
75 extern int i8259A_irq_pending(unsigned int irq);
76 extern void make_8259A_irq(unsigned int irq);
77 extern void init_8259A(int aeoi);
78 extern void FASTCALL(send_IPI_self(int vector));
79 extern void init_VISWS_APIC_irqs(void);
80 extern void setup_IO_APIC(void);
81 extern void disable_IO_APIC(void);
82 extern void print_IO_APIC(void);
83 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
84 extern void send_IPI(int dest, int vector);
85 
86 extern unsigned long io_apic_irqs;
87 
88 extern atomic_t irq_err_count;
89 extern atomic_t irq_mis_count;
90 
91 extern char _stext, _etext;
92 
93 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
94 
95 #define __STR(x) #x
96 #define STR(x) __STR(x)
97 
98 #define SAVE_ALL \
99 	"cld\n\t" \
100 	"pushl %es\n\t" \
101 	"pushl %ds\n\t" \
102 	"pushl %eax\n\t" \
103 	"pushl %ebp\n\t" \
104 	"pushl %edi\n\t" \
105 	"pushl %esi\n\t" \
106 	"pushl %edx\n\t" \
107 	"pushl %ecx\n\t" \
108 	"pushl %ebx\n\t" \
109 	"movl $" STR(__KERNEL_DS) ",%edx\n\t" \
110 	"movl %edx,%ds\n\t" \
111 	"movl %edx,%es\n\t"
112 
113 #define IRQ_NAME2(nr) nr##_interrupt(void)
114 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
115 
116 #define GET_CURRENT \
117 	"movl %esp, %ebx\n\t" \
118 	"andl $-8192, %ebx\n\t"
119 
120 /*
121  *	SMP has a few special interrupts for IPI messages
122  */
123 
124 	/* there is a second layer of macro just to get the symbolic
125 	   name for the vector evaluated. This change is for RTLinux */
126 #define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
127 #define XBUILD_SMP_INTERRUPT(x,v)\
128 asmlinkage void x(void); \
129 asmlinkage void call_##x(void); \
130 __asm__( \
131 "\n"__ALIGN_STR"\n" \
132 SYMBOL_NAME_STR(x) ":\n\t" \
133 	"pushl $"#v"-256\n\t" \
134 	SAVE_ALL \
135 	SYMBOL_NAME_STR(call_##x)":\n\t" \
136 	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
137 	"jmp ret_from_intr\n");
138 
139 #define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v)
140 #define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
141 asmlinkage void x(struct pt_regs * regs); \
142 asmlinkage void call_##x(void); \
143 __asm__( \
144 "\n"__ALIGN_STR"\n" \
145 SYMBOL_NAME_STR(x) ":\n\t" \
146 	"pushl $"#v"-256\n\t" \
147 	SAVE_ALL \
148 	"movl %esp,%eax\n\t" \
149 	"pushl %eax\n\t" \
150 	SYMBOL_NAME_STR(call_##x)":\n\t" \
151 	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
152 	"addl $4,%esp\n\t" \
153 	"jmp ret_from_intr\n");
154 
155 #define BUILD_COMMON_IRQ() \
156 asmlinkage void call_do_IRQ(void); \
157 __asm__( \
158 	"\n" __ALIGN_STR"\n" \
159 	"common_interrupt:\n\t" \
160 	SAVE_ALL \
161 	SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \
162 	"call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
163 	"jmp ret_from_intr\n");
164 
165 /*
166  * subtle. orig_eax is used by the signal code to distinct between
167  * system calls and interrupted 'random user-space'. Thus we have
168  * to put a negative value into orig_eax here. (the problem is that
169  * both system calls and IRQs want to have small integer numbers in
170  * orig_eax, and the syscall code has won the optimization conflict ;)
171  *
172  * Subtle as a pigs ear.  VY
173  */
174 
175 #define BUILD_IRQ(nr) \
176 asmlinkage void IRQ_NAME(nr); \
177 __asm__( \
178 "\n"__ALIGN_STR"\n" \
179 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
180 	"pushl $"#nr"-256\n\t" \
181 	"jmp common_interrupt");
182 
183 extern unsigned long prof_cpu_mask;
184 extern unsigned int * prof_buffer;
185 extern unsigned long prof_len;
186 extern unsigned long prof_shift;
187 
188 /*
189  * x86 profiling function, SMP safe. We might want to do this in
190  * assembly totally?
191  */
x86_do_profile(unsigned long eip)192 static inline void x86_do_profile (unsigned long eip)
193 {
194 	if (!prof_buffer)
195 		return;
196 
197 	/*
198 	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
199 	 * (default is all CPUs.)
200 	 */
201 	if (!((1<<smp_processor_id()) & prof_cpu_mask))
202 		return;
203 
204 	eip -= (unsigned long) &_stext;
205 	eip >>= prof_shift;
206 	/*
207 	 * Don't ignore out-of-bounds EIP values silently,
208 	 * put them into the last histogram slot, so if
209 	 * present, they will show up as a sharp peak.
210 	 */
211 	if (eip > prof_len-1)
212 		eip = prof_len-1;
213 	atomic_inc((atomic_t *)&prof_buffer[eip]);
214 }
215 
216 #if defined(CONFIG_X86_IO_APIC)
hw_resend_irq(struct hw_interrupt_type * h,unsigned int i)217 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
218 	if (IO_APIC_IRQ(i))
219 		send_IPI_self(IO_APIC_VECTOR(i));
220 }
221 #else
hw_resend_irq(struct hw_interrupt_type * h,unsigned int i)222 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
223 #endif
224 
225 #endif /* _ASM_HW_IRQ_H */
226