ia64/xen-unstable

view linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c @ 9747:de2dc4e7966a

[IA64] Add support to physdev_ops

Add support to physdev ops, and thus give IOSAPIC RTEs
managed by Xen now. Dom0 now issues hypercall to r/w
RTE entry. Another change is the irq vector allocation
which is also owned by xen now.

After this change, the IOSAPIC is almost owned by xen
with only exception as IOSAPIC EOI which is still issued
by dom0 directly. But that's OK since currently dom0
owns all external physical devices. Later full event
channel mechanism will provide necessary support for
driver domain, and at that time, dom0 instead issues
physdev_op (PHYSDEVOP_IRQ_UNMASK_NOTIFY) naturally as
replace of IOSAPIC EOI.

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author awilliam@xenbuild.aw
date Fri Apr 21 09:03:19 2006 -0600 (2006-04-21)
parents 19148831ab05
children de0c04ed4ab7
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 CONFIG_PERFMON
44 # include <asm/perfmon.h>
45 #endif
47 #define IRQ_DEBUG 0
49 /* default base addr of IPI table */
50 void __iomem *ipi_base_addr = ((void __iomem *)
51 (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
53 /*
54 * Legacy IRQ to IA-64 vector translation table.
55 */
56 __u8 isa_irq_to_vector_map[16] = {
57 /* 8259 IRQ translation, first 16 entries */
58 0x2f, 0x20, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
59 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21
60 };
61 EXPORT_SYMBOL(isa_irq_to_vector_map);
63 static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
65 int
66 assign_irq_vector (int irq)
67 {
68 int pos, vector;
69 #ifdef CONFIG_XEN
70 extern int xen_assign_irq_vector(int);
71 if (running_on_xen)
72 return xen_assign_irq_vector(irq);
73 #endif /* CONFIG_XEN */
74 again:
75 pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
76 vector = IA64_FIRST_DEVICE_VECTOR + pos;
77 if (vector > IA64_LAST_DEVICE_VECTOR)
78 return -ENOSPC;
79 if (test_and_set_bit(pos, ia64_vector_mask))
80 goto again;
81 return vector;
82 }
84 void
85 free_irq_vector (int vector)
86 {
87 int pos;
89 if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
90 return;
92 pos = vector - IA64_FIRST_DEVICE_VECTOR;
93 if (!test_and_clear_bit(pos, ia64_vector_mask))
94 printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
95 }
97 #ifdef CONFIG_SMP
98 # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
99 #else
100 # define IS_RESCHEDULE(vec) (0)
101 #endif
102 /*
103 * That's where the IVT branches when we get an external
104 * interrupt. This branches to the correct hardware IRQ handler via
105 * function ptr.
106 */
107 void
108 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
109 {
110 unsigned long saved_tpr;
112 #if IRQ_DEBUG
113 {
114 unsigned long bsp, sp;
116 /*
117 * Note: if the interrupt happened while executing in
118 * the context switch routine (ia64_switch_to), we may
119 * get a spurious stack overflow here. This is
120 * because the register and the memory stack are not
121 * switched atomically.
122 */
123 bsp = ia64_getreg(_IA64_REG_AR_BSP);
124 sp = ia64_getreg(_IA64_REG_SP);
126 if ((sp - bsp) < 1024) {
127 static unsigned char count;
128 static long last_time;
130 if (jiffies - last_time > 5*HZ)
131 count = 0;
132 if (++count < 5) {
133 last_time = jiffies;
134 printk("ia64_handle_irq: DANGER: less than "
135 "1KB of free stack space!!\n"
136 "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
137 }
138 }
139 }
140 #endif /* IRQ_DEBUG */
142 /*
143 * Always set TPR to limit maximum interrupt nesting depth to
144 * 16 (without this, it would be ~240, which could easily lead
145 * to kernel stack overflows).
146 */
147 irq_enter();
148 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
149 ia64_srlz_d();
150 while (vector != IA64_SPURIOUS_INT_VECTOR) {
151 if (!IS_RESCHEDULE(vector)) {
152 ia64_setreg(_IA64_REG_CR_TPR, vector);
153 ia64_srlz_d();
155 __do_IRQ(local_vector_to_irq(vector), regs);
157 /*
158 * Disable interrupts and send EOI:
159 */
160 local_irq_disable();
161 ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
162 }
163 ia64_eoi();
164 vector = ia64_get_ivr();
165 }
166 /*
167 * This must be done *after* the ia64_eoi(). For example, the keyboard softirq
168 * handler needs to be able to wait for further keyboard interrupts, which can't
169 * come through until ia64_eoi() has been done.
170 */
171 irq_exit();
172 }
174 #ifdef CONFIG_HOTPLUG_CPU
175 /*
176 * This function emulates a interrupt processing when a cpu is about to be
177 * brought down.
178 */
179 void ia64_process_pending_intr(void)
180 {
181 ia64_vector vector;
182 unsigned long saved_tpr;
183 extern unsigned int vectors_in_migration[NR_IRQS];
185 vector = ia64_get_ivr();
187 irq_enter();
188 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
189 ia64_srlz_d();
191 /*
192 * Perform normal interrupt style processing
193 */
194 while (vector != IA64_SPURIOUS_INT_VECTOR) {
195 if (!IS_RESCHEDULE(vector)) {
196 ia64_setreg(_IA64_REG_CR_TPR, vector);
197 ia64_srlz_d();
199 /*
200 * Now try calling normal ia64_handle_irq as it would have got called
201 * from a real intr handler. Try passing null for pt_regs, hopefully
202 * it will work. I hope it works!.
203 * Probably could shared code.
204 */
205 vectors_in_migration[local_vector_to_irq(vector)]=0;
206 __do_IRQ(local_vector_to_irq(vector), NULL);
208 /*
209 * Disable interrupts and send EOI
210 */
211 local_irq_disable();
212 ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
213 }
214 ia64_eoi();
215 vector = ia64_get_ivr();
216 }
217 irq_exit();
218 }
219 #endif
222 #ifdef CONFIG_SMP
223 extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
225 static struct irqaction ipi_irqaction = {
226 .handler = handle_IPI,
227 .flags = SA_INTERRUPT,
228 .name = "IPI"
229 };
230 #endif
232 void
233 register_percpu_irq (ia64_vector vec, struct irqaction *action)
234 {
235 irq_desc_t *desc;
236 unsigned int irq;
238 for (irq = 0; irq < NR_IRQS; ++irq)
239 if (irq_to_vector(irq) == vec) {
240 desc = irq_descp(irq);
241 desc->status |= IRQ_PER_CPU;
242 desc->handler = &irq_type_ia64_lsapic;
243 if (action)
244 setup_irq(irq, action);
245 }
246 }
248 void __init
249 init_IRQ (void)
250 {
251 register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
252 #ifdef CONFIG_SMP
253 register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
254 #endif
255 #ifdef CONFIG_PERFMON
256 pfm_init_percpu();
257 #endif
258 platform_irq_init();
259 }
261 void
262 ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
263 {
264 void __iomem *ipi_addr;
265 unsigned long ipi_data;
266 unsigned long phys_cpu_id;
268 #ifdef CONFIG_SMP
269 phys_cpu_id = cpu_physical_id(cpu);
270 #else
271 phys_cpu_id = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
272 #endif
274 /*
275 * cpu number is in 8bit ID and 8bit EID
276 */
278 ipi_data = (delivery_mode << 8) | (vector & 0xff);
279 ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3));
281 writeq(ipi_data, ipi_addr);
282 }