direct-io.hg

changeset 5705:7c3d7c37dfde

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@cam.ac.uk
author sos22@douglas.cl.cam.ac.uk
date Fri Jul 08 17:33:42 2005 +0000 (2005-07-08)
parents 1d375ce8e0e0
children 04d15727e6e8
files linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c xen/common/event_channel.c
line diff
     1.1 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c	Fri Jul 08 14:17:54 2005 +0000
     1.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c	Fri Jul 08 17:33:42 2005 +0000
     1.3 @@ -1312,7 +1312,7 @@ void __devinit smp_prepare_boot_cpu(void
     1.4  
     1.5  /* hotplug down/up funtion pointer and target vcpu */
     1.6  struct vcpu_hotplug_handler_t {
     1.7 -	void (*fn)();
     1.8 +	void (*fn)(int vcpu);
     1.9  	u32 vcpu;
    1.10  };
    1.11  static struct vcpu_hotplug_handler_t vcpu_hotplug_handler;
    1.12 @@ -1325,6 +1325,7 @@ static int __devinit cpu_enable(unsigned
    1.13  		prepare_for_smp();
    1.14  #endif
    1.15  
    1.16 +	printk("<0>Starting enable cpu.\n");
    1.17  	/* get the target out of its holding state */
    1.18  	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
    1.19  	wmb();
    1.20 @@ -1333,11 +1334,10 @@ static int __devinit cpu_enable(unsigned
    1.21  	while (!cpu_online(cpu))
    1.22  		cpu_relax();
    1.23  
    1.24 -   /* re-route bound IRQs 0 to cpu */
    1.25 -   rebind_evtchn_from_irq(0, cpu,  per_cpu(resched_irq, cpu));
    1.26 -   rebind_evtchn_from_irq(0, cpu, per_cpu(callfunc_irq, cpu));
    1.27 +	printk("<0>Calling fixup_irqs.\n");
    1.28 +	fixup_irqs(cpu_online_map);
    1.29 +	printk("<0>Called fixup_irqs.\n");
    1.30  
    1.31 -	fixup_irqs(cpu_online_map);
    1.32  	/* counter the disable in fixup_irqs() */
    1.33  	local_irq_enable();
    1.34  	return 0;
    1.35 @@ -1359,17 +1359,14 @@ int __cpu_disable(void)
    1.36  	if (cpu == 0)
    1.37  		return -EBUSY;
    1.38  
    1.39 -	/* Allow any queued timer interrupts to get serviced */
    1.40 -	local_irq_enable();
    1.41 -	mdelay(1);
    1.42 -	local_irq_disable();
    1.43 -
    1.44  	cpu_clear(cpu, map);
    1.45  	fixup_irqs(map);
    1.46 +	printk("<0>Done fixup_irqs.\n");
    1.47  
    1.48 -   /* re-route IRQs from dead vcpu to another */
    1.49 -   rebind_evtchn_from_irq(cpu, 0,  per_cpu(resched_irq, cpu));
    1.50 -   rebind_evtchn_from_irq(cpu, 0, per_cpu(callfunc_irq, cpu));
    1.51 +	local_irq_enable();
    1.52 +	printk("<0>Interrupts on.\n");
    1.53 +	local_irq_disable();
    1.54 +	printk("<0>Interrupts off again.\n");
    1.55  
    1.56  	/* It's now safe to remove this processor from the online map */
    1.57  	cpu_clear(cpu, cpu_online_map);
    1.58 @@ -1498,6 +1495,7 @@ int __devinit __cpu_up(unsigned int cpu)
    1.59  	/* Already up, and in cpu_quiescent now? */
    1.60  	if (cpu_isset(cpu, smp_commenced_mask)) {
    1.61  		cpu_enable(cpu);
    1.62 +		printk("<0>cpu_enable completed.\n");
    1.63  		return 0;
    1.64  	}
    1.65  #endif
    1.66 @@ -1533,13 +1531,13 @@ void __init smp_intr_init(void)
    1.67  	int cpu = smp_processor_id();
    1.68  
    1.69  	per_cpu(resched_irq, cpu) =
    1.70 -		bind_ipi_to_irq(RESCHEDULE_VECTOR);
    1.71 +		bind_ipi_on_cpu_to_irq(RESCHEDULE_VECTOR);
    1.72  	sprintf(resched_name[cpu], "resched%d", cpu);
    1.73  	BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt,
    1.74  	                   SA_INTERRUPT, resched_name[cpu], NULL));
    1.75  
    1.76  	per_cpu(callfunc_irq, cpu) =
    1.77 -		bind_ipi_to_irq(CALL_FUNCTION_VECTOR);
    1.78 +		bind_ipi_on_cpu_to_irq(CALL_FUNCTION_VECTOR);
    1.79  	sprintf(callfunc_name[cpu], "callfunc%d", cpu);
    1.80  	BUG_ON(request_irq(per_cpu(callfunc_irq, cpu),
    1.81  	                   smp_call_function_interrupt,
     2.1 --- a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c	Fri Jul 08 14:17:54 2005 +0000
     2.2 +++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c	Fri Jul 08 17:33:42 2005 +0000
     2.3 @@ -271,38 +271,6 @@ int bind_ipi_on_cpu_to_irq(int ipi)
     2.4      return irq;
     2.5  }
     2.6  
     2.7 -void rebind_evtchn_from_ipi(int cpu, int newcpu, int ipi)
     2.8 -{
     2.9 -    evtchn_op_t op;
    2.10 -    int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
    2.11 -
    2.12 -    spin_lock(&irq_mapping_update_lock);
    2.13 -
    2.14 -    op.cmd              = EVTCHNOP_bind_vcpu;
    2.15 -    op.u.bind_vcpu.port = evtchn;
    2.16 -    op.u.bind_vcpu.vcpu = newcpu;
    2.17 -    if ( HYPERVISOR_event_channel_op(&op) != 0 )
    2.18 -       printk(KERN_INFO "Failed to rebind IPI%d to CPU%d\n",ipi,newcpu);
    2.19 -
    2.20 -    spin_unlock(&irq_mapping_update_lock);
    2.21 -}
    2.22 -
    2.23 -void rebind_evtchn_from_irq(int cpu, int newcpu, int irq)
    2.24 -{
    2.25 -    evtchn_op_t op;
    2.26 -    int evtchn = irq_to_evtchn[irq];
    2.27 -
    2.28 -    spin_lock(&irq_mapping_update_lock);
    2.29 -
    2.30 -    op.cmd              = EVTCHNOP_bind_vcpu;
    2.31 -    op.u.bind_vcpu.port = evtchn;
    2.32 -    op.u.bind_vcpu.vcpu = newcpu;
    2.33 -    if ( HYPERVISOR_event_channel_op(&op) != 0 )
    2.34 -       printk(KERN_INFO "Failed to rebind IRQ%d to CPU%d\n",irq,newcpu);
    2.35 -
    2.36 -    spin_unlock(&irq_mapping_update_lock);
    2.37 -}
    2.38 -
    2.39  void unbind_ipi_from_irq(int ipi)
    2.40  {
    2.41      evtchn_op_t op;
    2.42 @@ -363,6 +331,63 @@ void unbind_evtchn_from_irq(int evtchn)
    2.43      spin_unlock(&irq_mapping_update_lock);
    2.44  }
    2.45  
    2.46 +static void do_nothing_function(void *ign)
    2.47 +{
    2.48 +}
    2.49 +
    2.50 +/* Rebind an evtchn so that it gets delivered to a specific cpu */
    2.51 +static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
    2.52 +{
    2.53 +    evtchn_op_t op;
    2.54 +    int evtchn;
    2.55 +
    2.56 +    printk("<0>Rebind irq %d to vcpu %d.\n", irq, tcpu);
    2.57 +    spin_lock(&irq_mapping_update_lock);
    2.58 +    evtchn = irq_to_evtchn[irq];
    2.59 +    if (!VALID_EVTCHN(evtchn)) {
    2.60 +	spin_unlock(&irq_mapping_update_lock);
    2.61 +	return;
    2.62 +    }
    2.63 +
    2.64 +    printk("<0>Is evtchn %d.\n", evtchn);
    2.65 +
    2.66 +    /* Tell Xen to send future instances of this interrupt to the
    2.67 +       other vcpu */
    2.68 +    op.cmd = EVTCHNOP_bind_vcpu;
    2.69 +    op.u.bind_vcpu.port = evtchn;
    2.70 +    op.u.bind_vcpu.vcpu = tcpu;
    2.71 +
    2.72 +    /* If this fails, it usually just indicates that we're dealing
    2.73 +       with a virq or IPI channel, which don't actually need to be
    2.74 +       rebound.  Ignore it, but don't do the xenlinux-level rebind
    2.75 +       in that case. */
    2.76 +    if (HYPERVISOR_event_channel_op(&op) >= 0)
    2.77 +	bind_evtchn_to_cpu(evtchn, tcpu);
    2.78 +
    2.79 +    spin_unlock(&irq_mapping_update_lock);
    2.80 +
    2.81 +    /* Now send the new target processor a NOP IPI.  When this
    2.82 +       returns, it will check for any pending interrupts, and so
    2.83 +       service any that got delivered to the wrong processor by
    2.84 +       mistake. */
    2.85 +    /* XXX: The only time this is called with interrupts disabled is
    2.86 +       from the hotplug/hotunplug path.  In that case, all cpus are
    2.87 +       stopped with interrupts disabled, and the missed interrupts
    2.88 +       will be picked up when they start again.  This is kind of a
    2.89 +       hack. */
    2.90 +    if (!irqs_disabled()) {
    2.91 +	printk("<0>Doing nop ipi\n");
    2.92 +	smp_call_function(do_nothing_function, NULL, 0, 0);
    2.93 +	printk("<0>Done nop ipi\n");
    2.94 +    }
    2.95 +}
    2.96 +
    2.97 +
    2.98 +static void set_affinity_irq(unsigned irq, cpumask_t dest)
    2.99 +{
   2.100 +    unsigned tcpu = first_cpu(dest);
   2.101 +    rebind_irq_to_cpu(irq, tcpu);
   2.102 +}
   2.103  
   2.104  /*
   2.105   * Interface to generic handling in irq.c
   2.106 @@ -425,7 +450,7 @@ static struct hw_interrupt_type dynirq_t
   2.107      disable_dynirq,
   2.108      ack_dynirq,
   2.109      end_dynirq,
   2.110 -    NULL
   2.111 +    set_affinity_irq
   2.112  };
   2.113  
   2.114  static inline void pirq_unmask_notify(int pirq)
   2.115 @@ -549,7 +574,7 @@ static struct hw_interrupt_type pirq_typ
   2.116      disable_pirq,
   2.117      ack_pirq,
   2.118      end_pirq,
   2.119 -    NULL
   2.120 +    set_affinity_irq
   2.121  };
   2.122  
   2.123  void irq_suspend(void)
     3.1 --- a/xen/common/event_channel.c	Fri Jul 08 14:17:54 2005 +0000
     3.2 +++ b/xen/common/event_channel.c	Fri Jul 08 17:33:42 2005 +0000
     3.3 @@ -587,13 +587,16 @@ static long evtchn_bind_vcpu(evtchn_bind
     3.4      struct evtchn *chn;
     3.5      long           rc = 0;
     3.6  
     3.7 -    if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) )
     3.8 +    if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) {
     3.9 +        printf("vcpu %d bad.\n", vcpu);
    3.10          return -EINVAL;
    3.11 +    }
    3.12  
    3.13      spin_lock(&d->evtchn_lock);
    3.14  
    3.15      if ( !port_is_valid(d, port) )
    3.16      {
    3.17 +        printf("port %d bad.\n", port);
    3.18          rc = -EINVAL;
    3.19          goto out;
    3.20      }
    3.21 @@ -607,6 +610,7 @@ static long evtchn_bind_vcpu(evtchn_bind
    3.22          chn->notify_vcpu_id = vcpu;
    3.23          break;
    3.24      default:
    3.25 +        printf("evtchn type %d can't be rebound.\n", chn->state);
    3.26          rc = -EINVAL;
    3.27          break;
    3.28      }