debuggers.hg
annotate xen/arch/x86/irq.c @ 3658:0ef6e8e6e85d
bitkeeper revision 1.1159.212.71 (4200f0afX_JumfbEHQex6TdFENULMQ)
Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
author | iap10@labyrinth.cl.cam.ac.uk |
---|---|
date | Wed Feb 02 15:24:31 2005 +0000 (2005-02-02) |
parents | 75f82adfcc90 beb0887c54bc |
children | bf2c38625b39 |
rev | line source |
---|---|
kaf24@1535 | 1 /****************************************************************************** |
kaf24@1535 | 2 * arch/x86/irq.c |
kaf24@1535 | 3 * |
kaf24@1535 | 4 * Portions of this file are: |
kaf24@1535 | 5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar |
kaf24@1490 | 6 */ |
kaf24@1490 | 7 |
kaf24@1490 | 8 #include <xen/config.h> |
kaf24@1490 | 9 #include <xen/errno.h> |
kaf24@1535 | 10 #include <xen/event.h> |
kaf24@1490 | 11 #include <xen/irq.h> |
kaf24@1490 | 12 #include <xen/perfc.h> |
kaf24@1535 | 13 #include <xen/sched.h> |
kaf24@1490 | 14 #include <asm/smpboot.h> |
kaf24@1490 | 15 |
kaf24@3113 | 16 irq_desc_t irq_desc[NR_IRQS]; |
kaf24@1490 | 17 |
kaf24@1490 | 18 static void __do_IRQ_guest(int irq); |
kaf24@1490 | 19 |
ach61@2843 | 20 void no_action(int cpl, void *dev_id, struct xen_regs *regs) { } |
kaf24@1490 | 21 |
kaf24@1490 | 22 static void enable_none(unsigned int irq) { } |
kaf24@1490 | 23 static unsigned int startup_none(unsigned int irq) { return 0; } |
kaf24@1490 | 24 static void disable_none(unsigned int irq) { } |
kaf24@1490 | 25 static void ack_none(unsigned int irq) |
kaf24@1490 | 26 { |
kaf24@1535 | 27 printk("Unexpected IRQ trap at vector %02x.\n", irq); |
kaf24@1490 | 28 ack_APIC_irq(); |
kaf24@1490 | 29 } |
kaf24@1490 | 30 |
kaf24@1490 | 31 #define shutdown_none disable_none |
kaf24@1490 | 32 #define end_none enable_none |
kaf24@1490 | 33 |
kaf24@1490 | 34 struct hw_interrupt_type no_irq_type = { |
kaf24@1490 | 35 "none", |
kaf24@1490 | 36 startup_none, |
kaf24@1490 | 37 shutdown_none, |
kaf24@1490 | 38 enable_none, |
kaf24@1490 | 39 disable_none, |
kaf24@1490 | 40 ack_none, |
kaf24@1490 | 41 end_none |
kaf24@1490 | 42 }; |
kaf24@1490 | 43 |
kaf24@1490 | 44 atomic_t irq_err_count; |
kaf24@1490 | 45 atomic_t irq_mis_count; |
kaf24@1490 | 46 |
kaf24@1490 | 47 inline void disable_irq_nosync(unsigned int irq) |
kaf24@1490 | 48 { |
kaf24@1535 | 49 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1490 | 50 unsigned long flags; |
kaf24@1490 | 51 |
kaf24@1490 | 52 spin_lock_irqsave(&desc->lock, flags); |
kaf24@1535 | 53 |
kaf24@1535 | 54 if ( desc->depth++ == 0 ) |
kaf24@1535 | 55 { |
kaf24@1490 | 56 desc->status |= IRQ_DISABLED; |
kaf24@1490 | 57 desc->handler->disable(irq); |
kaf24@1490 | 58 } |
kaf24@1535 | 59 |
kaf24@1490 | 60 spin_unlock_irqrestore(&desc->lock, flags); |
kaf24@1490 | 61 } |
kaf24@1490 | 62 |
kaf24@1490 | 63 void disable_irq(unsigned int irq) |
kaf24@1490 | 64 { |
kaf24@1490 | 65 disable_irq_nosync(irq); |
kaf24@1535 | 66 do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS ); |
kaf24@1490 | 67 } |
kaf24@1490 | 68 |
kaf24@1490 | 69 void enable_irq(unsigned int irq) |
kaf24@1490 | 70 { |
kaf24@1535 | 71 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1490 | 72 unsigned long flags; |
kaf24@1490 | 73 |
kaf24@1490 | 74 spin_lock_irqsave(&desc->lock, flags); |
kaf24@1535 | 75 |
kaf24@1535 | 76 if ( --desc->depth == 0 ) |
kaf24@1535 | 77 { |
kaf24@1535 | 78 desc->status &= ~IRQ_DISABLED; |
kaf24@1535 | 79 if ( (desc->status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING ) |
kaf24@1535 | 80 { |
kaf24@1535 | 81 desc->status |= IRQ_REPLAY; |
kaf24@1490 | 82 hw_resend_irq(desc->handler,irq); |
kaf24@1490 | 83 } |
kaf24@1490 | 84 desc->handler->enable(irq); |
kaf24@1490 | 85 } |
kaf24@1535 | 86 |
kaf24@1490 | 87 spin_unlock_irqrestore(&desc->lock, flags); |
kaf24@1490 | 88 } |
kaf24@1490 | 89 |
ach61@2843 | 90 asmlinkage void do_IRQ(struct xen_regs regs) |
kaf24@1490 | 91 { |
kaf24@1710 | 92 #if defined(__i386__) |
kaf24@3127 | 93 unsigned int irq = regs.entry_vector; |
kaf24@1710 | 94 #else |
kaf24@1710 | 95 unsigned int irq = 0; /* XXX */ |
kaf24@1710 | 96 #endif |
kaf24@1535 | 97 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1535 | 98 struct irqaction *action; |
kaf24@1490 | 99 |
kaf24@1535 | 100 perfc_incrc(irqs); |
kaf24@1490 | 101 |
kaf24@1490 | 102 spin_lock(&desc->lock); |
kaf24@1490 | 103 desc->handler->ack(irq); |
kaf24@1490 | 104 |
kaf24@1535 | 105 if ( likely(desc->status & IRQ_GUEST) ) |
kaf24@1490 | 106 { |
kaf24@1490 | 107 __do_IRQ_guest(irq); |
kaf24@1490 | 108 spin_unlock(&desc->lock); |
kaf24@1535 | 109 return; |
kaf24@1490 | 110 } |
kaf24@1490 | 111 |
kaf24@1535 | 112 desc->status &= ~IRQ_REPLAY; |
kaf24@1535 | 113 desc->status |= IRQ_PENDING; |
kaf24@1490 | 114 |
kaf24@1490 | 115 /* |
kaf24@1535 | 116 * Since we set PENDING, if another processor is handling a different |
kaf24@1535 | 117 * instance of this same irq, the other processor will take care of it. |
kaf24@1490 | 118 */ |
kaf24@1535 | 119 if ( desc->status & (IRQ_DISABLED | IRQ_INPROGRESS) ) |
kaf24@1535 | 120 goto out; |
kaf24@1535 | 121 |
kaf24@1535 | 122 desc->status |= IRQ_INPROGRESS; |
kaf24@1535 | 123 |
kaf24@1535 | 124 action = desc->action; |
kaf24@1535 | 125 while ( desc->status & IRQ_PENDING ) |
kaf24@1535 | 126 { |
kaf24@1490 | 127 desc->status &= ~IRQ_PENDING; |
kaf24@1535 | 128 irq_enter(smp_processor_id(), irq); |
kaf24@1535 | 129 spin_unlock_irq(&desc->lock); |
kaf24@1535 | 130 action->handler(irq, action->dev_id, ®s); |
kaf24@1535 | 131 spin_lock_irq(&desc->lock); |
kaf24@1535 | 132 irq_exit(smp_processor_id(), irq); |
kaf24@1490 | 133 } |
kaf24@1535 | 134 |
kaf24@1490 | 135 desc->status &= ~IRQ_INPROGRESS; |
kaf24@1535 | 136 |
kaf24@1490 | 137 out: |
kaf24@1490 | 138 desc->handler->end(irq); |
kaf24@1490 | 139 spin_unlock(&desc->lock); |
kaf24@1490 | 140 } |
kaf24@1490 | 141 |
kaf24@1535 | 142 void free_irq(unsigned int irq) |
kaf24@1490 | 143 { |
kaf24@1535 | 144 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1535 | 145 unsigned long flags; |
kaf24@1490 | 146 |
kaf24@1535 | 147 spin_lock_irqsave(&desc->lock,flags); |
kaf24@1535 | 148 desc->action = NULL; |
kaf24@1535 | 149 desc->depth = 1; |
kaf24@1535 | 150 desc->status |= IRQ_DISABLED; |
kaf24@1535 | 151 desc->handler->shutdown(irq); |
kaf24@1535 | 152 spin_unlock_irqrestore(&desc->lock,flags); |
kaf24@1490 | 153 |
kaf24@1535 | 154 /* Wait to make sure it's not being used on another CPU */ |
kaf24@1535 | 155 do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS ); |
kaf24@1490 | 156 } |
kaf24@1490 | 157 |
kaf24@1535 | 158 int setup_irq(unsigned int irq, struct irqaction *new) |
kaf24@1490 | 159 { |
kaf24@1535 | 160 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1490 | 161 unsigned long flags; |
kaf24@1535 | 162 |
kaf24@1490 | 163 spin_lock_irqsave(&desc->lock,flags); |
kaf24@1490 | 164 |
kaf24@1535 | 165 if ( desc->action != NULL ) |
kaf24@1490 | 166 { |
kaf24@1490 | 167 spin_unlock_irqrestore(&desc->lock,flags); |
kaf24@1490 | 168 return -EBUSY; |
kaf24@1490 | 169 } |
kaf24@1490 | 170 |
kaf24@1535 | 171 desc->action = new; |
kaf24@1535 | 172 desc->depth = 0; |
kaf24@1535 | 173 desc->status &= ~IRQ_DISABLED; |
kaf24@1535 | 174 desc->handler->startup(irq); |
kaf24@1490 | 175 |
kaf24@1490 | 176 spin_unlock_irqrestore(&desc->lock,flags); |
kaf24@1490 | 177 |
kaf24@1490 | 178 return 0; |
kaf24@1490 | 179 } |
kaf24@1490 | 180 |
kaf24@1490 | 181 |
kaf24@1490 | 182 /* |
kaf24@1490 | 183 * HANDLING OF GUEST-BOUND PHYSICAL IRQS |
kaf24@1490 | 184 */ |
kaf24@1490 | 185 |
kaf24@1490 | 186 #define IRQ_MAX_GUESTS 7 |
kaf24@1490 | 187 typedef struct { |
kaf24@1490 | 188 u8 nr_guests; |
kaf24@1490 | 189 u8 in_flight; |
kaf24@1490 | 190 u8 shareable; |
cl349@2962 | 191 struct exec_domain *guest[IRQ_MAX_GUESTS]; |
kaf24@1490 | 192 } irq_guest_action_t; |
kaf24@1490 | 193 |
kaf24@1490 | 194 static void __do_IRQ_guest(int irq) |
kaf24@1490 | 195 { |
kaf24@1535 | 196 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1490 | 197 irq_guest_action_t *action = (irq_guest_action_t *)desc->action; |
cl349@2962 | 198 struct exec_domain *ed; |
kaf24@1535 | 199 int i; |
kaf24@1490 | 200 |
kaf24@1490 | 201 for ( i = 0; i < action->nr_guests; i++ ) |
kaf24@1490 | 202 { |
cl349@2962 | 203 ed = action->guest[i]; |
cl349@2962 | 204 if ( !test_and_set_bit(irq, &ed->domain->pirq_mask) ) |
kaf24@1490 | 205 action->in_flight++; |
cl349@2962 | 206 send_guest_pirq(ed, irq); |
kaf24@1490 | 207 } |
kaf24@1490 | 208 } |
kaf24@1490 | 209 |
kaf24@2280 | 210 int pirq_guest_unmask(struct domain *d) |
kaf24@1490 | 211 { |
kaf24@1535 | 212 irq_desc_t *desc; |
kaf24@2842 | 213 unsigned int i, j, pirq; |
kaf24@1535 | 214 u32 m; |
kaf24@2280 | 215 shared_info_t *s = d->shared_info; |
kaf24@1490 | 216 |
kaf24@2280 | 217 for ( i = 0; i < ARRAY_SIZE(d->pirq_mask); i++ ) |
kaf24@1490 | 218 { |
kaf24@2280 | 219 m = d->pirq_mask[i]; |
kaf24@2842 | 220 while ( m != 0 ) |
kaf24@1490 | 221 { |
kaf24@2842 | 222 j = find_first_set_bit(m); |
kaf24@2842 | 223 m &= ~(1 << j); |
kaf24@1490 | 224 pirq = (i << 5) + j; |
kaf24@1490 | 225 desc = &irq_desc[pirq]; |
kaf24@1490 | 226 spin_lock_irq(&desc->lock); |
kaf24@2280 | 227 if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) && |
kaf24@2280 | 228 test_and_clear_bit(pirq, &d->pirq_mask) && |
kaf24@1490 | 229 (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) |
kaf24@1490 | 230 desc->handler->end(pirq); |
kaf24@1490 | 231 spin_unlock_irq(&desc->lock); |
kaf24@1490 | 232 } |
kaf24@1490 | 233 } |
kaf24@1490 | 234 |
kaf24@1490 | 235 return 0; |
kaf24@1490 | 236 } |
kaf24@1490 | 237 |
cl349@2962 | 238 int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) |
kaf24@1490 | 239 { |
cl349@2962 | 240 struct domain *d = ed->domain; |
kaf24@1535 | 241 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1490 | 242 irq_guest_action_t *action; |
kaf24@1535 | 243 unsigned long flags; |
kaf24@1535 | 244 int rc = 0; |
kaf24@1490 | 245 |
kaf24@2280 | 246 if ( !IS_CAPABLE_PHYSDEV(d) ) |
kaf24@1490 | 247 return -EPERM; |
kaf24@1490 | 248 |
kaf24@1490 | 249 spin_lock_irqsave(&desc->lock, flags); |
kaf24@1490 | 250 |
kaf24@1490 | 251 action = (irq_guest_action_t *)desc->action; |
kaf24@1490 | 252 |
kaf24@1490 | 253 if ( !(desc->status & IRQ_GUEST) ) |
kaf24@1490 | 254 { |
kaf24@1490 | 255 if ( desc->action != NULL ) |
kaf24@1490 | 256 { |
kaf24@1490 | 257 DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n", |
kaf24@1490 | 258 irq, desc->action->name); |
kaf24@1490 | 259 rc = -EBUSY; |
kaf24@1490 | 260 goto out; |
kaf24@1490 | 261 } |
kaf24@1490 | 262 |
iap10@3650 | 263 action = xmalloc(irq_guest_action_t); |
kaf24@1490 | 264 if ( (desc->action = (struct irqaction *)action) == NULL ) |
kaf24@1490 | 265 { |
kaf24@1490 | 266 DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq); |
kaf24@1490 | 267 rc = -ENOMEM; |
kaf24@1490 | 268 goto out; |
kaf24@1490 | 269 } |
kaf24@1490 | 270 |
kaf24@1490 | 271 action->nr_guests = 0; |
kaf24@1490 | 272 action->in_flight = 0; |
kaf24@1490 | 273 action->shareable = will_share; |
kaf24@1490 | 274 |
kaf24@1490 | 275 desc->depth = 0; |
kaf24@1490 | 276 desc->status |= IRQ_GUEST; |
kaf24@1535 | 277 desc->status &= ~IRQ_DISABLED; |
kaf24@1490 | 278 desc->handler->startup(irq); |
kaf24@1490 | 279 |
kaf24@1490 | 280 /* Attempt to bind the interrupt target to the correct CPU. */ |
kaf24@1490 | 281 if ( desc->handler->set_affinity != NULL ) |
kaf24@1490 | 282 desc->handler->set_affinity( |
cl349@2981 | 283 irq, apicid_to_phys_cpu_present(ed->processor)); |
kaf24@1490 | 284 } |
kaf24@1490 | 285 else if ( !will_share || !action->shareable ) |
kaf24@1490 | 286 { |
kaf24@1490 | 287 DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n", |
kaf24@1490 | 288 irq); |
kaf24@1490 | 289 rc = -EBUSY; |
kaf24@1490 | 290 goto out; |
kaf24@1490 | 291 } |
kaf24@1490 | 292 |
kaf24@1490 | 293 if ( action->nr_guests == IRQ_MAX_GUESTS ) |
kaf24@1490 | 294 { |
kaf24@1490 | 295 DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq); |
kaf24@1490 | 296 rc = -EBUSY; |
kaf24@1490 | 297 goto out; |
kaf24@1490 | 298 } |
kaf24@1490 | 299 |
cl349@2962 | 300 action->guest[action->nr_guests++] = ed; |
kaf24@1490 | 301 |
kaf24@1490 | 302 out: |
kaf24@1490 | 303 spin_unlock_irqrestore(&desc->lock, flags); |
kaf24@1490 | 304 return rc; |
kaf24@1490 | 305 } |
kaf24@1490 | 306 |
kaf24@2280 | 307 int pirq_guest_unbind(struct domain *d, int irq) |
kaf24@1490 | 308 { |
kaf24@1535 | 309 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1490 | 310 irq_guest_action_t *action; |
kaf24@1535 | 311 unsigned long flags; |
kaf24@1535 | 312 int i; |
kaf24@1490 | 313 |
kaf24@1490 | 314 spin_lock_irqsave(&desc->lock, flags); |
kaf24@1490 | 315 |
kaf24@1490 | 316 action = (irq_guest_action_t *)desc->action; |
kaf24@1490 | 317 |
kaf24@2280 | 318 if ( test_and_clear_bit(irq, &d->pirq_mask) && |
kaf24@1490 | 319 (--action->in_flight == 0) ) |
kaf24@1490 | 320 desc->handler->end(irq); |
kaf24@1490 | 321 |
kaf24@1490 | 322 if ( action->nr_guests == 1 ) |
kaf24@1490 | 323 { |
kaf24@1490 | 324 desc->action = NULL; |
kaf24@1958 | 325 xfree(action); |
kaf24@1535 | 326 desc->depth = 1; |
kaf24@1490 | 327 desc->status |= IRQ_DISABLED; |
kaf24@1490 | 328 desc->status &= ~IRQ_GUEST; |
kaf24@1490 | 329 desc->handler->shutdown(irq); |
kaf24@1490 | 330 } |
kaf24@1490 | 331 else |
kaf24@1490 | 332 { |
kaf24@1490 | 333 i = 0; |
cl349@2962 | 334 while ( action->guest[i] && action->guest[i]->domain != d ) |
kaf24@1490 | 335 i++; |
kaf24@1490 | 336 memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1); |
kaf24@1490 | 337 action->nr_guests--; |
kaf24@1490 | 338 } |
kaf24@1490 | 339 |
kaf24@1490 | 340 spin_unlock_irqrestore(&desc->lock, flags); |
kaf24@1490 | 341 return 0; |
kaf24@1490 | 342 } |
kaf24@1535 | 343 |
kaf24@1535 | 344 int pirq_guest_bindable(int irq, int will_share) |
kaf24@1535 | 345 { |
kaf24@1535 | 346 irq_desc_t *desc = &irq_desc[irq]; |
kaf24@1535 | 347 irq_guest_action_t *action; |
kaf24@1535 | 348 unsigned long flags; |
kaf24@1535 | 349 int okay; |
kaf24@1535 | 350 |
kaf24@1535 | 351 spin_lock_irqsave(&desc->lock, flags); |
kaf24@1535 | 352 |
kaf24@1535 | 353 action = (irq_guest_action_t *)desc->action; |
kaf24@1535 | 354 |
kaf24@1535 | 355 /* |
kaf24@1535 | 356 * To be bindable the IRQ must either be not currently bound (1), or |
kaf24@1535 | 357 * it must be shareable (2) and not at its share limit (3). |
kaf24@1535 | 358 */ |
kaf24@1535 | 359 okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */ |
kaf24@1535 | 360 (action->shareable && will_share && /* 2 */ |
kaf24@1535 | 361 (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */ |
kaf24@1535 | 362 |
kaf24@1535 | 363 spin_unlock_irqrestore(&desc->lock, flags); |
kaf24@1535 | 364 return okay; |
kaf24@1535 | 365 } |