irq.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 764 行 · 第 1/2 页

C
764
字号
    if ( !cpus_empty(cpu_eoi_map) )        on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 1, 0);}int pirq_guest_eoi(struct domain *d, int irq){    if ( (irq < 0) || (irq >= NR_IRQS) )        return -EINVAL;    __pirq_guest_eoi(d, irq);    return 0;}int pirq_guest_unmask(struct domain *d){    unsigned int   irq;    for ( irq = find_first_bit(d->pirq_mask, NR_IRQS);          irq < NR_IRQS;          irq = find_next_bit(d->pirq_mask, NR_IRQS, irq+1) )    {        if ( !test_bit(d->pirq_to_evtchn[irq], &shared_info(d, evtchn_mask)) )            __pirq_guest_eoi(d, irq);    }    return 0;}extern int ioapic_ack_new;int pirq_acktype(struct domain *d, int irq){    irq_desc_t  *desc;    unsigned int vector;    vector = domain_irq_to_vector(d, irq);    if ( vector == 0 )        return ACKTYPE_NONE;    desc = &irq_desc[vector];    if ( desc->handler == &no_irq_type )        return ACKTYPE_NONE;    /*     * Edge-triggered IO-APIC and LAPIC interrupts need no final     * acknowledgement: we ACK early during interrupt processing.     * MSIs are treated as edge-triggered interrupts.     */    if ( !strcmp(desc->handler->typename, "IO-APIC-edge") ||         !strcmp(desc->handler->typename, "local-APIC-edge") ||         !strcmp(desc->handler->typename, "PCI-MSI") )        return ACKTYPE_NONE;    /*     * Level-triggered IO-APIC interrupts need to be acknowledged on the CPU     * on which they were received. This is because we tickle the LAPIC to EOI.     */    if ( !strcmp(desc->handler->typename, "IO-APIC-level") )        return ioapic_ack_new ? ACKTYPE_EOI : ACKTYPE_UNMASK;    /* Legacy PIC interrupts can be acknowledged from any CPU. */    if ( !strcmp(desc->handler->typename, "XT-PIC") )        return ACKTYPE_UNMASK;    if ( strstr(desc->handler->typename, "MPIC") )    {        if ( desc->status & IRQ_LEVEL )            return (desc->status & IRQ_PER_CPU) ? ACKTYPE_EOI : ACKTYPE_UNMASK;        return ACKTYPE_NONE; /* edge-triggered => no final EOI */    }    printk("Unknown PIC type '%s' for IRQ %d\n", desc->handler->typename, irq);    BUG();    return 0;}int pirq_shared(struct domain *d, int irq){    unsigned int        vector;    irq_desc_t         *desc;    irq_guest_action_t *action;    unsigned long       flags;    int                 shared;    vector = domain_irq_to_vector(d, irq);    if ( vector == 0 )        return 0;    desc = &irq_desc[vector];    spin_lock_irqsave(&desc->lock, flags);    action = (irq_guest_action_t *)desc->action;    shared = ((desc->status & IRQ_GUEST) && (action->nr_guests > 1));    spin_unlock_irqrestore(&desc->lock, flags);    return shared;}int pirq_guest_bind(struct vcpu *v, int irq, int will_share){    unsigned int        vector;    irq_desc_t         *desc;    irq_guest_action_t *action;    unsigned long       flags;    int                 rc = 0;    cpumask_t           cpumask = CPU_MASK_NONE; retry:    vector = domain_irq_to_vector(v->domain, irq);    if ( vector == 0 )        return -EINVAL;    desc = &irq_desc[vector];    spin_lock_irqsave(&desc->lock, flags);    action = (irq_guest_action_t *)desc->action;    if ( !(desc->status & IRQ_GUEST) )    {        if ( desc->action != NULL )        {            gdprintk(XENLOG_INFO,                    "Cannot bind IRQ %d to guest. In use by '%s'.\n",                    irq, desc->action->name);            rc = -EBUSY;            goto out;        }        action = xmalloc(irq_guest_action_t);        if ( (desc->action = (struct irqaction *)action) == NULL )        {            gdprintk(XENLOG_INFO,                    "Cannot bind IRQ %d to guest. Out of memory.\n",                    irq);            rc = -ENOMEM;            goto out;        }        action->nr_guests   = 0;        action->in_flight   = 0;        action->shareable   = will_share;        action->ack_type    = pirq_acktype(v->domain, irq);        cpus_clear(action->cpu_eoi_map);        desc->depth = 0;        desc->status |= IRQ_GUEST;        desc->status &= ~IRQ_DISABLED;        desc->handler->startup(vector);        /* Attempt to bind the interrupt target to the correct CPU. */        cpu_set(v->processor, cpumask);        if ( !opt_noirqbalance && (desc->handler->set_affinity != NULL) )            desc->handler->set_affinity(vector, cpumask);    }    else if ( !will_share || !action->shareable )    {        gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "               "Will not share with others.\n",                irq);        rc = -EBUSY;        goto out;    }    else if ( action->nr_guests == 0 )    {        /*         * Indicates that an ACKTYPE_EOI interrupt is being released.         * Wait for that to happen before continuing.         */        ASSERT(action->ack_type == ACKTYPE_EOI);        ASSERT(desc->status & IRQ_DISABLED);        spin_unlock_irqrestore(&desc->lock, flags);        cpu_relax();        goto retry;    }    if ( action->nr_guests == IRQ_MAX_GUESTS )    {        gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "               "Already at max share.\n", irq);        rc = -EBUSY;        goto out;    }    action->guest[action->nr_guests++] = v->domain; out:    spin_unlock_irqrestore(&desc->lock, flags);    return rc;}void pirq_guest_unbind(struct domain *d, int irq){    unsigned int        vector;    irq_desc_t         *desc;    irq_guest_action_t *action;    cpumask_t           cpu_eoi_map;    unsigned long       flags;    int                 i;    vector = domain_irq_to_vector(d, irq);    desc = &irq_desc[vector];    BUG_ON(vector == 0);    spin_lock_irqsave(&desc->lock, flags);    action = (irq_guest_action_t *)desc->action;    i = 0;    while ( action->guest[i] && (action->guest[i] != d) )        i++;    memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);    action->nr_guests--;    switch ( action->ack_type )    {    case ACKTYPE_UNMASK:        if ( test_and_clear_bit(irq, d->pirq_mask) &&             (--action->in_flight == 0) )            desc->handler->end(vector);        break;    case ACKTYPE_EOI:        /* NB. If #guests == 0 then we clear the eoi_map later on. */        if ( test_and_clear_bit(irq, d->pirq_mask) &&             (--action->in_flight == 0) &&             (action->nr_guests != 0) )        {            cpu_eoi_map = action->cpu_eoi_map;            spin_unlock_irqrestore(&desc->lock, flags);                on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 1, 0);            spin_lock_irqsave(&desc->lock, flags);        }        break;    }    /*     * The guest cannot re-bind to this IRQ until this function returns. So,     * when we have flushed this IRQ from pirq_mask, it should remain flushed.     */    BUG_ON(test_bit(irq, d->pirq_mask));    if ( action->nr_guests != 0 )        goto out;    BUG_ON(action->in_flight != 0);    /* Disabling IRQ before releasing the desc_lock avoids an IRQ storm. */    desc->depth   = 1;    desc->status |= IRQ_DISABLED;    desc->handler->disable(vector);    /*     * Mark any remaining pending EOIs as ready to flush.     * NOTE: We will need to make this a stronger barrier if in future we allow     * an interrupt vectors to be re-bound to a different PIC. In that case we     * would need to flush all ready EOIs before returning as otherwise the     * desc->handler could change and we would call the wrong 'end' hook.     */    cpu_eoi_map = action->cpu_eoi_map;    if ( !cpus_empty(cpu_eoi_map) )    {        BUG_ON(action->ack_type != ACKTYPE_EOI);        spin_unlock_irqrestore(&desc->lock, flags);        on_selected_cpus(cpu_eoi_map, set_eoi_ready, desc, 1, 1);        spin_lock_irqsave(&desc->lock, flags);    }    BUG_ON(!cpus_empty(action->cpu_eoi_map));    desc->action = NULL;    xfree(action);    desc->status &= ~IRQ_GUEST;    desc->status &= ~IRQ_INPROGRESS;    kill_timer(&irq_guest_eoi_timer[vector]);    desc->handler->shutdown(vector); out:    spin_unlock_irqrestore(&desc->lock, flags);    }extern void dump_ioapic_irq_info(void);static void dump_irqs(unsigned char key){    int i, irq, vector;    irq_desc_t *desc;    irq_guest_action_t *action;    struct domain *d;    unsigned long flags;    printk("Guest interrupt information:\n");    for ( irq = 0; irq < NR_IRQS; irq++ )    {        vector = irq_to_vector(irq);        if ( vector == 0 )            continue;        desc = &irq_desc[vector];        spin_lock_irqsave(&desc->lock, flags);        if ( desc->status & IRQ_GUEST )        {            action = (irq_guest_action_t *)desc->action;            printk("    IRQ%3d Vec%3d: type=%-15s status=%08x "                   "in-flight=%d domain-list=",                   irq, vector, desc->handler->typename,                   desc->status, action->in_flight);            for ( i = 0; i < action->nr_guests; i++ )            {                d = action->guest[i];                printk("%u(%c%c%c%c)",                       d->domain_id,                       (test_bit(d->pirq_to_evtchn[irq],                                 &shared_info(d, evtchn_pending)) ?                        'P' : '-'),                       (test_bit(d->pirq_to_evtchn[irq]/BITS_PER_GUEST_LONG(d),                                 &vcpu_info(d->vcpu[0], evtchn_pending_sel)) ?                        'S' : '-'),                       (test_bit(d->pirq_to_evtchn[irq],                                 &shared_info(d, evtchn_mask)) ?                        'M' : '-'),                       (test_bit(irq, d->pirq_mask) ?                        'M' : '-'));                if ( i != action->nr_guests )                    printk(",");            }            printk("\n");        }        spin_unlock_irqrestore(&desc->lock, flags);    }    dump_ioapic_irq_info();}static int __init setup_dump_irqs(void){    register_keyhandler('i', dump_irqs, "dump interrupt bindings");    return 0;}__initcall(setup_dump_irqs);#ifdef CONFIG_HOTPLUG_CPU#include <asm/mach-generic/mach_apic.h>#include <xen/delay.h>void fixup_irqs(cpumask_t map){    unsigned int irq;    static int warned;    for ( irq = 0; irq < NR_IRQS; irq++ )    {        cpumask_t mask;        if ( irq == 2 )            continue;        cpus_and(mask, irq_desc[irq].affinity, map);        if ( any_online_cpu(mask) == NR_CPUS )        {            printk("Breaking affinity for irq %i\n", irq);            mask = map;        }        if ( irq_desc[irq].handler->set_affinity )            irq_desc[irq].handler->set_affinity(irq, mask);        else if ( irq_desc[irq].action && !(warned++) )            printk("Cannot set affinity for irq %i\n", irq);    }    local_irq_enable();    mdelay(1);    local_irq_disable();}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?