ia64/xen-unstable

view xen/arch/x86/irq.c @ 5374:22e42640bcff

bitkeeper revision 1.1691.1.8 (42a6fb21d3oJwpLmOxa2jKHRJ-8fJg)

First phase of removing IRQ numbers from Xen (transitioning to
IRQ addressing by 'legacy ISA IRQ', 'interrupt vector', and
'I/O APIC address + pin' as appropriate). Overall plan is to move
I/O APIC parsing and setup out of Xen (so we start DOM0 in virtual wire
mode).
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Jun 08 14:05:21 2005 +0000 (2005-06-08)
parents fea2f7f8df31
children 0be846d7d261
line source
1 /******************************************************************************
2 * arch/x86/irq.c
3 *
4 * Portions of this file are:
5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
6 */
8 #include <xen/config.h>
9 #include <xen/errno.h>
10 #include <xen/event.h>
11 #include <xen/irq.h>
12 #include <xen/perfc.h>
13 #include <xen/sched.h>
14 #include <asm/current.h>
15 #include <asm/smpboot.h>
17 irq_desc_t irq_desc[NR_IRQS];
19 static void __do_IRQ_guest(int vector);
21 void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs) { }
23 static void enable_none(unsigned int irq) { }
24 static unsigned int startup_none(unsigned int irq) { return 0; }
25 static void disable_none(unsigned int irq) { }
26 static void ack_none(unsigned int irq)
27 {
28 printk("Unexpected IRQ trap at vector %02x.\n", irq);
29 ack_APIC_irq();
30 }
32 #define shutdown_none disable_none
33 #define end_none enable_none
35 struct hw_interrupt_type no_irq_type = {
36 "none",
37 startup_none,
38 shutdown_none,
39 enable_none,
40 disable_none,
41 ack_none,
42 end_none
43 };
45 atomic_t irq_err_count;
47 inline void disable_irq_nosync(unsigned int irq)
48 {
49 unsigned int vector = irq_to_vector(irq);
50 irq_desc_t *desc = &irq_desc[vector];
51 unsigned long flags;
53 spin_lock_irqsave(&desc->lock, flags);
55 if ( desc->depth++ == 0 )
56 {
57 desc->status |= IRQ_DISABLED;
58 desc->handler->disable(irq);
59 }
61 spin_unlock_irqrestore(&desc->lock, flags);
62 }
64 void enable_irq(unsigned int irq)
65 {
66 unsigned int vector = irq_to_vector(irq);
67 irq_desc_t *desc = &irq_desc[vector];
68 unsigned long flags;
70 spin_lock_irqsave(&desc->lock, flags);
72 if ( --desc->depth == 0 )
73 {
74 desc->status &= ~IRQ_DISABLED;
75 if ( (desc->status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING )
76 desc->status |= IRQ_REPLAY;
77 desc->handler->enable(irq);
78 }
80 spin_unlock_irqrestore(&desc->lock, flags);
81 }
83 asmlinkage void do_IRQ(struct cpu_user_regs *regs)
84 {
85 unsigned int vector = regs->entry_vector;
86 unsigned int irq = vector_to_irq(vector);
87 irq_desc_t *desc = &irq_desc[vector];
88 struct irqaction *action;
90 perfc_incrc(irqs);
92 spin_lock(&desc->lock);
93 desc->handler->ack(irq);
95 if ( likely(desc->status & IRQ_GUEST) )
96 {
97 __do_IRQ_guest(vector);
98 spin_unlock(&desc->lock);
99 return;
100 }
102 desc->status &= ~IRQ_REPLAY;
103 desc->status |= IRQ_PENDING;
105 /*
106 * Since we set PENDING, if another processor is handling a different
107 * instance of this same irq, the other processor will take care of it.
108 */
109 if ( desc->status & (IRQ_DISABLED | IRQ_INPROGRESS) )
110 goto out;
112 desc->status |= IRQ_INPROGRESS;
114 action = desc->action;
115 while ( desc->status & IRQ_PENDING )
116 {
117 desc->status &= ~IRQ_PENDING;
118 irq_enter(smp_processor_id());
119 spin_unlock_irq(&desc->lock);
120 action->handler(irq, action->dev_id, regs);
121 spin_lock_irq(&desc->lock);
122 irq_exit(smp_processor_id());
123 }
125 desc->status &= ~IRQ_INPROGRESS;
127 out:
128 desc->handler->end(irq);
129 spin_unlock(&desc->lock);
130 }
132 void free_irq(unsigned int irq)
133 {
134 unsigned int vector = irq_to_vector(irq);
135 irq_desc_t *desc = &irq_desc[vector];
136 unsigned long flags;
138 spin_lock_irqsave(&desc->lock,flags);
139 desc->action = NULL;
140 desc->depth = 1;
141 desc->status |= IRQ_DISABLED;
142 desc->handler->shutdown(irq);
143 spin_unlock_irqrestore(&desc->lock,flags);
145 /* Wait to make sure it's not being used on another CPU */
146 do { smp_mb(); } while ( desc->status & IRQ_INPROGRESS );
147 }
149 int setup_irq(unsigned int irq, struct irqaction *new)
150 {
151 unsigned int vector = irq_to_vector(irq);
152 irq_desc_t *desc = &irq_desc[vector];
153 unsigned long flags;
155 spin_lock_irqsave(&desc->lock,flags);
157 if ( desc->action != NULL )
158 {
159 spin_unlock_irqrestore(&desc->lock,flags);
160 return -EBUSY;
161 }
163 desc->action = new;
164 desc->depth = 0;
165 desc->status &= ~IRQ_DISABLED;
166 desc->handler->startup(irq);
168 spin_unlock_irqrestore(&desc->lock,flags);
170 return 0;
171 }
174 /*
175 * HANDLING OF GUEST-BOUND PHYSICAL IRQS
176 */
178 #define IRQ_MAX_GUESTS 7
179 typedef struct {
180 u8 nr_guests;
181 u8 in_flight;
182 u8 shareable;
183 struct domain *guest[IRQ_MAX_GUESTS];
184 } irq_guest_action_t;
186 static void __do_IRQ_guest(int vector)
187 {
188 unsigned int irq = vector_to_irq(vector);
189 irq_desc_t *desc = &irq_desc[vector];
190 irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
191 struct domain *d;
192 int i;
194 for ( i = 0; i < action->nr_guests; i++ )
195 {
196 d = action->guest[i];
197 if ( !test_and_set_bit(irq, &d->pirq_mask) )
198 action->in_flight++;
199 send_guest_pirq(d, irq);
200 }
201 }
203 int pirq_guest_unmask(struct domain *d)
204 {
205 irq_desc_t *desc;
206 unsigned int i, j, pirq;
207 u32 m;
208 shared_info_t *s = d->shared_info;
210 for ( i = 0; i < ARRAY_SIZE(d->pirq_mask); i++ )
211 {
212 m = d->pirq_mask[i];
213 while ( m != 0 )
214 {
215 j = find_first_set_bit(m);
216 m &= ~(1 << j);
217 pirq = (i << 5) + j;
218 desc = &irq_desc[irq_to_vector(pirq)];
219 spin_lock_irq(&desc->lock);
220 if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) &&
221 test_and_clear_bit(pirq, &d->pirq_mask) &&
222 (--((irq_guest_action_t *)desc->action)->in_flight == 0) )
223 desc->handler->end(pirq);
224 spin_unlock_irq(&desc->lock);
225 }
226 }
228 return 0;
229 }
231 int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
232 {
233 unsigned int vector = irq_to_vector(irq);
234 struct domain *d = v->domain;
235 irq_desc_t *desc = &irq_desc[vector];
236 irq_guest_action_t *action;
237 unsigned long flags;
238 int rc = 0;
239 cpumask_t cpumask = CPU_MASK_NONE;
241 if ( !IS_CAPABLE_PHYSDEV(d) )
242 return -EPERM;
244 if ( vector == 0 )
245 return -EBUSY;
247 spin_lock_irqsave(&desc->lock, flags);
249 action = (irq_guest_action_t *)desc->action;
251 if ( !(desc->status & IRQ_GUEST) )
252 {
253 if ( desc->action != NULL )
254 {
255 DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n",
256 irq, desc->action->name);
257 rc = -EBUSY;
258 goto out;
259 }
261 action = xmalloc(irq_guest_action_t);
262 if ( (desc->action = (struct irqaction *)action) == NULL )
263 {
264 DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq);
265 rc = -ENOMEM;
266 goto out;
267 }
269 action->nr_guests = 0;
270 action->in_flight = 0;
271 action->shareable = will_share;
273 desc->depth = 0;
274 desc->status |= IRQ_GUEST;
275 desc->status &= ~IRQ_DISABLED;
276 desc->handler->startup(irq);
278 /* Attempt to bind the interrupt target to the correct CPU. */
279 cpu_set(v->processor, cpumask);
280 if ( desc->handler->set_affinity != NULL )
281 desc->handler->set_affinity(irq, cpumask);
282 }
283 else if ( !will_share || !action->shareable )
284 {
285 DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n",
286 irq);
287 rc = -EBUSY;
288 goto out;
289 }
291 if ( action->nr_guests == IRQ_MAX_GUESTS )
292 {
293 DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq);
294 rc = -EBUSY;
295 goto out;
296 }
298 action->guest[action->nr_guests++] = v->domain;
300 out:
301 spin_unlock_irqrestore(&desc->lock, flags);
302 return rc;
303 }
305 int pirq_guest_unbind(struct domain *d, int irq)
306 {
307 unsigned int vector = irq_to_vector(irq);
308 irq_desc_t *desc = &irq_desc[vector];
309 irq_guest_action_t *action;
310 unsigned long flags;
311 int i;
313 BUG_ON(vector == 0);
315 spin_lock_irqsave(&desc->lock, flags);
317 action = (irq_guest_action_t *)desc->action;
319 if ( test_and_clear_bit(irq, &d->pirq_mask) &&
320 (--action->in_flight == 0) )
321 desc->handler->end(irq);
323 if ( action->nr_guests == 1 )
324 {
325 desc->action = NULL;
326 xfree(action);
327 desc->depth = 1;
328 desc->status |= IRQ_DISABLED;
329 desc->status &= ~IRQ_GUEST;
330 desc->handler->shutdown(irq);
331 }
332 else
333 {
334 i = 0;
335 while ( action->guest[i] && (action->guest[i] != d) )
336 i++;
337 memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
338 action->nr_guests--;
339 }
341 spin_unlock_irqrestore(&desc->lock, flags);
342 return 0;
343 }