ia64/xen-unstable

view xen/arch/ia64/linux-xen/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 db2bd8169e9b
children 811c02dbe595
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 #ifdef XEN
64 unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
65 #else
66 static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
67 #endif
69 int
70 assign_irq_vector (int irq)
71 {
72 int pos, vector;
73 again:
74 pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
75 vector = IA64_FIRST_DEVICE_VECTOR + pos;
76 if (vector > IA64_LAST_DEVICE_VECTOR)
77 return -ENOSPC;
78 if (test_and_set_bit(pos, ia64_vector_mask))
79 goto again;
80 return vector;
81 }
83 void
84 free_irq_vector (int vector)
85 {
86 int pos;
88 if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
89 return;
91 pos = vector - IA64_FIRST_DEVICE_VECTOR;
92 if (!test_and_clear_bit(pos, ia64_vector_mask))
93 printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
94 }
96 #ifdef CONFIG_SMP
97 # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
98 #else
99 # define IS_RESCHEDULE(vec) (0)
100 #endif
101 /*
102 * That's where the IVT branches when we get an external
103 * interrupt. This branches to the correct hardware IRQ handler via
104 * function ptr.
105 */
106 void
107 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
108 {
109 unsigned long saved_tpr;
111 #if IRQ_DEBUG
112 #ifdef XEN
113 xen_debug_irq(vector, regs);
114 #endif
115 {
116 unsigned long bsp, sp;
118 /*
119 * Note: if the interrupt happened while executing in
120 * the context switch routine (ia64_switch_to), we may
121 * get a spurious stack overflow here. This is
122 * because the register and the memory stack are not
123 * switched atomically.
124 */
125 bsp = ia64_getreg(_IA64_REG_AR_BSP);
126 sp = ia64_getreg(_IA64_REG_SP);
128 if ((sp - bsp) < 1024) {
129 static unsigned char count;
130 static long last_time;
132 if (jiffies - last_time > 5*HZ)
133 count = 0;
134 if (++count < 5) {
135 last_time = jiffies;
136 printk("ia64_handle_irq: DANGER: less than "
137 "1KB of free stack space!!\n"
138 "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
139 }
140 }
141 }
142 #endif /* IRQ_DEBUG */
144 /*
145 * Always set TPR to limit maximum interrupt nesting depth to
146 * 16 (without this, it would be ~240, which could easily lead
147 * to kernel stack overflows).
148 */
149 irq_enter();
150 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
151 ia64_srlz_d();
152 while (vector != IA64_SPURIOUS_INT_VECTOR) {
153 if (!IS_RESCHEDULE(vector)) {
154 ia64_setreg(_IA64_REG_CR_TPR, vector);
155 ia64_srlz_d();
157 __do_IRQ(local_vector_to_irq(vector), regs);
159 /*
160 * Disable interrupts and send EOI:
161 */
162 local_irq_disable();
163 ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
164 }
165 ia64_eoi();
166 vector = ia64_get_ivr();
167 }
168 /*
169 * This must be done *after* the ia64_eoi(). For example, the keyboard softirq
170 * handler needs to be able to wait for further keyboard interrupts, which can't
171 * come through until ia64_eoi() has been done.
172 */
173 irq_exit();
174 }
176 #ifdef CONFIG_HOTPLUG_CPU
177 /*
178 * This function emulates a interrupt processing when a cpu is about to be
179 * brought down.
180 */
181 void ia64_process_pending_intr(void)
182 {
183 ia64_vector vector;
184 unsigned long saved_tpr;
185 extern unsigned int vectors_in_migration[NR_IRQS];
187 vector = ia64_get_ivr();
189 irq_enter();
190 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
191 ia64_srlz_d();
193 /*
194 * Perform normal interrupt style processing
195 */
196 while (vector != IA64_SPURIOUS_INT_VECTOR) {
197 if (!IS_RESCHEDULE(vector)) {
198 ia64_setreg(_IA64_REG_CR_TPR, vector);
199 ia64_srlz_d();
201 /*
202 * Now try calling normal ia64_handle_irq as it would have got called
203 * from a real intr handler. Try passing null for pt_regs, hopefully
204 * it will work. I hope it works!.
205 * Probably could shared code.
206 */
207 vectors_in_migration[local_vector_to_irq(vector)]=0;
208 __do_IRQ(local_vector_to_irq(vector), NULL);
210 /*
211 * Disable interrupts and send EOI
212 */
213 local_irq_disable();
214 ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
215 }
216 ia64_eoi();
217 vector = ia64_get_ivr();
218 }
219 irq_exit();
220 }
221 #endif
224 #ifdef CONFIG_SMP
225 extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
227 static struct irqaction ipi_irqaction = {
228 .handler = handle_IPI,
229 #ifndef XEN
230 .flags = SA_INTERRUPT,
231 #endif
232 .name = "IPI"
233 };
234 #endif
236 void
237 register_percpu_irq (ia64_vector vec, struct irqaction *action)
238 {
239 irq_desc_t *desc;
240 unsigned int irq;
242 for (irq = 0; irq < NR_IRQS; ++irq)
243 if (irq_to_vector(irq) == vec) {
244 desc = irq_descp(irq);
245 desc->status |= IRQ_PER_CPU;
246 desc->handler = &irq_type_ia64_lsapic;
247 if (action)
248 setup_irq(irq, action);
249 }
250 }
252 void __init
253 init_IRQ (void)
254 {
255 register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
256 #ifdef CONFIG_SMP
257 register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
258 #endif
259 #ifdef CONFIG_PERFMON
260 pfm_init_percpu();
261 #endif
262 platform_irq_init();
263 }
265 void
266 ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
267 {
268 void __iomem *ipi_addr;
269 unsigned long ipi_data;
270 unsigned long phys_cpu_id;
272 #ifdef CONFIG_SMP
273 phys_cpu_id = cpu_physical_id(cpu);
274 #else
275 phys_cpu_id = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
276 #endif
278 /*
279 * cpu number is in 8bit ID and 8bit EID
280 */
282 ipi_data = (delivery_mode << 8) | (vector & 0xff);
283 ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3));
285 #ifdef XEN
286 //printf ("send_ipi to %d (%x)\n", cpu, phys_cpu_id);
287 #endif
288 writeq(ipi_data, ipi_addr);
289 }