debuggers.hg

view xen/arch/x86/irq.c @ 3659:bf2c38625b39

bitkeeper revision 1.1159.212.72 (42011b79Y7C9nEKFZ5pdQXwp8jC9hw)

More x86/64. Now boot secondary CPUs, but I seem to have problems
executing IRET, so interrupts are fatal.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Wed Feb 02 18:27:05 2005 +0000 (2005-02-02)
parents 0ef6e8e6e85d
children bbe8541361dd
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/smpboot.h>
16 irq_desc_t irq_desc[NR_IRQS];
18 static void __do_IRQ_guest(int irq);
20 void no_action(int cpl, void *dev_id, struct xen_regs *regs) { }
22 static void enable_none(unsigned int irq) { }
23 static unsigned int startup_none(unsigned int irq) { return 0; }
24 static void disable_none(unsigned int irq) { }
25 static void ack_none(unsigned int irq)
26 {
27 printk("Unexpected IRQ trap at vector %02x.\n", irq);
28 ack_APIC_irq();
29 }
31 #define shutdown_none disable_none
32 #define end_none enable_none
34 struct hw_interrupt_type no_irq_type = {
35 "none",
36 startup_none,
37 shutdown_none,
38 enable_none,
39 disable_none,
40 ack_none,
41 end_none
42 };
44 atomic_t irq_err_count;
45 atomic_t irq_mis_count;
47 inline void disable_irq_nosync(unsigned int irq)
48 {
49 irq_desc_t *desc = &irq_desc[irq];
50 unsigned long flags;
52 spin_lock_irqsave(&desc->lock, flags);
54 if ( desc->depth++ == 0 )
55 {
56 desc->status |= IRQ_DISABLED;
57 desc->handler->disable(irq);
58 }
60 spin_unlock_irqrestore(&desc->lock, flags);
61 }
63 void disable_irq(unsigned int irq)
64 {
65 disable_irq_nosync(irq);
66 do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS );
67 }
69 void enable_irq(unsigned int irq)
70 {
71 irq_desc_t *desc = &irq_desc[irq];
72 unsigned long flags;
74 spin_lock_irqsave(&desc->lock, flags);
76 if ( --desc->depth == 0 )
77 {
78 desc->status &= ~IRQ_DISABLED;
79 if ( (desc->status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING )
80 {
81 desc->status |= IRQ_REPLAY;
82 hw_resend_irq(desc->handler,irq);
83 }
84 desc->handler->enable(irq);
85 }
87 spin_unlock_irqrestore(&desc->lock, flags);
88 }
90 asmlinkage void do_IRQ(struct xen_regs *regs)
91 {
92 unsigned int irq = regs->entry_vector;
93 irq_desc_t *desc = &irq_desc[irq];
94 struct irqaction *action;
96 perfc_incrc(irqs);
98 spin_lock(&desc->lock);
99 desc->handler->ack(irq);
101 if ( likely(desc->status & IRQ_GUEST) )
102 {
103 __do_IRQ_guest(irq);
104 spin_unlock(&desc->lock);
105 return;
106 }
108 desc->status &= ~IRQ_REPLAY;
109 desc->status |= IRQ_PENDING;
111 /*
112 * Since we set PENDING, if another processor is handling a different
113 * instance of this same irq, the other processor will take care of it.
114 */
115 if ( desc->status & (IRQ_DISABLED | IRQ_INPROGRESS) )
116 goto out;
118 desc->status |= IRQ_INPROGRESS;
120 action = desc->action;
121 while ( desc->status & IRQ_PENDING )
122 {
123 desc->status &= ~IRQ_PENDING;
124 irq_enter(smp_processor_id(), irq);
125 spin_unlock_irq(&desc->lock);
126 action->handler(irq, action->dev_id, regs);
127 spin_lock_irq(&desc->lock);
128 irq_exit(smp_processor_id(), irq);
129 }
131 desc->status &= ~IRQ_INPROGRESS;
133 out:
134 desc->handler->end(irq);
135 spin_unlock(&desc->lock);
136 }
138 void free_irq(unsigned int irq)
139 {
140 irq_desc_t *desc = &irq_desc[irq];
141 unsigned long flags;
143 spin_lock_irqsave(&desc->lock,flags);
144 desc->action = NULL;
145 desc->depth = 1;
146 desc->status |= IRQ_DISABLED;
147 desc->handler->shutdown(irq);
148 spin_unlock_irqrestore(&desc->lock,flags);
150 /* Wait to make sure it's not being used on another CPU */
151 do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS );
152 }
154 int setup_irq(unsigned int irq, struct irqaction *new)
155 {
156 irq_desc_t *desc = &irq_desc[irq];
157 unsigned long flags;
159 spin_lock_irqsave(&desc->lock,flags);
161 if ( desc->action != NULL )
162 {
163 spin_unlock_irqrestore(&desc->lock,flags);
164 return -EBUSY;
165 }
167 desc->action = new;
168 desc->depth = 0;
169 desc->status &= ~IRQ_DISABLED;
170 desc->handler->startup(irq);
172 spin_unlock_irqrestore(&desc->lock,flags);
174 return 0;
175 }
178 /*
179 * HANDLING OF GUEST-BOUND PHYSICAL IRQS
180 */
182 #define IRQ_MAX_GUESTS 7
183 typedef struct {
184 u8 nr_guests;
185 u8 in_flight;
186 u8 shareable;
187 struct exec_domain *guest[IRQ_MAX_GUESTS];
188 } irq_guest_action_t;
190 static void __do_IRQ_guest(int irq)
191 {
192 irq_desc_t *desc = &irq_desc[irq];
193 irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
194 struct exec_domain *ed;
195 int i;
197 for ( i = 0; i < action->nr_guests; i++ )
198 {
199 ed = action->guest[i];
200 if ( !test_and_set_bit(irq, &ed->domain->pirq_mask) )
201 action->in_flight++;
202 send_guest_pirq(ed, irq);
203 }
204 }
206 int pirq_guest_unmask(struct domain *d)
207 {
208 irq_desc_t *desc;
209 unsigned int i, j, pirq;
210 u32 m;
211 shared_info_t *s = d->shared_info;
213 for ( i = 0; i < ARRAY_SIZE(d->pirq_mask); i++ )
214 {
215 m = d->pirq_mask[i];
216 while ( m != 0 )
217 {
218 j = find_first_set_bit(m);
219 m &= ~(1 << j);
220 pirq = (i << 5) + j;
221 desc = &irq_desc[pirq];
222 spin_lock_irq(&desc->lock);
223 if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) &&
224 test_and_clear_bit(pirq, &d->pirq_mask) &&
225 (--((irq_guest_action_t *)desc->action)->in_flight == 0) )
226 desc->handler->end(pirq);
227 spin_unlock_irq(&desc->lock);
228 }
229 }
231 return 0;
232 }
234 int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share)
235 {
236 struct domain *d = ed->domain;
237 irq_desc_t *desc = &irq_desc[irq];
238 irq_guest_action_t *action;
239 unsigned long flags;
240 int rc = 0;
242 if ( !IS_CAPABLE_PHYSDEV(d) )
243 return -EPERM;
245 spin_lock_irqsave(&desc->lock, flags);
247 action = (irq_guest_action_t *)desc->action;
249 if ( !(desc->status & IRQ_GUEST) )
250 {
251 if ( desc->action != NULL )
252 {
253 DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n",
254 irq, desc->action->name);
255 rc = -EBUSY;
256 goto out;
257 }
259 action = xmalloc(irq_guest_action_t);
260 if ( (desc->action = (struct irqaction *)action) == NULL )
261 {
262 DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq);
263 rc = -ENOMEM;
264 goto out;
265 }
267 action->nr_guests = 0;
268 action->in_flight = 0;
269 action->shareable = will_share;
271 desc->depth = 0;
272 desc->status |= IRQ_GUEST;
273 desc->status &= ~IRQ_DISABLED;
274 desc->handler->startup(irq);
276 /* Attempt to bind the interrupt target to the correct CPU. */
277 if ( desc->handler->set_affinity != NULL )
278 desc->handler->set_affinity(
279 irq, apicid_to_phys_cpu_present(ed->processor));
280 }
281 else if ( !will_share || !action->shareable )
282 {
283 DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n",
284 irq);
285 rc = -EBUSY;
286 goto out;
287 }
289 if ( action->nr_guests == IRQ_MAX_GUESTS )
290 {
291 DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq);
292 rc = -EBUSY;
293 goto out;
294 }
296 action->guest[action->nr_guests++] = ed;
298 out:
299 spin_unlock_irqrestore(&desc->lock, flags);
300 return rc;
301 }
303 int pirq_guest_unbind(struct domain *d, int irq)
304 {
305 irq_desc_t *desc = &irq_desc[irq];
306 irq_guest_action_t *action;
307 unsigned long flags;
308 int i;
310 spin_lock_irqsave(&desc->lock, flags);
312 action = (irq_guest_action_t *)desc->action;
314 if ( test_and_clear_bit(irq, &d->pirq_mask) &&
315 (--action->in_flight == 0) )
316 desc->handler->end(irq);
318 if ( action->nr_guests == 1 )
319 {
320 desc->action = NULL;
321 xfree(action);
322 desc->depth = 1;
323 desc->status |= IRQ_DISABLED;
324 desc->status &= ~IRQ_GUEST;
325 desc->handler->shutdown(irq);
326 }
327 else
328 {
329 i = 0;
330 while ( action->guest[i] && action->guest[i]->domain != d )
331 i++;
332 memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
333 action->nr_guests--;
334 }
336 spin_unlock_irqrestore(&desc->lock, flags);
337 return 0;
338 }
340 int pirq_guest_bindable(int irq, int will_share)
341 {
342 irq_desc_t *desc = &irq_desc[irq];
343 irq_guest_action_t *action;
344 unsigned long flags;
345 int okay;
347 spin_lock_irqsave(&desc->lock, flags);
349 action = (irq_guest_action_t *)desc->action;
351 /*
352 * To be bindable the IRQ must either be not currently bound (1), or
353 * it must be shareable (2) and not at its share limit (3).
354 */
355 okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */
356 (action->shareable && will_share && /* 2 */
357 (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */
359 spin_unlock_irqrestore(&desc->lock, flags);
360 return okay;
361 }