[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.