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
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, &regs);
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 }