source: trunk/packages/xen-3.1/xen-3.1/xen/arch/x86/irq.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 17.6 KB
Line 
1/******************************************************************************
2 * arch/x86/irq.c
3 *
4 * Portions of this file are:
5 *  Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
6 */
7
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 <xen/keyhandler.h>
16#include <xen/compat.h>
17#include <asm/current.h>
18#include <asm/smpboot.h>
19
20/* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
21int opt_noirqbalance = 0;
22boolean_param("noirqbalance", opt_noirqbalance);
23
24irq_desc_t irq_desc[NR_IRQS];
25
26static void __do_IRQ_guest(int vector);
27
28void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs) { }
29
30static void enable_none(unsigned int vector) { }
31static unsigned int startup_none(unsigned int vector) { return 0; }
32static void disable_none(unsigned int vector) { }
33static void ack_none(unsigned int vector)
34{
35    ack_bad_irq(vector);
36}
37
38#define shutdown_none   disable_none
39#define end_none        enable_none
40
41struct hw_interrupt_type no_irq_type = {
42    "none",
43    startup_none,
44    shutdown_none,
45    enable_none,
46    disable_none,
47    ack_none,
48    end_none
49};
50
51atomic_t irq_err_count;
52
53asmlinkage void do_IRQ(struct cpu_user_regs *regs)
54{
55    unsigned int      vector = regs->entry_vector;
56    irq_desc_t       *desc = &irq_desc[vector];
57    struct irqaction *action;
58
59    perfc_incr(irqs);
60
61    spin_lock(&desc->lock);
62    desc->handler->ack(vector);
63
64    if ( likely(desc->status & IRQ_GUEST) )
65    {
66        __do_IRQ_guest(vector);
67        spin_unlock(&desc->lock);
68        return;
69    }
70
71    desc->status &= ~IRQ_REPLAY;
72    desc->status |= IRQ_PENDING;
73
74    /*
75     * Since we set PENDING, if another processor is handling a different
76     * instance of this same irq, the other processor will take care of it.
77     */
78    if ( desc->status & (IRQ_DISABLED | IRQ_INPROGRESS) )
79        goto out;
80
81    desc->status |= IRQ_INPROGRESS;
82
83    action = desc->action;
84    while ( desc->status & IRQ_PENDING )
85    {
86        desc->status &= ~IRQ_PENDING;
87        irq_enter();
88        spin_unlock_irq(&desc->lock);
89        action->handler(vector_to_irq(vector), action->dev_id, regs);
90        spin_lock_irq(&desc->lock);
91        irq_exit();
92    }
93
94    desc->status &= ~IRQ_INPROGRESS;
95
96 out:
97    desc->handler->end(vector);
98    spin_unlock(&desc->lock);
99}
100
101void free_irq(unsigned int irq)
102{
103    unsigned int  vector = irq_to_vector(irq);
104    irq_desc_t   *desc = &irq_desc[vector];
105    unsigned long flags;
106
107    spin_lock_irqsave(&desc->lock,flags);
108    desc->action  = NULL;
109    desc->depth   = 1;
110    desc->status |= IRQ_DISABLED;
111    desc->handler->shutdown(irq);
112    spin_unlock_irqrestore(&desc->lock,flags);
113
114    /* Wait to make sure it's not being used on another CPU */
115    do { smp_mb(); } while ( desc->status & IRQ_INPROGRESS );
116}
117
118int setup_irq(unsigned int irq, struct irqaction *new)
119{
120    unsigned int  vector = irq_to_vector(irq);
121    irq_desc_t   *desc = &irq_desc[vector];
122    unsigned long flags;
123 
124    spin_lock_irqsave(&desc->lock,flags);
125
126    if ( desc->action != NULL )
127    {
128        spin_unlock_irqrestore(&desc->lock,flags);
129        return -EBUSY;
130    }
131
132    desc->action  = new;
133    desc->depth   = 0;
134    desc->status &= ~IRQ_DISABLED;
135    desc->handler->startup(vector);
136
137    spin_unlock_irqrestore(&desc->lock,flags);
138
139    return 0;
140}
141
142
143/*
144 * HANDLING OF GUEST-BOUND PHYSICAL IRQS
145 */
146
147#define IRQ_MAX_GUESTS 7
148typedef struct {
149    u8 nr_guests;
150    u8 in_flight;
151    u8 shareable;
152    u8 ack_type;
153#define ACKTYPE_NONE   0     /* No final acknowledgement is required */
154#define ACKTYPE_UNMASK 1     /* Unmask PIC hardware (from any CPU)   */
155#define ACKTYPE_EOI    2     /* EOI on the CPU that was interrupted  */
156    cpumask_t cpu_eoi_map;   /* CPUs that need to EOI this interrupt */
157    struct domain *guest[IRQ_MAX_GUESTS];
158} irq_guest_action_t;
159
160/*
161 * Stack of interrupts awaiting EOI on each CPU. These must be popped in
162 * order, as only the current highest-priority pending irq can be EOIed.
163 */
164struct pending_eoi {
165    u8 vector; /* Vector awaiting EOI */
166    u8 ready;  /* Ready for EOI now?  */
167};
168static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]);
169#define pending_eoi_sp(p) ((p)[NR_VECTORS-1].vector)
170
171static void __do_IRQ_guest(int vector)
172{
173    unsigned int        irq = vector_to_irq(vector);
174    irq_desc_t         *desc = &irq_desc[vector];
175    irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
176    struct domain      *d;
177    int                 i, sp;
178    struct pending_eoi *peoi = this_cpu(pending_eoi);
179
180    if ( unlikely(action->nr_guests == 0) )
181    {
182        /* An interrupt may slip through while freeing an ACKTYPE_EOI irq. */
183        ASSERT(action->ack_type == ACKTYPE_EOI);
184        ASSERT(desc->status & IRQ_DISABLED);
185        desc->handler->end(vector);
186        return;
187    }
188
189    if ( action->ack_type == ACKTYPE_EOI )
190    {
191        sp = pending_eoi_sp(peoi);
192        ASSERT((sp == 0) || (peoi[sp-1].vector < vector));
193        ASSERT(sp < (NR_VECTORS-1));
194        peoi[sp].vector = vector;
195        peoi[sp].ready = 0;
196        pending_eoi_sp(peoi) = sp+1;
197        cpu_set(smp_processor_id(), action->cpu_eoi_map);
198    }
199
200    for ( i = 0; i < action->nr_guests; i++ )
201    {
202        d = action->guest[i];
203        if ( (action->ack_type != ACKTYPE_NONE) &&
204             !test_and_set_bit(irq, d->pirq_mask) )
205            action->in_flight++;
206        send_guest_pirq(d, irq);
207    }
208}
209
210/* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */
211static void flush_ready_eoi(void *unused)
212{
213    struct pending_eoi *peoi = this_cpu(pending_eoi);
214    irq_desc_t         *desc;
215    int                 vector, sp;
216
217    ASSERT(!local_irq_is_enabled());
218
219    sp = pending_eoi_sp(peoi);
220
221    while ( (--sp >= 0) && peoi[sp].ready )
222    {
223        vector = peoi[sp].vector;
224        desc = &irq_desc[vector];
225        spin_lock(&desc->lock);
226        desc->handler->end(vector);
227        spin_unlock(&desc->lock);
228    }
229
230    pending_eoi_sp(peoi) = sp+1;
231}
232
233static void __set_eoi_ready(irq_desc_t *desc)
234{
235    irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
236    struct pending_eoi *peoi = this_cpu(pending_eoi);
237    int                 vector, sp;
238
239    vector = desc - irq_desc;
240
241    if ( !(desc->status & IRQ_GUEST) ||
242         (action->in_flight != 0) ||
243         !cpu_test_and_clear(smp_processor_id(), action->cpu_eoi_map) )
244        return;
245
246    sp = pending_eoi_sp(peoi);
247    do {
248        ASSERT(sp > 0);
249    } while ( peoi[--sp].vector != vector );
250    ASSERT(!peoi[sp].ready);
251    peoi[sp].ready = 1;
252}
253
254/* Mark specified IRQ as ready-for-EOI (if it really is) and attempt to EOI. */
255static void set_eoi_ready(void *data)
256{
257    irq_desc_t *desc = data;
258
259    ASSERT(!local_irq_is_enabled());
260
261    spin_lock(&desc->lock);
262    __set_eoi_ready(desc);
263    spin_unlock(&desc->lock);
264
265    flush_ready_eoi(NULL);
266}
267
268static void __pirq_guest_eoi(struct domain *d, int irq)
269{
270    irq_desc_t         *desc;
271    irq_guest_action_t *action;
272    cpumask_t           cpu_eoi_map;
273
274    desc   = &irq_desc[irq_to_vector(irq)];
275    action = (irq_guest_action_t *)desc->action;
276
277    spin_lock_irq(&desc->lock);
278
279    ASSERT(!test_bit(irq, d->pirq_mask) ||
280           (action->ack_type != ACKTYPE_NONE));
281
282    if ( unlikely(!test_and_clear_bit(irq, d->pirq_mask)) ||
283         unlikely(--action->in_flight != 0) )
284    {
285        spin_unlock_irq(&desc->lock);
286        return;
287    }
288
289    if ( action->ack_type == ACKTYPE_UNMASK )
290    {
291        ASSERT(cpus_empty(action->cpu_eoi_map));
292        desc->handler->end(irq_to_vector(irq));
293        spin_unlock_irq(&desc->lock);
294        return;
295    }
296
297    ASSERT(action->ack_type == ACKTYPE_EOI);
298       
299    cpu_eoi_map = action->cpu_eoi_map;
300
301    if ( cpu_test_and_clear(smp_processor_id(), cpu_eoi_map) )
302    {
303        __set_eoi_ready(desc);
304        spin_unlock(&desc->lock);
305        flush_ready_eoi(NULL);
306        local_irq_enable();
307    }
308    else
309    {
310        spin_unlock_irq(&desc->lock);
311    }
312
313    if ( !cpus_empty(cpu_eoi_map) )
314        on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 1, 0);
315}
316
317int pirq_guest_eoi(struct domain *d, int irq)
318{
319    if ( (irq < 0) || (irq >= NR_IRQS) )
320        return -EINVAL;
321
322    __pirq_guest_eoi(d, irq);
323
324    return 0;
325}
326
327int pirq_guest_unmask(struct domain *d)
328{
329    unsigned int   irq;
330    shared_info_t *s = d->shared_info;
331
332    for ( irq = find_first_bit(d->pirq_mask, NR_IRQS);
333          irq < NR_IRQS;
334          irq = find_next_bit(d->pirq_mask, NR_IRQS, irq+1) )
335    {
336        if ( !test_bit(d->pirq_to_evtchn[irq], __shared_info_addr(d, s, evtchn_mask)) )
337            __pirq_guest_eoi(d, irq);
338    }
339
340    return 0;
341}
342
343extern int ioapic_ack_new;
344int pirq_acktype(int irq)
345{
346    irq_desc_t  *desc;
347    unsigned int vector;
348
349    vector = irq_to_vector(irq);
350    if ( vector == 0 )
351        return ACKTYPE_NONE;
352
353    desc = &irq_desc[vector];
354
355    if ( desc->handler == &no_irq_type )
356        return ACKTYPE_NONE;
357
358    /*
359     * Edge-triggered IO-APIC and LAPIC interrupts need no final
360     * acknowledgement: we ACK early during interrupt processing.
361     */
362    if ( !strcmp(desc->handler->typename, "IO-APIC-edge") ||
363         !strcmp(desc->handler->typename, "local-APIC-edge") )
364        return ACKTYPE_NONE;
365
366    /*
367     * Level-triggered IO-APIC interrupts need to be acknowledged on the CPU
368     * on which they were received. This is because we tickle the LAPIC to EOI.
369     */
370    if ( !strcmp(desc->handler->typename, "IO-APIC-level") )
371        return ioapic_ack_new ? ACKTYPE_EOI : ACKTYPE_UNMASK;
372
373    /* Legacy PIC interrupts can be acknowledged from any CPU. */
374    if ( !strcmp(desc->handler->typename, "XT-PIC") )
375        return ACKTYPE_UNMASK;
376
377    if ( strstr(desc->handler->typename, "MPIC") )
378    {
379        if ( desc->status & IRQ_LEVEL )
380            return (desc->status & IRQ_PER_CPU) ? ACKTYPE_EOI : ACKTYPE_UNMASK;
381        return ACKTYPE_NONE; /* edge-triggered => no final EOI */
382    }
383
384    printk("Unknown PIC type '%s' for IRQ %d\n", desc->handler->typename, irq);
385    BUG();
386
387    return 0;
388}
389
390int pirq_shared(int irq)
391{
392    unsigned int        vector;
393    irq_desc_t         *desc;
394    irq_guest_action_t *action;
395    unsigned long       flags;
396    int                 shared;
397
398    vector = irq_to_vector(irq);
399    if ( vector == 0 )
400        return 0;
401
402    desc = &irq_desc[vector];
403
404    spin_lock_irqsave(&desc->lock, flags);
405    action = (irq_guest_action_t *)desc->action;
406    shared = ((desc->status & IRQ_GUEST) && (action->nr_guests > 1));
407    spin_unlock_irqrestore(&desc->lock, flags);
408
409    return shared;
410}
411
412int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
413{
414    unsigned int        vector;
415    irq_desc_t         *desc;
416    irq_guest_action_t *action;
417    unsigned long       flags;
418    int                 rc = 0;
419    cpumask_t           cpumask = CPU_MASK_NONE;
420
421 retry:
422    vector = irq_to_vector(irq);
423    if ( vector == 0 )
424        return -EINVAL;
425
426    desc = &irq_desc[vector];
427
428    spin_lock_irqsave(&desc->lock, flags);
429
430    action = (irq_guest_action_t *)desc->action;
431
432    if ( !(desc->status & IRQ_GUEST) )
433    {
434        if ( desc->action != NULL )
435        {
436            gdprintk(XENLOG_INFO,
437                    "Cannot bind IRQ %d to guest. In use by '%s'.\n",
438                    irq, desc->action->name);
439            rc = -EBUSY;
440            goto out;
441        }
442
443        action = xmalloc(irq_guest_action_t);
444        if ( (desc->action = (struct irqaction *)action) == NULL )
445        {
446            gdprintk(XENLOG_INFO,
447                    "Cannot bind IRQ %d to guest. Out of memory.\n",
448                    irq);
449            rc = -ENOMEM;
450            goto out;
451        }
452
453        action->nr_guests   = 0;
454        action->in_flight   = 0;
455        action->shareable   = will_share;
456        action->ack_type    = pirq_acktype(irq);
457        cpus_clear(action->cpu_eoi_map);
458
459        desc->depth = 0;
460        desc->status |= IRQ_GUEST;
461        desc->status &= ~IRQ_DISABLED;
462        desc->handler->startup(vector);
463
464        /* Attempt to bind the interrupt target to the correct CPU. */
465        cpu_set(v->processor, cpumask);
466        if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )
467            desc->handler->set_affinity(vector, cpumask);
468    }
469    else if ( !will_share || !action->shareable )
470    {
471        gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "
472               "Will not share with others.\n",
473                irq);
474        rc = -EBUSY;
475        goto out;
476    }
477    else if ( action->nr_guests == 0 )
478    {
479        /*
480         * Indicates that an ACKTYPE_EOI interrupt is being released.
481         * Wait for that to happen before continuing.
482         */
483        ASSERT(action->ack_type == ACKTYPE_EOI);
484        ASSERT(desc->status & IRQ_DISABLED);
485        spin_unlock_irqrestore(&desc->lock, flags);
486        cpu_relax();
487        goto retry;
488    }
489
490    if ( action->nr_guests == IRQ_MAX_GUESTS )
491    {
492        gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "
493               "Already at max share.\n", irq);
494        rc = -EBUSY;
495        goto out;
496    }
497
498    action->guest[action->nr_guests++] = v->domain;
499
500 out:
501    spin_unlock_irqrestore(&desc->lock, flags);
502    return rc;
503}
504
505int pirq_guest_unbind(struct domain *d, int irq)
506{
507    unsigned int        vector = irq_to_vector(irq);
508    irq_desc_t         *desc = &irq_desc[vector];
509    irq_guest_action_t *action;
510    cpumask_t           cpu_eoi_map;
511    unsigned long       flags;
512    int                 i;
513
514    BUG_ON(vector == 0);
515
516    spin_lock_irqsave(&desc->lock, flags);
517
518    action = (irq_guest_action_t *)desc->action;
519
520    i = 0;
521    while ( action->guest[i] && (action->guest[i] != d) )
522        i++;
523    memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
524    action->nr_guests--;
525
526    switch ( action->ack_type )
527    {
528    case ACKTYPE_UNMASK:
529        if ( test_and_clear_bit(irq, d->pirq_mask) &&
530             (--action->in_flight == 0) )
531            desc->handler->end(vector);
532        break;
533    case ACKTYPE_EOI:
534        /* NB. If #guests == 0 then we clear the eoi_map later on. */
535        if ( test_and_clear_bit(irq, d->pirq_mask) &&
536             (--action->in_flight == 0) &&
537             (action->nr_guests != 0) )
538        {
539            cpu_eoi_map = action->cpu_eoi_map;
540            spin_unlock_irqrestore(&desc->lock, flags);   
541            on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 1, 0);
542            spin_lock_irqsave(&desc->lock, flags);
543        }
544        break;
545    }
546
547    /*
548     * The guest cannot re-bind to this IRQ until this function returns. So,
549     * when we have flushed this IRQ from pirq_mask, it should remain flushed.
550     */
551    BUG_ON(test_bit(irq, d->pirq_mask));
552
553    if ( action->nr_guests != 0 )
554        goto out;
555
556    BUG_ON(action->in_flight != 0);
557
558    /* Disabling IRQ before releasing the desc_lock avoids an IRQ storm. */
559    desc->depth   = 1;
560    desc->status |= IRQ_DISABLED;
561    desc->handler->disable(vector);
562
563    /*
564     * Mark any remaining pending EOIs as ready to flush.
565     * NOTE: We will need to make this a stronger barrier if in future we allow
566     * an interrupt vectors to be re-bound to a different PIC. In that case we
567     * would need to flush all ready EOIs before returning as otherwise the
568     * desc->handler could change and we would call the wrong 'end' hook.
569     */
570    cpu_eoi_map = action->cpu_eoi_map;
571    if ( !cpus_empty(cpu_eoi_map) )
572    {
573        BUG_ON(action->ack_type != ACKTYPE_EOI);
574        spin_unlock_irqrestore(&desc->lock, flags);
575        on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 1, 1);
576        spin_lock_irqsave(&desc->lock, flags);
577    }
578
579    BUG_ON(!cpus_empty(action->cpu_eoi_map));
580
581    desc->action = NULL;
582    xfree(action);
583    desc->status &= ~IRQ_GUEST;
584    desc->handler->shutdown(vector);
585
586 out:
587    spin_unlock_irqrestore(&desc->lock, flags);   
588    return 0;
589}
590
591extern void dump_ioapic_irq_info(void);
592
593static void dump_irqs(unsigned char key)
594{
595    int i, irq, vector;
596    irq_desc_t *desc;
597    irq_guest_action_t *action;
598    struct domain *d;
599    unsigned long flags;
600
601    printk("Guest interrupt information:\n");
602
603    for ( irq = 0; irq < NR_IRQS; irq++ )
604    {
605        vector = irq_to_vector(irq);
606        if ( vector == 0 )
607            continue;
608
609        desc = &irq_desc[vector];
610
611        spin_lock_irqsave(&desc->lock, flags);
612
613        if ( desc->status & IRQ_GUEST )
614        {
615            action = (irq_guest_action_t *)desc->action;
616
617            printk("    IRQ%3d Vec%3d: type=%-15s status=%08x "
618                   "in-flight=%d domain-list=",
619                   irq, vector, desc->handler->typename,
620                   desc->status, action->in_flight);
621
622            for ( i = 0; i < action->nr_guests; i++ )
623            {
624                d = action->guest[i];
625                printk("%u(%c%c%c%c)",
626                       d->domain_id,
627                       (test_bit(d->pirq_to_evtchn[irq],
628                                 shared_info_addr(d, evtchn_pending)) ?
629                        'P' : '-'),
630                       (test_bit(d->pirq_to_evtchn[irq]/BITS_PER_GUEST_LONG(d),
631                                 vcpu_info_addr(d->vcpu[0], evtchn_pending_sel)) ?
632                        'S' : '-'),
633                       (test_bit(d->pirq_to_evtchn[irq],
634                                 shared_info_addr(d, evtchn_mask)) ?
635                        'M' : '-'),
636                       (test_bit(irq, d->pirq_mask) ?
637                        'M' : '-'));
638                if ( i != action->nr_guests )
639                    printk(",");
640            }
641
642            printk("\n");
643        }
644
645        spin_unlock_irqrestore(&desc->lock, flags);
646    }
647
648    dump_ioapic_irq_info();
649}
650
651static int __init setup_dump_irqs(void)
652{
653    register_keyhandler('i', dump_irqs, "dump interrupt bindings");
654    return 0;
655}
656__initcall(setup_dump_irqs);
Note: See TracBrowser for help on using the repository browser.