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