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 + -
显示快捷键?