ia64/xen-unstable

changeset 2937:b35c932069a7

bitkeeper revision 1.1159.1.405 (41927f27DOMh29BHDXqA1jRKSnc6Qg)

SMP IPI support.
author cl349@freefall.cl.cam.ac.uk
date Wed Nov 10 20:50:47 2004 +0000 (2004-11-10)
parents 0c03aa71a5c3
children 99703645a405
files linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h xen/common/event_channel.c
line diff
     1.1 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c	Wed Nov 10 16:00:14 2004 +0000
     1.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c	Wed Nov 10 20:50:47 2004 +0000
     1.3 @@ -25,6 +25,7 @@
     1.4  #if 0
     1.5  #include <mach_apic.h>
     1.6  #endif
     1.7 +#include <asm-xen/evtchn.h>
     1.8  
     1.9  #define xxprint(msg) HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg)
    1.10  
    1.11 @@ -125,35 +126,47 @@ static inline int __prepare_ICR2 (unsign
    1.12  	return SET_APIC_DEST_FIELD(mask);
    1.13  }
    1.14  
    1.15 +DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]);
    1.16 +
    1.17 +static inline void __send_IPI_one(unsigned int cpu, int vector)
    1.18 +{
    1.19 +	unsigned int evtchn;
    1.20 +
    1.21 +	evtchn = per_cpu(ipi_to_evtchn, cpu)[vector];
    1.22 +	// printk("send_IPI_mask_bitmask cpu %d vector %d evtchn %d\n", cpu, vector, evtchn);
    1.23 +	if (evtchn) {
    1.24 +		shared_info_t *s = HYPERVISOR_shared_info;
    1.25 +		while (synch_test_bit(evtchn, &s->evtchn_pending[0]) ||
    1.26 +		       synch_test_bit(evtchn, &s->evtchn_mask[0]))
    1.27 +			;
    1.28 +		notify_via_evtchn(evtchn);
    1.29 +	} else
    1.30 +		printk("send_IPI to unbound port %d/%d",
    1.31 +		       cpu, vector);
    1.32 +}
    1.33 +
    1.34  void __send_IPI_shortcut(unsigned int shortcut, int vector)
    1.35  {
    1.36 -#if 1
    1.37 -	xxprint("__send_IPI_shortcut\n");
    1.38 -#else
    1.39 -	/*
    1.40 -	 * Subtle. In the case of the 'never do double writes' workaround
    1.41 -	 * we have to lock out interrupts to be safe.  As we don't care
    1.42 -	 * of the value read we use an atomic rmw access to avoid costly
    1.43 -	 * cli/sti.  Otherwise we use an even cheaper single atomic write
    1.44 -	 * to the APIC.
    1.45 -	 */
    1.46 -	unsigned int cfg;
    1.47 +	int cpu;
    1.48  
    1.49 -	/*
    1.50 -	 * Wait for idle.
    1.51 -	 */
    1.52 -	apic_wait_icr_idle();
    1.53 -
    1.54 -	/*
    1.55 -	 * No need to touch the target chip field
    1.56 -	 */
    1.57 -	cfg = __prepare_ICR(shortcut, vector);
    1.58 -
    1.59 -	/*
    1.60 -	 * Send the IPI. The write to APIC_ICR fires this off.
    1.61 -	 */
    1.62 -	apic_write_around(APIC_ICR, cfg);
    1.63 -#endif
    1.64 +	switch (shortcut) {
    1.65 +	case APIC_DEST_SELF:
    1.66 +		__send_IPI_one(smp_processor_id(), vector);
    1.67 +		break;
    1.68 +	case APIC_DEST_ALLBUT:
    1.69 +		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
    1.70 +			if (cpu == smp_processor_id())
    1.71 +				continue;
    1.72 +			if (cpu_isset(cpu, cpu_online_map)) {
    1.73 +				__send_IPI_one(cpu, vector);
    1.74 +			}
    1.75 +		}
    1.76 +		break;
    1.77 +	default:
    1.78 +		printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
    1.79 +		       vector);
    1.80 +		break;
    1.81 +	}
    1.82  }
    1.83  
    1.84  void fastcall send_IPI_self(int vector)
    1.85 @@ -164,86 +177,26 @@ void fastcall send_IPI_self(int vector)
    1.86  /*
    1.87   * This is only used on smaller machines.
    1.88   */
    1.89 -void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
    1.90 +void send_IPI_mask_bitmask(cpumask_t mask, int vector)
    1.91  {
    1.92 -#if 1
    1.93 -	xxprint("send_IPI_mask_bitmask\n");
    1.94 -	dump_stack();
    1.95 -#else
    1.96 -	unsigned long mask = cpus_addr(cpumask)[0];
    1.97 -	unsigned long cfg;
    1.98  	unsigned long flags;
    1.99 +	unsigned int cpu;
   1.100  
   1.101  	local_irq_save(flags);
   1.102 -		
   1.103 -	/*
   1.104 -	 * Wait for idle.
   1.105 -	 */
   1.106 -	apic_wait_icr_idle();
   1.107 -		
   1.108 -	/*
   1.109 -	 * prepare target chip field
   1.110 -	 */
   1.111 -	cfg = __prepare_ICR2(mask);
   1.112 -	apic_write_around(APIC_ICR2, cfg);
   1.113 -		
   1.114 -	/*
   1.115 -	 * program the ICR 
   1.116 -	 */
   1.117 -	cfg = __prepare_ICR(0, vector);
   1.118 -			
   1.119 -	/*
   1.120 -	 * Send the IPI. The write to APIC_ICR fires this off.
   1.121 -	 */
   1.122 -	apic_write_around(APIC_ICR, cfg);
   1.123 +
   1.124 +	for (cpu = 0; cpu < NR_CPUS; ++cpu) {
   1.125 +		if (cpu_isset(cpu, mask)) {
   1.126 +			__send_IPI_one(cpu, vector);
   1.127 +		}
   1.128 +	}
   1.129  
   1.130  	local_irq_restore(flags);
   1.131 -#endif
   1.132  }
   1.133  
   1.134  inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
   1.135  {
   1.136 -#if 1
   1.137 -	xxprint("send_IPI_mask_sequence\n");
   1.138 -#else
   1.139 -	unsigned long cfg, flags;
   1.140 -	unsigned int query_cpu;
   1.141  
   1.142 -	/*
   1.143 -	 * Hack. The clustered APIC addressing mode doesn't allow us to send 
   1.144 -	 * to an arbitrary mask, so I do a unicasts to each CPU instead. This 
   1.145 -	 * should be modified to do 1 message per cluster ID - mbligh
   1.146 -	 */ 
   1.147 -
   1.148 -	local_irq_save(flags);
   1.149 -
   1.150 -	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
   1.151 -		if (cpu_isset(query_cpu, mask)) {
   1.152 -		
   1.153 -			/*
   1.154 -			 * Wait for idle.
   1.155 -			 */
   1.156 -			apic_wait_icr_idle();
   1.157 -		
   1.158 -			/*
   1.159 -			 * prepare target chip field
   1.160 -			 */
   1.161 -			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
   1.162 -			apic_write_around(APIC_ICR2, cfg);
   1.163 -		
   1.164 -			/*
   1.165 -			 * program the ICR 
   1.166 -			 */
   1.167 -			cfg = __prepare_ICR(0, vector);
   1.168 -			
   1.169 -			/*
   1.170 -			 * Send the IPI. The write to APIC_ICR fires this off.
   1.171 -			 */
   1.172 -			apic_write_around(APIC_ICR, cfg);
   1.173 -		}
   1.174 -	}
   1.175 -	local_irq_restore(flags);
   1.176 -#endif
   1.177 +	send_IPI_mask_bitmask(mask, vector);
   1.178  }
   1.179  
   1.180  #include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
   1.181 @@ -325,7 +278,8 @@ static inline void leave_mm (unsigned lo
   1.182   * 2) Leave the mm if we are in the lazy tlb mode.
   1.183   */
   1.184  
   1.185 -asmlinkage void smp_invalidate_interrupt (void)
   1.186 +irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id,
   1.187 +				     struct pt_regs *regs)
   1.188  {
   1.189  	unsigned long cpu;
   1.190  
   1.191 @@ -351,16 +305,14 @@ asmlinkage void smp_invalidate_interrupt
   1.192  		} else
   1.193  			leave_mm(cpu);
   1.194  	}
   1.195 -#if 1
   1.196 -	xxprint("smp_invalidate_interrupt ack_APIC_irq\n");
   1.197 -#else
   1.198 -	ack_APIC_irq();
   1.199 -#endif
   1.200 +	xxprint("smp_invalidate_interrupt\n");
   1.201  	smp_mb__before_clear_bit();
   1.202  	cpu_clear(cpu, flush_cpumask);
   1.203  	smp_mb__after_clear_bit();
   1.204  out:
   1.205  	put_cpu_no_resched();
   1.206 +
   1.207 +	return IRQ_HANDLED;
   1.208  }
   1.209  
   1.210  static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
   1.211 @@ -561,10 +513,10 @@ int smp_call_function (void (*func) (voi
   1.212  	/* Wait for response */
   1.213  	while (atomic_read(&data.started) != cpus)
   1.214  		barrier();
   1.215 -
   1.216  	if (wait)
   1.217  		while (atomic_read(&data.finished) != cpus)
   1.218  			barrier();
   1.219 +
   1.220  	spin_unlock(&call_lock);
   1.221  
   1.222  	return 0;
   1.223 @@ -609,26 +561,21 @@ void smp_send_stop(void)
   1.224   * all the work is done automatically when
   1.225   * we return from the interrupt.
   1.226   */
   1.227 -asmlinkage void smp_reschedule_interrupt(void)
   1.228 +irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id,
   1.229 +				     struct pt_regs *regs)
   1.230  {
   1.231 -#if 1
   1.232 -	xxprint("smp_reschedule_interrupt: ack_APIC_irq\n");
   1.233 -#else
   1.234 -	ack_APIC_irq();
   1.235 -#endif
   1.236 +
   1.237 +	return IRQ_HANDLED;
   1.238  }
   1.239  
   1.240 -asmlinkage void smp_call_function_interrupt(void)
   1.241 +#include <linux/kallsyms.h>
   1.242 +irqreturn_t smp_call_function_interrupt(int irq, void *dev_id,
   1.243 +					struct pt_regs *regs)
   1.244  {
   1.245  	void (*func) (void *info) = call_data->func;
   1.246  	void *info = call_data->info;
   1.247  	int wait = call_data->wait;
   1.248  
   1.249 -#if 1
   1.250 -	xxprint("smp_call_function_interrupt: ack_APIC_irq\n");
   1.251 -#else
   1.252 -	ack_APIC_irq();
   1.253 -#endif
   1.254  	/*
   1.255  	 * Notify initiating CPU that I've grabbed the data and am
   1.256  	 * about to execute the function
   1.257 @@ -646,5 +593,7 @@ asmlinkage void smp_call_function_interr
   1.258  		mb();
   1.259  		atomic_inc(&call_data->finished);
   1.260  	}
   1.261 +
   1.262 +	return IRQ_HANDLED;
   1.263  }
   1.264  
     2.1 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c	Wed Nov 10 16:00:14 2004 +0000
     2.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c	Wed Nov 10 20:50:47 2004 +0000
     2.3 @@ -457,10 +457,7 @@ static struct irqaction local_irq_debug 
     2.4  
     2.5  void local_setup_debug(void)
     2.6  {
     2.7 -	int time_irq;
     2.8 -
     2.9 -	time_irq = bind_virq_to_irq(VIRQ_DEBUG);
    2.10 -	(void)setup_irq(time_irq, &local_irq_debug);
    2.11 +	(void)setup_irq(bind_virq_to_irq(VIRQ_DEBUG), &local_irq_debug);
    2.12  }
    2.13  
    2.14  
    2.15 @@ -484,6 +481,7 @@ int __init start_secondary(void *unused)
    2.16  	setup_misdirect_virq();
    2.17  	local_setup_timer();
    2.18  	local_setup_debug();	/* XXX */
    2.19 +	smp_intr_init();
    2.20  	local_irq_enable();
    2.21  	/*
    2.22  	 * low-memory mappings have been cleared, flush them from
    2.23 @@ -492,7 +490,7 @@ int __init start_secondary(void *unused)
    2.24  	local_flush_tlb();
    2.25  	cpu_set(smp_processor_id(), cpu_online_map);
    2.26  	wmb();
    2.27 -	if (01) {
    2.28 +	if (0) {
    2.29  		char *msg2 = "delay2\n";
    2.30  		int timeout;
    2.31  		for (timeout = 0; timeout < 50000; timeout++) {
    2.32 @@ -1171,6 +1169,8 @@ static void __init smp_boot_cpus(unsigne
    2.33  		return;
    2.34  	}
    2.35  
    2.36 +	smp_intr_init();
    2.37 +
    2.38  #if 0
    2.39  	connect_bsp_APIC();
    2.40  	setup_local_APIC();
    2.41 @@ -1342,27 +1342,37 @@ void __init smp_cpus_done(unsigned int m
    2.42  #endif
    2.43  }
    2.44  
    2.45 +extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
    2.46 +
    2.47 +static struct irqaction reschedule_irq = {
    2.48 +	smp_reschedule_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "reschedule",
    2.49 +	NULL, NULL
    2.50 +};
    2.51 +
    2.52 +extern irqreturn_t smp_invalidate_interrupt(int, void *, struct pt_regs *);
    2.53 +
    2.54 +static struct irqaction invalidate_irq = {
    2.55 +	smp_invalidate_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "invalidate",
    2.56 +	NULL, NULL
    2.57 +};
    2.58 +
    2.59 +extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
    2.60 +
    2.61 +static struct irqaction call_function_irq = {
    2.62 +	smp_call_function_interrupt, SA_INTERRUPT, CPU_MASK_NONE,
    2.63 +	"call_function", NULL, NULL
    2.64 +};
    2.65 +
    2.66  void __init smp_intr_init(void)
    2.67  {
    2.68 -#if 1
    2.69 -	xxprint("smp_intr_init\n");
    2.70 -#else
    2.71 -	/*
    2.72 -	 * IRQ0 must be given a fixed assignment and initialized,
    2.73 -	 * because it's used before the IO-APIC is set up.
    2.74 -	 */
    2.75 -	set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
    2.76  
    2.77 -	/*
    2.78 -	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
    2.79 -	 * IPI, driven by wakeup.
    2.80 -	 */
    2.81 -	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
    2.82 -
    2.83 -	/* IPI for invalidation */
    2.84 -	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
    2.85 -
    2.86 -	/* IPI for generic function call */
    2.87 -	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
    2.88 -#endif
    2.89 +	(void)setup_irq(
    2.90 +	    bind_ipi_on_cpu_to_irq(smp_processor_id(), RESCHEDULE_VECTOR),
    2.91 +	    &reschedule_irq);
    2.92 +	(void)setup_irq(
    2.93 +	    bind_ipi_on_cpu_to_irq(smp_processor_id(), INVALIDATE_TLB_VECTOR),
    2.94 +	    &invalidate_irq);
    2.95 +	(void)setup_irq(
    2.96 +	    bind_ipi_on_cpu_to_irq(smp_processor_id(), CALL_FUNCTION_VECTOR),
    2.97 +	    &call_function_irq);
    2.98  }
     3.1 --- a/linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c	Wed Nov 10 16:00:14 2004 +0000
     3.2 +++ b/linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c	Wed Nov 10 20:50:47 2004 +0000
     3.3 @@ -63,8 +63,7 @@ static int irq_to_evtchn[NR_IRQS];
     3.4  /* IRQ <-> VIRQ mapping. */
     3.5  DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]);
     3.6  
     3.7 -#define NR_IPIS 8
     3.8 -/* IRQ <-> IPI mapping. */
     3.9 +/* evtchn <-> IPI mapping. */
    3.10  DEFINE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]);
    3.11  
    3.12  /* Reference counts for bindings to IRQs. */
    3.13 @@ -196,38 +195,56 @@ void unbind_virq_from_irq(int virq)
    3.14      spin_unlock(&irq_mapping_update_lock);
    3.15  }
    3.16  
    3.17 -void bind_ipi_on_cpu(int cpu, int ipi)
    3.18 +int bind_ipi_on_cpu_to_irq(int cpu, int ipi)
    3.19  {
    3.20      evtchn_op_t op;
    3.21 +    int evtchn, irq;
    3.22  
    3.23      spin_lock(&irq_mapping_update_lock);
    3.24  
    3.25 -    if (per_cpu(ipi_to_evtchn, cpu)[ipi] == 0) {
    3.26 +    if ( (evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == 0 )
    3.27 +    {
    3.28          op.cmd                 = EVTCHNOP_bind_ipi;
    3.29          op.u.bind_ipi.ipi_edom = cpu;
    3.30          if ( HYPERVISOR_event_channel_op(&op) != 0 )
    3.31              panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu);
    3.32 +        evtchn = op.u.bind_ipi.port;
    3.33  
    3.34 -        per_cpu(ipi_to_evtchn, cpu)[ipi] = op.u.bind_ipi.port;
    3.35 -    }
    3.36 +        irq = find_unbound_irq();
    3.37 +        evtchn_to_irq[evtchn] = irq;
    3.38 +        irq_to_evtchn[irq]    = evtchn;
    3.39 +
    3.40 +        per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn;
    3.41 +    } else
    3.42 +	irq = evtchn_to_irq[evtchn];
    3.43 +
    3.44 +    irq_bindcount[irq]++;
    3.45  
    3.46      spin_unlock(&irq_mapping_update_lock);
    3.47 +
    3.48 +    return irq;
    3.49  }
    3.50  
    3.51 -void unbind_ipi_on_cpu(int cpu, int ipi)
    3.52 +void unbind_ipi_on_cpu_from_irq(int cpu, int ipi)
    3.53  {
    3.54      evtchn_op_t op;
    3.55      int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
    3.56 +    int irq    = irq_to_evtchn[evtchn];
    3.57  
    3.58      spin_lock(&irq_mapping_update_lock);
    3.59  
    3.60 -    op.cmd          = EVTCHNOP_close;
    3.61 -    op.u.close.dom  = DOMID_SELF;
    3.62 -    op.u.close.port = evtchn;
    3.63 -    if ( HYPERVISOR_event_channel_op(&op) != 0 )
    3.64 -	panic("Failed to unbind virtual IPI %d on cpu %d\n", ipi, cpu);
    3.65 +    if ( --irq_bindcount[irq] == 0 )
    3.66 +    {
    3.67 +	op.cmd          = EVTCHNOP_close;
    3.68 +	op.u.close.dom  = DOMID_SELF;
    3.69 +	op.u.close.port = evtchn;
    3.70 +	if ( HYPERVISOR_event_channel_op(&op) != 0 )
    3.71 +	    panic("Failed to unbind virtual IPI %d on cpu %d\n", ipi, cpu);
    3.72  
    3.73 -    per_cpu(ipi_to_evtchn, cpu)[ipi] = 0;
    3.74 +        evtchn_to_irq[evtchn] = -1;
    3.75 +        irq_to_evtchn[irq]    = -1;
    3.76 +	per_cpu(ipi_to_evtchn, cpu)[ipi] = 0;
    3.77 +    }
    3.78  
    3.79      spin_unlock(&irq_mapping_update_lock);
    3.80  }
    3.81 @@ -538,10 +555,11 @@ void __init init_IRQ(void)
    3.82  
    3.83      spin_lock_init(&irq_mapping_update_lock);
    3.84  
    3.85 -    /* No VIRQ -> IRQ mappings. */
    3.86 -    for ( cpu = 0; cpu < NR_CPUS; cpu++ )
    3.87 +    for ( cpu = 0; cpu < NR_CPUS; cpu++ ) {
    3.88 +	/* No VIRQ -> IRQ mappings. */
    3.89  	for ( i = 0; i < NR_VIRQS; i++ )
    3.90  	    per_cpu(virq_to_irq, cpu)[i] = -1;
    3.91 +    }
    3.92  
    3.93      /* No event-channel -> IRQ mappings. */
    3.94      for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
     4.1 --- a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h	Wed Nov 10 16:00:14 2004 +0000
     4.2 +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h	Wed Nov 10 20:50:47 2004 +0000
     4.3 @@ -34,6 +34,7 @@
     4.4   * Vectors 0x20-0x2f are used for ISA interrupts.
     4.5   */
     4.6  
     4.7 +#if 0
     4.8  /*
     4.9   * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
    4.10   *
    4.11 @@ -56,6 +57,7 @@
    4.12   * sources per level' errata.
    4.13   */
    4.14  #define LOCAL_TIMER_VECTOR	0xef
    4.15 +#endif
    4.16  
    4.17  /*
    4.18   * First APIC vector available to drivers: (vectors 0x30-0xee)
    4.19 @@ -65,8 +67,6 @@
    4.20  #define FIRST_DEVICE_VECTOR	0x31
    4.21  #define FIRST_SYSTEM_VECTOR	0xef
    4.22  
    4.23 -/*  #define TIMER_IRQ _EVENT_TIMER */
    4.24 -
    4.25  /*
    4.26   * 16 8259A IRQ's, 208 potential APIC interrupt sources.
    4.27   * Right now the APIC is mostly only used for SMP.
    4.28 @@ -77,6 +77,12 @@
    4.29   * the usable vector space is 0x20-0xff (224 vectors)
    4.30   */
    4.31  
    4.32 +#define NR_IPIS 8
    4.33 +
    4.34 +#define RESCHEDULE_VECTOR	1
    4.35 +#define INVALIDATE_TLB_VECTOR	2
    4.36 +#define CALL_FUNCTION_VECTOR	3
    4.37 +
    4.38  /*
    4.39   * The maximum number of vectors supported by i386 processors
    4.40   * is limited to 256. For processors other than i386, NR_VECTORS
    4.41 @@ -138,8 +144,8 @@
    4.42  /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
    4.43  extern int  bind_virq_to_irq(int virq);
    4.44  extern void unbind_virq_from_irq(int virq);
    4.45 -extern void bind_ipi_on_cpu(int cpu, int ipi);
    4.46 -extern void unbind_ipi_on_cpu(int cpu, int ipi);
    4.47 +extern int  bind_ipi_on_cpu_to_irq(int cpu, int ipi);
    4.48 +extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
    4.49  extern int  bind_evtchn_to_irq(int evtchn);
    4.50  extern void unbind_evtchn_from_irq(int evtchn);
    4.51  
     5.1 --- a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h	Wed Nov 10 16:00:14 2004 +0000
     5.2 +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h	Wed Nov 10 20:50:47 2004 +0000
     5.3 @@ -443,71 +443,80 @@ struct alt_instr {
     5.4  /* 
     5.5   * The use of 'barrier' in the following reflects their use as local-lock
     5.6   * operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
     5.7 - * critical operations are executed. All critical operatiosn must complete
     5.8 + * critical operations are executed. All critical operations must complete
     5.9   * /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
    5.10   * includes these barriers, for example.
    5.11   */
    5.12  
    5.13 -#define __cli()                                                               \
    5.14 -do {                                                                          \
    5.15 -    HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1;              \
    5.16 -    barrier();                                                                \
    5.17 +#define __cli()								\
    5.18 +do {									\
    5.19 +	vcpu_info_t *_vcpu =						\
    5.20 +		&HYPERVISOR_shared_info->vcpu_data[smp_processor_id()];	\
    5.21 +	_vcpu->evtchn_upcall_mask = 1;					\
    5.22 +	barrier();							\
    5.23  } while (0)
    5.24  
    5.25 -#define __sti()                                                               \
    5.26 -do {                                                                          \
    5.27 -    shared_info_t *_shared = HYPERVISOR_shared_info;                          \
    5.28 -    barrier();                                                                \
    5.29 -    _shared->vcpu_data[0].evtchn_upcall_mask = 0;                             \
    5.30 -    barrier(); /* unmask then check (avoid races) */                          \
    5.31 -    if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) )              \
    5.32 -        force_evtchn_callback();                                              \
    5.33 +#define __sti()								\
    5.34 +do {									\
    5.35 +	vcpu_info_t *_vcpu =						\
    5.36 +		&HYPERVISOR_shared_info->vcpu_data[smp_processor_id()];	\
    5.37 +	barrier();							\
    5.38 +	_vcpu->evtchn_upcall_mask = 0;					\
    5.39 +	barrier(); /* unmask then check (avoid races) */		\
    5.40 +	if ( unlikely(_vcpu->evtchn_upcall_pending) )			\
    5.41 +		force_evtchn_callback();				\
    5.42  } while (0)
    5.43  
    5.44 -#define __save_flags(x)                                                       \
    5.45 -do {                                                                          \
    5.46 -    (x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask;            \
    5.47 +#define __save_flags(x)							\
    5.48 +do {									\
    5.49 +	vcpu_info_t *_vcpu =						\
    5.50 +		&HYPERVISOR_shared_info->vcpu_data[smp_processor_id()];	\
    5.51 +	(x) = _vcpu->evtchn_upcall_mask;				\
    5.52  } while (0)
    5.53  
    5.54 -#define __restore_flags(x)                                                    \
    5.55 -do {                                                                          \
    5.56 -    shared_info_t *_shared = HYPERVISOR_shared_info;                          \
    5.57 -    barrier();                                                                \
    5.58 -    if ( (_shared->vcpu_data[0].evtchn_upcall_mask = (x)) == 0 ) {            \
    5.59 -        barrier(); /* unmask then check (avoid races) */                      \
    5.60 -        if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) )          \
    5.61 -            force_evtchn_callback();                                          \
    5.62 -    }                                                                         \
    5.63 +#define __restore_flags(x)						\
    5.64 +do {									\
    5.65 +	vcpu_info_t *_vcpu =						\
    5.66 +		&HYPERVISOR_shared_info->vcpu_data[smp_processor_id()];	\
    5.67 +	barrier();							\
    5.68 +	if ( (_vcpu->evtchn_upcall_mask = (x)) == 0 ) {			\
    5.69 +		barrier(); /* unmask then check (avoid races) */	\
    5.70 +		if ( unlikely(_vcpu->evtchn_upcall_pending) )		\
    5.71 +			force_evtchn_callback();			\
    5.72 +	}								\
    5.73  } while (0)
    5.74  
    5.75 -#define safe_halt()             ((void)0)
    5.76 +#define safe_halt()		((void)0)
    5.77  
    5.78 -#define __save_and_cli(x)                                                     \
    5.79 -do {                                                                          \
    5.80 -    (x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask;            \
    5.81 -    HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1;              \
    5.82 -    barrier();                                                                \
    5.83 +#define __save_and_cli(x)						\
    5.84 +do {									\
    5.85 +	vcpu_info_t *_vcpu =						\
    5.86 +		&HYPERVISOR_shared_info->vcpu_data[smp_processor_id()];	\
    5.87 +	(x) = _vcpu->evtchn_upcall_mask;				\
    5.88 +	_vcpu->evtchn_upcall_mask = 1;					\
    5.89 +	barrier();							\
    5.90  } while (0)
    5.91  
    5.92 -#define __save_and_sti(x)                                                     \
    5.93 -do {                                                                          \
    5.94 -    shared_info_t *_shared = HYPERVISOR_shared_info;                          \
    5.95 -    barrier();                                                                \
    5.96 -    (x) = _shared->vcpu_data[0].evtchn_upcall_mask;                           \
    5.97 -    _shared->vcpu_data[0].evtchn_upcall_mask = 0;                             \
    5.98 -    barrier(); /* unmask then check (avoid races) */                          \
    5.99 -    if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) )              \
   5.100 -        force_evtchn_callback();                                              \
   5.101 +#define __save_and_sti(x)						\
   5.102 +do {									\
   5.103 +	vcpu_info_t *_vcpu =						\
   5.104 +		&HYPERVISOR_shared_info->vcpu_data[smp_processor_id()];	\
   5.105 +	barrier();							\
   5.106 +	(x) = _vcpu->evtchn_upcall_mask;				\
   5.107 +	_vcpu->evtchn_upcall_mask = 0;					\
   5.108 +	barrier(); /* unmask then check (avoid races) */		\
   5.109 +	if ( unlikely(_vcpu->evtchn_upcall_pending) )			\
   5.110 +		force_evtchn_callback();				\
   5.111  } while (0)
   5.112  
   5.113  #define local_irq_save(x)	__save_and_cli(x)
   5.114 -#define local_irq_restore(x)    __restore_flags(x)
   5.115 -#define local_save_flags(x)     __save_flags(x)
   5.116 -#define local_irq_disable()     __cli()
   5.117 -#define local_irq_enable()      __sti()
   5.118 +#define local_irq_restore(x)	__restore_flags(x)
   5.119 +#define local_save_flags(x)	__save_flags(x)
   5.120 +#define local_irq_disable()	__cli()
   5.121 +#define local_irq_enable()	__sti()
   5.122  
   5.123  #define irqs_disabled()			\
   5.124 -	HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask
   5.125 +    HYPERVISOR_shared_info->vcpu_data[smp_processor_id()].evtchn_upcall_mask
   5.126  
   5.127  /*
   5.128   * disable hlt during certain critical i/o operations
     6.1 --- a/xen/common/event_channel.c	Wed Nov 10 16:00:14 2004 +0000
     6.2 +++ b/xen/common/event_channel.c	Wed Nov 10 20:50:47 2004 +0000
     6.3 @@ -28,26 +28,28 @@
     6.4  
     6.5  #define INIT_EVENT_CHANNELS   16
     6.6  #define MAX_EVENT_CHANNELS  1024
     6.7 +#define EVENT_CHANNELS_SPREAD 32
     6.8  
     6.9  
    6.10 -static int get_free_port(struct domain *d)
    6.11 +static int get_free_port(struct exec_domain *ed)
    6.12  {
    6.13 +    struct domain *d = ed->domain;
    6.14      int max, port;
    6.15      event_channel_t *chn;
    6.16  
    6.17      max = d->max_event_channel;
    6.18      chn = d->event_channel;
    6.19  
    6.20 -    for ( port = 0; port < max; port++ )
    6.21 +    for ( port = ed->eid * EVENT_CHANNELS_SPREAD; port < max; port++ )
    6.22          if ( chn[port].state == ECS_FREE )
    6.23              break;
    6.24  
    6.25 -    if ( port == max )
    6.26 +    if ( port >= max )
    6.27      {
    6.28          if ( max == MAX_EVENT_CHANNELS )
    6.29              return -ENOSPC;
    6.30          
    6.31 -        max *= 2;
    6.32 +        max = port + EVENT_CHANNELS_SPREAD;
    6.33          
    6.34          chn = xmalloc(max * sizeof(event_channel_t));
    6.35          if ( unlikely(chn == NULL) )
    6.36 @@ -57,7 +59,8 @@ static int get_free_port(struct domain *
    6.37  
    6.38          if ( d->event_channel != NULL )
    6.39          {
    6.40 -            memcpy(chn, d->event_channel, (max/2) * sizeof(event_channel_t));
    6.41 +            memcpy(chn, d->event_channel, d->max_event_channel *
    6.42 +                   sizeof(event_channel_t));
    6.43              xfree(d->event_channel);
    6.44          }
    6.45  
    6.46 @@ -76,7 +79,7 @@ static long evtchn_alloc_unbound(evtchn_
    6.47  
    6.48      spin_lock(&d->event_channel_lock);
    6.49  
    6.50 -    if ( (port = get_free_port(d)) >= 0 )
    6.51 +    if ( (port = get_free_port(current)) >= 0 )
    6.52      {
    6.53          d->event_channel[port].state = ECS_UNBOUND;
    6.54          d->event_channel[port].u.unbound.remote_domid = alloc->dom;
    6.55 @@ -139,7 +142,7 @@ static long evtchn_bind_interdomain(evtc
    6.56      /* Obtain, or ensure that we already have, a valid <port1>. */
    6.57      if ( port1 == 0 )
    6.58      {
    6.59 -        if ( (port1 = get_free_port(d1)) < 0 )
    6.60 +        if ( (port1 = get_free_port(ed1)) < 0 )
    6.61              ERROR_EXIT(port1);
    6.62      }
    6.63      else if ( port1 >= d1->max_event_channel )
    6.64 @@ -151,7 +154,7 @@ static long evtchn_bind_interdomain(evtc
    6.65          /* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
    6.66          u16 tmp = d1->event_channel[port1].state;
    6.67          d1->event_channel[port1].state = ECS_INTERDOMAIN;
    6.68 -        port2 = get_free_port(d2);
    6.69 +        port2 = get_free_port(ed2);
    6.70          d1->event_channel[port1].state = tmp;
    6.71          if ( port2 < 0 )
    6.72              ERROR_EXIT(port2);
    6.73 @@ -255,7 +258,7 @@ static long evtchn_bind_virq(evtchn_bind
    6.74       */
    6.75      if ( ((port = ed->virq_to_evtchn[virq]) != 0) ||
    6.76           (virq == VIRQ_MISDIRECT) ||
    6.77 -         ((port = get_free_port(d)) < 0) )
    6.78 +         ((port = get_free_port(ed)) < 0) )
    6.79          goto out;
    6.80  
    6.81      d->event_channel[port].state  = ECS_VIRQ;
    6.82 @@ -283,7 +286,7 @@ static long evtchn_bind_ipi(evtchn_bind_
    6.83  
    6.84      spin_lock(&d->event_channel_lock);
    6.85  
    6.86 -    if ( (port = get_free_port(d)) >= 0 )
    6.87 +    if ( (port = get_free_port(ed)) >= 0 )
    6.88      {
    6.89          d->event_channel[port].state      = ECS_IPI;
    6.90          d->event_channel[port].u.ipi_edom = ipi_edom;
    6.91 @@ -312,7 +315,7 @@ static long evtchn_bind_pirq(evtchn_bind
    6.92      spin_lock(&d->event_channel_lock);
    6.93  
    6.94      if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
    6.95 -         ((rc = port = get_free_port(d)) < 0) )
    6.96 +         ((rc = port = get_free_port(current)) < 0) )
    6.97          goto out;
    6.98  
    6.99      d->pirq_to_evtchn[pirq] = port;
   6.100 @@ -476,26 +479,39 @@ static long evtchn_send(int lport)
   6.101  {
   6.102      struct domain *ld = current->domain;
   6.103      struct exec_domain *rd;
   6.104 -    int            rport;
   6.105 +    int            rport, ret = 0;
   6.106  
   6.107      spin_lock(&ld->event_channel_lock);
   6.108  
   6.109      if ( unlikely(lport < 0) ||
   6.110 -         unlikely(lport >= ld->max_event_channel) || 
   6.111 -         unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) )
   6.112 +         unlikely(lport >= ld->max_event_channel))
   6.113      {
   6.114          spin_unlock(&ld->event_channel_lock);
   6.115          return -EINVAL;
   6.116      }
   6.117  
   6.118 -    rd    = ld->event_channel[lport].u.interdomain.remote_dom;
   6.119 -    rport = ld->event_channel[lport].u.interdomain.remote_port;
   6.120 +    switch ( ld->event_channel[lport].state )
   6.121 +    {
   6.122 +    case ECS_INTERDOMAIN:
   6.123 +        rd    = ld->event_channel[lport].u.interdomain.remote_dom;
   6.124 +        rport = ld->event_channel[lport].u.interdomain.remote_port;
   6.125  
   6.126 -    evtchn_set_pending(rd, rport);
   6.127 +        evtchn_set_pending(rd, rport);
   6.128 +        break;
   6.129 +    case ECS_IPI:
   6.130 +        rd = ld->exec_domain[ld->event_channel[lport].u.ipi_edom];
   6.131 +        if ( rd  )
   6.132 +            evtchn_set_pending(rd, lport);
   6.133 +        else
   6.134 +            ret = -EINVAL;
   6.135 +        break;
   6.136 +    default:
   6.137 +        ret = -EINVAL;
   6.138 +    }
   6.139  
   6.140      spin_unlock(&ld->event_channel_lock);
   6.141  
   6.142 -    return 0;
   6.143 +    return ret;
   6.144  }
   6.145  
   6.146