xen-vtx-unstable

view xen/arch/x86/irq.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents a83ac0806d6b
children
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/init.h>
10 #include <xen/errno.h>
11 #include <xen/event.h>
12 #include <xen/irq.h>
13 #include <xen/perfc.h>
14 #include <xen/sched.h>
15 #include <asm/current.h>
16 #include <asm/smpboot.h>
18 /* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
19 int opt_noirqbalance = 0;
20 boolean_param("noirqbalance", opt_noirqbalance);
22 irq_desc_t irq_desc[NR_IRQS];
24 static void __do_IRQ_guest(int vector);
26 void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs) { }
28 static void enable_none(unsigned int vector) { }
29 static unsigned int startup_none(unsigned int vector) { return 0; }
30 static void disable_none(unsigned int vector) { }
31 static void ack_none(unsigned int vector)
32 {
33 printk("Unexpected IRQ trap at vector %02x.\n", vector);
34 ack_APIC_irq();
35 }
37 #define shutdown_none disable_none
38 #define end_none enable_none
40 struct hw_interrupt_type no_irq_type = {
41 "none",
42 startup_none,
43 shutdown_none,
44 enable_none,
45 disable_none,
46 ack_none,
47 end_none
48 };
50 atomic_t irq_err_count;
52 asmlinkage void do_IRQ(struct cpu_user_regs *regs)
53 {
54 unsigned int vector = regs->entry_vector;
55 irq_desc_t *desc = &irq_desc[vector];
56 struct irqaction *action;
58 perfc_incrc(irqs);
60 spin_lock(&desc->lock);
61 desc->handler->ack(vector);
63 if ( likely(desc->status & IRQ_GUEST) )
64 {
65 __do_IRQ_guest(vector);
66 spin_unlock(&desc->lock);
67 return;
68 }
70 desc->status &= ~IRQ_REPLAY;
71 desc->status |= IRQ_PENDING;
73 /*
74 * Since we set PENDING, if another processor is handling a different
75 * instance of this same irq, the other processor will take care of it.
76 */
77 if ( desc->status & (IRQ_DISABLED | IRQ_INPROGRESS) )
78 goto out;
80 desc->status |= IRQ_INPROGRESS;
82 action = desc->action;
83 while ( desc->status & IRQ_PENDING )
84 {
85 desc->status &= ~IRQ_PENDING;
86 irq_enter(smp_processor_id());
87 spin_unlock_irq(&desc->lock);
88 action->handler(vector_to_irq(vector), action->dev_id, regs);
89 spin_lock_irq(&desc->lock);
90 irq_exit(smp_processor_id());
91 }
93 desc->status &= ~IRQ_INPROGRESS;
95 out:
96 desc->handler->end(vector);
97 spin_unlock(&desc->lock);
98 }
100 void free_irq(unsigned int irq)
101 {
102 unsigned int vector = irq_to_vector(irq);
103 irq_desc_t *desc = &irq_desc[vector];
104 unsigned long flags;
106 spin_lock_irqsave(&desc->lock,flags);
107 desc->action = NULL;
108 desc->depth = 1;
109 desc->status |= IRQ_DISABLED;
110 desc->handler->shutdown(irq);
111 spin_unlock_irqrestore(&desc->lock,flags);
113 /* Wait to make sure it's not being used on another CPU */
114 do { smp_mb(); } while ( desc->status & IRQ_INPROGRESS );
115 }
117 int setup_irq(unsigned int irq, struct irqaction *new)
118 {
119 unsigned int vector = irq_to_vector(irq);
120 irq_desc_t *desc = &irq_desc[vector];
121 unsigned long flags;
123 spin_lock_irqsave(&desc->lock,flags);
125 if ( desc->action != NULL )
126 {
127 spin_unlock_irqrestore(&desc->lock,flags);
128 return -EBUSY;
129 }
131 desc->action = new;
132 desc->depth = 0;
133 desc->status &= ~IRQ_DISABLED;
134 desc->handler->startup(vector);
136 spin_unlock_irqrestore(&desc->lock,flags);
138 return 0;
139 }
142 /*
143 * HANDLING OF GUEST-BOUND PHYSICAL IRQS
144 */
146 #define IRQ_MAX_GUESTS 7
147 typedef struct {
148 u8 nr_guests;
149 u8 in_flight;
150 u8 shareable;
151 struct domain *guest[IRQ_MAX_GUESTS];
152 } irq_guest_action_t;
154 static void __do_IRQ_guest(int vector)
155 {
156 unsigned int irq = vector_to_irq(vector);
157 irq_desc_t *desc = &irq_desc[vector];
158 irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
159 struct domain *d;
160 int i;
162 for ( i = 0; i < action->nr_guests; i++ )
163 {
164 d = action->guest[i];
165 if ( !test_and_set_bit(irq, &d->pirq_mask) )
166 action->in_flight++;
167 send_guest_pirq(d, irq);
168 }
169 }
171 int pirq_guest_unmask(struct domain *d)
172 {
173 irq_desc_t *desc;
174 unsigned int i, j, pirq;
175 u32 m;
176 shared_info_t *s = d->shared_info;
178 for ( i = 0; i < ARRAY_SIZE(d->pirq_mask); i++ )
179 {
180 m = d->pirq_mask[i];
181 while ( m != 0 )
182 {
183 j = find_first_set_bit(m);
184 m &= ~(1 << j);
185 pirq = (i << 5) + j;
186 desc = &irq_desc[irq_to_vector(pirq)];
187 spin_lock_irq(&desc->lock);
188 if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) &&
189 test_and_clear_bit(pirq, &d->pirq_mask) &&
190 (--((irq_guest_action_t *)desc->action)->in_flight == 0) )
191 desc->handler->end(irq_to_vector(pirq));
192 spin_unlock_irq(&desc->lock);
193 }
194 }
196 return 0;
197 }
199 int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
200 {
201 unsigned int vector = irq_to_vector(irq);
202 struct domain *d = v->domain;
203 irq_desc_t *desc = &irq_desc[vector];
204 irq_guest_action_t *action;
205 unsigned long flags;
206 int rc = 0;
207 cpumask_t cpumask = CPU_MASK_NONE;
209 if ( !IS_CAPABLE_PHYSDEV(d) )
210 return -EPERM;
212 if ( vector == 0 )
213 return -EBUSY;
215 spin_lock_irqsave(&desc->lock, flags);
217 action = (irq_guest_action_t *)desc->action;
219 if ( !(desc->status & IRQ_GUEST) )
220 {
221 if ( desc->action != NULL )
222 {
223 DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n",
224 irq, desc->action->name);
225 rc = -EBUSY;
226 goto out;
227 }
229 action = xmalloc(irq_guest_action_t);
230 if ( (desc->action = (struct irqaction *)action) == NULL )
231 {
232 DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq);
233 rc = -ENOMEM;
234 goto out;
235 }
237 action->nr_guests = 0;
238 action->in_flight = 0;
239 action->shareable = will_share;
241 desc->depth = 0;
242 desc->status |= IRQ_GUEST;
243 desc->status &= ~IRQ_DISABLED;
244 desc->handler->startup(vector);
246 /* Attempt to bind the interrupt target to the correct CPU. */
247 cpu_set(v->processor, cpumask);
248 if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )
249 desc->handler->set_affinity(vector, cpumask);
250 }
251 else if ( !will_share || !action->shareable )
252 {
253 DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n",
254 irq);
255 rc = -EBUSY;
256 goto out;
257 }
259 if ( action->nr_guests == IRQ_MAX_GUESTS )
260 {
261 DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq);
262 rc = -EBUSY;
263 goto out;
264 }
266 action->guest[action->nr_guests++] = v->domain;
268 out:
269 spin_unlock_irqrestore(&desc->lock, flags);
270 return rc;
271 }
273 int pirq_guest_unbind(struct domain *d, int irq)
274 {
275 unsigned int vector = irq_to_vector(irq);
276 irq_desc_t *desc = &irq_desc[vector];
277 irq_guest_action_t *action;
278 unsigned long flags;
279 int i;
281 BUG_ON(vector == 0);
283 spin_lock_irqsave(&desc->lock, flags);
285 action = (irq_guest_action_t *)desc->action;
287 if ( test_and_clear_bit(irq, &d->pirq_mask) &&
288 (--action->in_flight == 0) )
289 desc->handler->end(vector);
291 if ( action->nr_guests == 1 )
292 {
293 desc->action = NULL;
294 xfree(action);
295 desc->depth = 1;
296 desc->status |= IRQ_DISABLED;
297 desc->status &= ~IRQ_GUEST;
298 desc->handler->shutdown(vector);
299 }
300 else
301 {
302 i = 0;
303 while ( action->guest[i] && (action->guest[i] != d) )
304 i++;
305 memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
306 action->nr_guests--;
307 }
309 spin_unlock_irqrestore(&desc->lock, flags);
310 return 0;
311 }