[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Get a very primitive relation of IRQ affinity working. For the
# HG changeset patch # User sos22@xxxxxxxxxxxxxxxxxxxx # Node ID 7c3d7c37dfded2aae4e0ba81666dc9a55dba3d6c # Parent 1d375ce8e0e04871782b94408e8b8fe3d399cdd6 Get a very primitive relation of IRQ affinity working. For the minute, we just pick one vcpu out of the allowed set and allows route the irq to that one; that's enough for the userspace irq balancer, but not enough for the kernel-space one. Whether it's actually worth implementing the full variant is open to debate. This also makes IRQ routing across vcpu hotplug events slightly easier. Signed-off-by: Steven Smith, sos22@xxxxxxxxx diff -r 1d375ce8e0e0 -r 7c3d7c37dfde xen/common/event_channel.c --- a/xen/common/event_channel.c Fri Jul 8 14:17:54 2005 +++ b/xen/common/event_channel.c Fri Jul 8 17:33:42 2005 @@ -587,13 +587,16 @@ struct evtchn *chn; long rc = 0; - if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) + if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) { + printf("vcpu %d bad.\n", vcpu); return -EINVAL; + } spin_lock(&d->evtchn_lock); if ( !port_is_valid(d, port) ) { + printf("port %d bad.\n", port); rc = -EINVAL; goto out; } @@ -607,6 +610,7 @@ chn->notify_vcpu_id = vcpu; break; default: + printf("evtchn type %d can't be rebound.\n", chn->state); rc = -EINVAL; break; } diff -r 1d375ce8e0e0 -r 7c3d7c37dfde linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c --- a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c Fri Jul 8 14:17:54 2005 +++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c Fri Jul 8 17:33:42 2005 @@ -271,38 +271,6 @@ return irq; } -void rebind_evtchn_from_ipi(int cpu, int newcpu, int ipi) -{ - evtchn_op_t op; - int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]; - - spin_lock(&irq_mapping_update_lock); - - op.cmd = EVTCHNOP_bind_vcpu; - op.u.bind_vcpu.port = evtchn; - op.u.bind_vcpu.vcpu = newcpu; - if ( HYPERVISOR_event_channel_op(&op) != 0 ) - printk(KERN_INFO "Failed to rebind IPI%d to CPU%d\n",ipi,newcpu); - - spin_unlock(&irq_mapping_update_lock); -} - -void rebind_evtchn_from_irq(int cpu, int newcpu, int irq) -{ - evtchn_op_t op; - int evtchn = irq_to_evtchn[irq]; - - spin_lock(&irq_mapping_update_lock); - - op.cmd = EVTCHNOP_bind_vcpu; - op.u.bind_vcpu.port = evtchn; - op.u.bind_vcpu.vcpu = newcpu; - if ( HYPERVISOR_event_channel_op(&op) != 0 ) - printk(KERN_INFO "Failed to rebind IRQ%d to CPU%d\n",irq,newcpu); - - spin_unlock(&irq_mapping_update_lock); -} - void unbind_ipi_from_irq(int ipi) { evtchn_op_t op; @@ -363,6 +331,63 @@ spin_unlock(&irq_mapping_update_lock); } +static void do_nothing_function(void *ign) +{ +} + +/* Rebind an evtchn so that it gets delivered to a specific cpu */ +static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu) +{ + evtchn_op_t op; + int evtchn; + + printk("<0>Rebind irq %d to vcpu %d.\n", irq, tcpu); + spin_lock(&irq_mapping_update_lock); + evtchn = irq_to_evtchn[irq]; + if (!VALID_EVTCHN(evtchn)) { + spin_unlock(&irq_mapping_update_lock); + return; + } + + printk("<0>Is evtchn %d.\n", evtchn); + + /* Tell Xen to send future instances of this interrupt to the + other vcpu */ + op.cmd = EVTCHNOP_bind_vcpu; + op.u.bind_vcpu.port = evtchn; + op.u.bind_vcpu.vcpu = tcpu; + + /* If this fails, it usually just indicates that we're dealing + with a virq or IPI channel, which don't actually need to be + rebound. Ignore it, but don't do the xenlinux-level rebind + in that case. */ + if (HYPERVISOR_event_channel_op(&op) >= 0) + bind_evtchn_to_cpu(evtchn, tcpu); + + spin_unlock(&irq_mapping_update_lock); + + /* Now send the new target processor a NOP IPI. When this + returns, it will check for any pending interrupts, and so + service any that got delivered to the wrong processor by + mistake. */ + /* XXX: The only time this is called with interrupts disabled is + from the hotplug/hotunplug path. In that case, all cpus are + stopped with interrupts disabled, and the missed interrupts + will be picked up when they start again. This is kind of a + hack. */ + if (!irqs_disabled()) { + printk("<0>Doing nop ipi\n"); + smp_call_function(do_nothing_function, NULL, 0, 0); + printk("<0>Done nop ipi\n"); + } +} + + +static void set_affinity_irq(unsigned irq, cpumask_t dest) +{ + unsigned tcpu = first_cpu(dest); + rebind_irq_to_cpu(irq, tcpu); +} /* * Interface to generic handling in irq.c @@ -425,7 +450,7 @@ disable_dynirq, ack_dynirq, end_dynirq, - NULL + set_affinity_irq }; static inline void pirq_unmask_notify(int pirq) @@ -549,7 +574,7 @@ disable_pirq, ack_pirq, end_pirq, - NULL + set_affinity_irq }; void irq_suspend(void) diff -r 1d375ce8e0e0 -r 7c3d7c37dfde linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c Fri Jul 8 14:17:54 2005 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c Fri Jul 8 17:33:42 2005 @@ -1312,7 +1312,7 @@ /* hotplug down/up funtion pointer and target vcpu */ struct vcpu_hotplug_handler_t { - void (*fn)(); + void (*fn)(int vcpu); u32 vcpu; }; static struct vcpu_hotplug_handler_t vcpu_hotplug_handler; @@ -1325,6 +1325,7 @@ prepare_for_smp(); #endif + printk("<0>Starting enable cpu.\n"); /* get the target out of its holding state */ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; wmb(); @@ -1333,11 +1334,10 @@ while (!cpu_online(cpu)) cpu_relax(); - /* re-route bound IRQs 0 to cpu */ - rebind_evtchn_from_irq(0, cpu, per_cpu(resched_irq, cpu)); - rebind_evtchn_from_irq(0, cpu, per_cpu(callfunc_irq, cpu)); - + printk("<0>Calling fixup_irqs.\n"); fixup_irqs(cpu_online_map); + printk("<0>Called fixup_irqs.\n"); + /* counter the disable in fixup_irqs() */ local_irq_enable(); return 0; @@ -1359,17 +1359,14 @@ if (cpu == 0) return -EBUSY; - /* Allow any queued timer interrupts to get serviced */ - local_irq_enable(); - mdelay(1); - local_irq_disable(); - cpu_clear(cpu, map); fixup_irqs(map); - - /* re-route IRQs from dead vcpu to another */ - rebind_evtchn_from_irq(cpu, 0, per_cpu(resched_irq, cpu)); - rebind_evtchn_from_irq(cpu, 0, per_cpu(callfunc_irq, cpu)); + printk("<0>Done fixup_irqs.\n"); + + local_irq_enable(); + printk("<0>Interrupts on.\n"); + local_irq_disable(); + printk("<0>Interrupts off again.\n"); /* It's now safe to remove this processor from the online map */ cpu_clear(cpu, cpu_online_map); @@ -1498,6 +1495,7 @@ /* Already up, and in cpu_quiescent now? */ if (cpu_isset(cpu, smp_commenced_mask)) { cpu_enable(cpu); + printk("<0>cpu_enable completed.\n"); return 0; } #endif @@ -1533,13 +1531,13 @@ int cpu = smp_processor_id(); per_cpu(resched_irq, cpu) = - bind_ipi_to_irq(RESCHEDULE_VECTOR); + bind_ipi_on_cpu_to_irq(RESCHEDULE_VECTOR); sprintf(resched_name[cpu], "resched%d", cpu); BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt, SA_INTERRUPT, resched_name[cpu], NULL)); per_cpu(callfunc_irq, cpu) = - bind_ipi_to_irq(CALL_FUNCTION_VECTOR); + bind_ipi_on_cpu_to_irq(CALL_FUNCTION_VECTOR); sprintf(callfunc_name[cpu], "callfunc%d", cpu); BUG_ON(request_irq(per_cpu(callfunc_irq, cpu), smp_call_function_interrupt, _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |