Irq nunmber for per-vcpu event (virq/ipi) needs kept accross vcpu plug/unplug, once allocated. We just reuse this irq number and bind it to a new event port. Or else, /proc/interrupt exports messed statistics like: ot@localhost ~]# cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 256: 423066 0 0 0 Dynamic-irq timer0 257: 3014 0 0 0 Dynamic-irq resched0 258: 37 0 0 0 Dynamic-irq callfunc0 259: 713 0 0 0 Dynamic-irq xenbus 260: 343 1323 65 50 Dynamic-irq xencons 261: 270 62 0 0 Dynamic-irq blkif 262: 0 1053818 1220 855 Dynamic-irq resched1 263: 0 0 2165 53 Dynamic-irq callfunc1 264: 0 3218 69 0 Dynamic-irq timer1 265: 0 0 42768 228 Dynamic-irq resched2 266: 0 45 0 1867 Dynamic-irq callfunc2 267: 0 0 39543 256 Dynamic-irq timer2 268: 0 2244 46 33027 Dynamic-irq resched3 269: 1585 0 0 0 Dynamic-irq callfunc3 270: 11273 0 1885 1073 Dynamic-irq timer3 NMI: 0 0 0 0 LOC: 0 0 0 0 ERR: 0 MIS: 0 This also applies to save/restore for same issue. Signed-off-by Kevin Tian diff -r 99d1480afae8 -r 7988ed3b9cd9 linux-2.6-xen-sparse/drivers/xen/core/evtchn.c --- a/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c Fri Feb 02 21:08:49 2007 +0800 +++ b/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c Sat Feb 03 12:30:46 2007 +0800 @@ -359,14 +359,21 @@ static int bind_virq_to_irq(unsigned int static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) { struct evtchn_bind_virq bind_virq; - int evtchn, irq; + int evtchn, irq, bind = 1; spin_lock(&irq_mapping_update_lock); - if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { + irq = per_cpu(virq_to_irq, cpu)[virq]; + if (irq == -1) { if ((irq = find_unbound_irq()) < 0) goto out; - + } else if (!evtchn_from_irq(irq)) { + /* Canonicalize the count */ + irq_bindcount[irq]--; + } else + bind = 0; + + if (bind) { bind_virq.virq = virq; bind_virq.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, @@ -392,14 +399,21 @@ static int bind_ipi_to_irq(unsigned int static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { struct evtchn_bind_ipi bind_ipi; - int evtchn, irq; + int evtchn, irq, bind = 1; spin_lock(&irq_mapping_update_lock); - if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { + irq = per_cpu(ipi_to_irq, cpu)[ipi]; + if (irq == -1) { if ((irq = find_unbound_irq()) < 0) goto out; - + } else if (!evtchn_from_irq(irq)) { + /* Canonicalize the count */ + irq_bindcount[irq]--; + } else + bind = 0; + + if (bind) { bind_ipi.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi) != 0) @@ -434,24 +448,24 @@ static void unbind_from_irq(unsigned int HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) BUG(); + /* Closed ports are implicitly re-bound to VCPU0. */ + bind_evtchn_to_cpu(evtchn, 0); + + evtchn_to_irq[evtchn] = -1; + switch (type_from_irq(irq)) { case IRQT_VIRQ: - per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) - [index_from_irq(irq)] = -1; - break; case IRQT_IPI: - per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) - [index_from_irq(irq)] = -1; + /* Keep irq number for per-vcpu type, and lock + * it from used by others + */ + irq_info[irq] &= ~0xFFFF; + irq_bindcount[irq]++; break; default: + irq_info[irq] = IRQ_UNBOUND; break; } - - /* Closed ports are implicitly re-bound to VCPU0. */ - bind_evtchn_to_cpu(evtchn, 0); - - evtchn_to_irq[evtchn] = -1; - irq_info[irq] = IRQ_UNBOUND; } spin_unlock(&irq_mapping_update_lock); @@ -901,14 +915,18 @@ void irq_resume(void) for (pirq = 0; pirq < NR_PIRQS; pirq++) BUG_ON(irq_info[pirq_to_irq(pirq)] != IRQ_UNBOUND); - /* Secondary CPUs must have no VIRQ or IPI bindings. */ + /* Secondary CPUs must have no VIRQ or IPI bindings to event + * port, but irq number may be preserved + */ for_each_possible_cpu(cpu) { if (cpu == 0) continue; for (virq = 0; virq < NR_VIRQS; virq++) - BUG_ON(per_cpu(virq_to_irq, cpu)[virq] != -1); + BUG_ON(((irq = per_cpu(virq_to_irq, cpu)[virq]) != -1) + && evtchn_from_irq(irq)); for (ipi = 0; ipi < NR_IPIS; ipi++) - BUG_ON(per_cpu(ipi_to_irq, cpu)[ipi] != -1); + BUG_ON(((irq = per_cpu(ipi_to_irq, cpu)[ipi]) != -1) + && evtchn_from_irq(irq)); } /* No IRQ <-> event-channel mappings. */