ia64/xen-unstable

view xen/arch/ia64/linux-xen/irq_ia64.c @ 19197:9e3be0660c1e

Cleanup naming for ia64 and x86 interrupt handling functions

- Append '_IRQ' to AUTO_ASSIGN, NEVER_ASSIGN, and FREE_TO_ASSIGN
- Rename {request,setup}_irq to {request,setup}_irq_vector
- Rename free_irq to release_irq_vector
- Add {request,setup,release}_irq wrappers for their
{request,setup,release}_irq_vector counterparts
- Added generic irq_to_vector inline for ia64
- Changed ia64 to use the new naming scheme

Signed-off-by: Espen Skoglund <espen.skoglund@netronome.com>
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 12 10:48:55 2009 +0000 (2009-02-12)
parents 1a77bb358d7b
children c4c4ba857d8b
line source
1 /*
2 * linux/arch/ia64/kernel/irq.c
3 *
4 * Copyright (C) 1998-2001 Hewlett-Packard Co
5 * Stephane Eranian <eranian@hpl.hp.com>
6 * David Mosberger-Tang <davidm@hpl.hp.com>
7 *
8 * 6/10/99: Updated to bring in sync with x86 version to facilitate
9 * support for SMP and different interrupt controllers.
10 *
11 * 09/15/00 Goutham Rao <goutham.rao@intel.com> Implemented pci_irq_to_vector
12 * PCI to vector allocation routine.
13 * 04/14/2004 Ashok Raj <ashok.raj@intel.com>
14 * Added CPU Hotplug handling for IPF.
15 */
17 #include <linux/config.h>
18 #include <linux/module.h>
20 #include <linux/jiffies.h>
21 #include <linux/errno.h>
22 #include <linux/init.h>
23 #include <linux/interrupt.h>
24 #include <linux/ioport.h>
25 #include <linux/kernel_stat.h>
26 #include <linux/slab.h>
27 #include <linux/ptrace.h>
28 #include <linux/random.h> /* for rand_initialize_irq() */
29 #include <linux/signal.h>
30 #include <linux/smp.h>
31 #include <linux/smp_lock.h>
32 #include <linux/threads.h>
33 #include <linux/bitops.h>
35 #include <asm/delay.h>
36 #include <asm/intrinsics.h>
37 #include <asm/io.h>
38 #include <asm/hw_irq.h>
39 #include <asm/machvec.h>
40 #include <asm/pgtable.h>
41 #include <asm/system.h>
43 #ifdef XEN
44 #include <xen/perfc.h>
45 #endif
47 #ifdef CONFIG_PERFMON
48 # include <asm/perfmon.h>
49 #endif
51 #define IRQ_DEBUG 0
53 /* default base addr of IPI table */
54 void __iomem *ipi_base_addr = ((void __iomem *)
55 (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
57 /*
58 * Legacy IRQ to IA-64 vector translation table.
59 */
60 __u8 isa_irq_to_vector_map[16] = {
61 /* 8259 IRQ translation, first 16 entries */
62 0x2f, 0x20, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
63 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21
64 };
65 EXPORT_SYMBOL(isa_irq_to_vector_map);
67 #ifdef XEN
68 unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
69 #else
70 static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
71 #endif
73 int
74 assign_irq_vector (int irq)
75 {
76 int pos, vector;
77 again:
78 pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
79 vector = IA64_FIRST_DEVICE_VECTOR + pos;
80 if (vector > IA64_LAST_DEVICE_VECTOR)
81 return -ENOSPC;
82 if (test_and_set_bit(pos, ia64_vector_mask))
83 goto again;
84 return vector;
85 }
87 void
88 free_irq_vector (int vector)
89 {
90 int pos;
92 if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
93 return;
95 pos = vector - IA64_FIRST_DEVICE_VECTOR;
96 if (!test_and_clear_bit(pos, ia64_vector_mask))
97 printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
98 }
100 #ifdef CONFIG_SMP
101 # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
102 #else
103 # define IS_RESCHEDULE(vec) (0)
104 #endif
105 /*
106 * That's where the IVT branches when we get an external
107 * interrupt. This branches to the correct hardware IRQ handler via
108 * function ptr.
109 */
110 void
111 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
112 {
113 unsigned long saved_tpr;
115 #ifdef XEN
116 perfc_incr(irqs);
117 #endif
118 #if IRQ_DEBUG
119 #ifdef XEN
120 xen_debug_irq(vector, regs);
121 #endif
122 {
123 unsigned long bsp, sp;
125 /*
126 * Note: if the interrupt happened while executing in
127 * the context switch routine (ia64_switch_to), we may
128 * get a spurious stack overflow here. This is
129 * because the register and the memory stack are not
130 * switched atomically.
131 */
132 bsp = ia64_getreg(_IA64_REG_AR_BSP);
133 sp = ia64_getreg(_IA64_REG_SP);
135 if ((sp - bsp) < 1024) {
136 static unsigned char count;
137 static long last_time;
139 if (jiffies - last_time > 5*HZ)
140 count = 0;
141 if (++count < 5) {
142 last_time = jiffies;
143 printk("ia64_handle_irq: DANGER: less than "
144 "1KB of free stack space!!\n"
145 "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
146 }
147 }
148 }
149 #endif /* IRQ_DEBUG */
151 /*
152 * Always set TPR to limit maximum interrupt nesting depth to
153 * 16 (without this, it would be ~240, which could easily lead
154 * to kernel stack overflows).
155 */
156 irq_enter();
157 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
158 ia64_srlz_d();
159 while (vector != IA64_SPURIOUS_INT_VECTOR) {
160 if (!IS_RESCHEDULE(vector)) {
161 ia64_setreg(_IA64_REG_CR_TPR, vector);
162 ia64_srlz_d();
164 __do_IRQ(local_vector_to_irq(vector), regs);
166 /*
167 * Disable interrupts and send EOI:
168 */
169 local_irq_disable();
170 ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
171 }
172 ia64_eoi();
173 vector = ia64_get_ivr();
174 }
175 /*
176 * This must be done *after* the ia64_eoi(). For example, the keyboard softirq
177 * handler needs to be able to wait for further keyboard interrupts, which can't
178 * come through until ia64_eoi() has been done.
179 */
180 irq_exit();
181 }
183 #ifndef XEN
184 #ifdef CONFIG_HOTPLUG_CPU
185 /*
186 * This function emulates a interrupt processing when a cpu is about to be
187 * brought down.
188 */
189 void ia64_process_pending_intr(void)
190 {
191 ia64_vector vector;
192 unsigned long saved_tpr;
193 extern unsigned int vectors_in_migration[NR_IRQS];
195 vector = ia64_get_ivr();
197 irq_enter();
198 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
199 ia64_srlz_d();
201 /*
202 * Perform normal interrupt style processing
203 */
204 while (vector != IA64_SPURIOUS_INT_VECTOR) {
205 if (!IS_RESCHEDULE(vector)) {
206 ia64_setreg(_IA64_REG_CR_TPR, vector);
207 ia64_srlz_d();
209 /*
210 * Now try calling normal ia64_handle_irq as it would have got called
211 * from a real intr handler. Try passing null for pt_regs, hopefully
212 * it will work. I hope it works!.
213 * Probably could shared code.
214 */
215 vectors_in_migration[local_vector_to_irq(vector)]=0;
216 __do_IRQ(local_vector_to_irq(vector), NULL);
218 /*
219 * Disable interrupts and send EOI
220 */
221 local_irq_disable();
222 ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
223 }
224 ia64_eoi();
225 vector = ia64_get_ivr();
226 }
227 irq_exit();
228 }
229 #endif
230 #endif
233 #ifdef CONFIG_SMP
234 extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
236 static struct irqaction ipi_irqaction = {
237 .handler = handle_IPI,
238 #ifndef XEN
239 .flags = SA_INTERRUPT,
240 #endif
241 .name = "IPI"
242 };
243 #endif
245 #ifdef XEN
246 extern void setup_vector (unsigned int vec, struct irqaction *action);
247 #endif
249 void
250 register_percpu_irq (ia64_vector vec, struct irqaction *action)
251 {
252 irq_desc_t *desc;
253 #ifndef XEN
254 unsigned int irq;
256 for (irq = 0; irq < NR_IRQS; ++irq)
257 if (irq_to_vector(irq) == vec) {
258 desc = irq_descp(irq);
259 desc->status |= IRQ_PER_CPU;
260 desc->handler = &irq_type_ia64_lsapic;
261 if (action)
262 setup_irq(irq, action);
263 }
264 #else
265 desc = irq_descp(vec);
266 desc->status |= IRQ_PER_CPU;
267 desc->handler = &irq_type_ia64_lsapic;
268 if (action)
269 setup_vector(vec, action);
270 #endif
271 }
273 #ifdef XEN
274 int request_irq_vector(unsigned int vector,
275 void (*handler)(int, void *, struct cpu_user_regs *),
276 unsigned long irqflags, const char * devname, void *dev_id)
277 {
278 struct irqaction * action;
279 int retval=0;
281 /*
282 * Sanity-check: shared interrupts must pass in a real dev-ID,
283 * otherwise we'll have trouble later trying to figure out
284 * which interrupt is which (messes up the interrupt freeing logic etc).
285 * */
286 if (vector >= NR_VECTORS)
287 return -EINVAL;
288 if (!handler)
289 return -EINVAL;
291 action = xmalloc(struct irqaction);
292 if (!action)
293 return -ENOMEM;
295 action->handler = handler;
296 action->name = devname;
297 action->dev_id = dev_id;
298 setup_vector(vector, action);
299 if (retval)
300 xfree(action);
302 return retval;
303 }
304 #endif
306 void __init
307 init_IRQ (void)
308 {
309 register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
310 #ifdef CONFIG_SMP
311 register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
312 #endif
313 #ifdef CONFIG_PERFMON
314 pfm_init_percpu();
315 #endif
316 platform_irq_init();
317 }
319 void
320 ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
321 {
322 void __iomem *ipi_addr;
323 unsigned long ipi_data;
324 unsigned long phys_cpu_id;
326 #ifdef CONFIG_SMP
327 phys_cpu_id = cpu_physical_id(cpu);
328 #else
329 phys_cpu_id = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
330 #endif
332 /*
333 * cpu number is in 8bit ID and 8bit EID
334 */
336 ipi_data = (delivery_mode << 8) | (vector & 0xff);
337 ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3));
339 writeq(ipi_data, ipi_addr);
340 }