From: jbeulich@novell.com Subject: fold IPIs onto a single IRQ each Patch-mainline: n/a --- head-2010-04-15.orig/arch/x86/kernel/apic/ipi-xen.c 2010-03-24 15:25:06.000000000 +0100 +++ head-2010-04-15/arch/x86/kernel/apic/ipi-xen.c 2010-01-25 13:46:29.000000000 +0100 @@ -21,31 +21,22 @@ #include -DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); - -static inline void __send_IPI_one(unsigned int cpu, int vector) -{ - int irq = per_cpu(ipi_to_irq, cpu)[vector]; - BUG_ON(irq < 0); - notify_remote_via_irq(irq); -} - static void __send_IPI_shortcut(unsigned int shortcut, int vector) { unsigned int cpu; switch (shortcut) { case APIC_DEST_SELF: - __send_IPI_one(smp_processor_id(), vector); + notify_remote_via_ipi(vector, smp_processor_id()); break; case APIC_DEST_ALLBUT: for_each_online_cpu(cpu) if (cpu != smp_processor_id()) - __send_IPI_one(cpu, vector); + notify_remote_via_ipi(vector, cpu); break; case APIC_DEST_ALLINC: for_each_online_cpu(cpu) - __send_IPI_one(cpu, vector); + notify_remote_via_ipi(vector, cpu); break; default: printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut, @@ -63,7 +54,7 @@ void xen_send_IPI_mask_allbutself(const WARN_ON(!cpumask_subset(cpumask, cpu_online_mask)); for_each_cpu_and(cpu, cpumask, cpu_online_mask) if (cpu != smp_processor_id()) - __send_IPI_one(cpu, vector); + notify_remote_via_ipi(vector, cpu); local_irq_restore(flags); } @@ -75,7 +66,7 @@ void xen_send_IPI_mask(const struct cpum local_irq_save(flags); WARN_ON(!cpumask_subset(cpumask, cpu_online_mask)); for_each_cpu_and(cpu, cpumask, cpu_online_mask) - __send_IPI_one(cpu, vector); + notify_remote_via_ipi(vector, cpu); local_irq_restore(flags); } --- head-2010-04-15.orig/arch/x86/kernel/irq-xen.c 2010-03-24 16:00:05.000000000 +0100 +++ head-2010-04-15/arch/x86/kernel/irq-xen.c 2010-01-25 13:46:29.000000000 +0100 @@ -312,6 +312,7 @@ void fixup_irqs(void) affinity = desc->affinity; if (!irq_has_action(irq) || + (desc->status & IRQ_PER_CPU) || cpumask_equal(affinity, cpu_online_mask)) { raw_spin_unlock(&desc->lock); continue; --- head-2010-04-15.orig/drivers/xen/Kconfig 2010-03-31 14:09:58.000000000 +0200 +++ head-2010-04-15/drivers/xen/Kconfig 2010-03-31 14:10:55.000000000 +0200 @@ -4,6 +4,7 @@ config XEN bool + select IRQ_PER_CPU if SMP if XEN config XEN_INTERFACE_VERSION @@ -351,6 +352,9 @@ endmenu config HAVE_IRQ_IGNORE_UNHANDLED def_bool y +config IRQ_PER_CPU + bool + config NO_IDLE_HZ def_bool y --- head-2010-04-15.orig/drivers/xen/core/evtchn.c 2010-04-23 15:20:28.000000000 +0200 +++ head-2010-04-15/drivers/xen/core/evtchn.c 2010-04-23 15:20:31.000000000 +0200 @@ -59,6 +59,22 @@ static DEFINE_SPINLOCK(irq_mapping_updat static int evtchn_to_irq[NR_EVENT_CHANNELS] = { [0 ... NR_EVENT_CHANNELS-1] = -1 }; +/* IRQ <-> IPI mapping. */ +#ifndef NR_IPIS +#define NR_IPIS 1 +#endif +#if defined(CONFIG_SMP) && defined(CONFIG_X86) +static int ipi_to_irq[NR_IPIS] __read_mostly = {[0 ... NR_IPIS-1] = -1}; +static DEFINE_PER_CPU(int[NR_IPIS], ipi_to_evtchn); +#else +#define PER_CPU_IPI_IRQ +#endif +#if !defined(CONFIG_SMP) || !defined(PER_CPU_IPI_IRQ) +#define BUG_IF_IPI(irq) BUG_ON(type_from_irq(irq) == IRQT_IPI) +#else +#define BUG_IF_IPI(irq) ((void)(irq)) +#endif + /* Binding types. */ enum { IRQT_UNBOUND, @@ -117,12 +133,14 @@ static inline u32 mk_irq_info(u32 type, * Accessors for packed IRQ information. */ +#ifdef PER_CPU_IPI_IRQ static inline unsigned int evtchn_from_irq(int irq) { const struct irq_cfg *cfg = irq_cfg(irq); return cfg ? cfg->info & ((1U << _EVTCHN_BITS) - 1) : 0; } +#endif static inline unsigned int index_from_irq(int irq) { @@ -139,6 +157,25 @@ static inline unsigned int type_from_irq return cfg ? cfg->info >> (32 - _IRQT_BITS) : IRQT_UNBOUND; } +#ifndef PER_CPU_IPI_IRQ +static inline unsigned int evtchn_from_per_cpu_irq(unsigned int irq, + unsigned int cpu) +{ + BUG_ON(type_from_irq(irq) != IRQT_IPI); + return per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)]; +} + +static inline unsigned int evtchn_from_irq(unsigned int irq) +{ + if (type_from_irq(irq) != IRQT_IPI) { + const struct irq_cfg *cfg = irq_cfg(irq); + + return cfg ? cfg->info & ((1U << _EVTCHN_BITS) - 1) : 0; + } + return evtchn_from_per_cpu_irq(irq, smp_processor_id()); +} +#endif + unsigned int irq_from_evtchn(unsigned int port) { return evtchn_to_irq[port]; @@ -148,11 +185,10 @@ EXPORT_SYMBOL_GPL(irq_from_evtchn); /* IRQ <-> VIRQ mapping. */ DEFINE_PER_CPU(int[NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1}; +#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) /* IRQ <-> IPI mapping. */ -#ifndef NR_IPIS -#define NR_IPIS 1 -#endif DEFINE_PER_CPU(int[NR_IPIS], ipi_to_irq) = {[0 ... NR_IPIS-1] = -1}; +#endif #ifdef CONFIG_SMP @@ -176,8 +212,14 @@ static void bind_evtchn_to_cpu(unsigned BUG_ON(!test_bit(chn, s->evtchn_mask)); - if (irq != -1) - cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); + if (irq != -1) { + struct irq_desc *desc = irq_to_desc(irq); + + if (!(desc->status & IRQ_PER_CPU)) + cpumask_copy(desc->affinity, cpumask_of(cpu)); + else + cpumask_set_cpu(cpu, desc->affinity); + } clear_bit(chn, per_cpu(cpu_evtchn_mask, cpu_evtchn[chn])); set_bit(chn, per_cpu(cpu_evtchn_mask, cpu)); @@ -350,7 +392,7 @@ asmlinkage void __irq_entry evtchn_do_up static struct irq_chip dynirq_chip; -static int find_unbound_irq(unsigned int cpu) +static int find_unbound_irq(unsigned int cpu, bool percpu) { static int warned; int irq; @@ -360,10 +402,19 @@ static int find_unbound_irq(unsigned int struct irq_cfg *cfg = desc->chip_data; if (!cfg->bindcount) { + irq_flow_handler_t handle; + const char *name; + desc->status |= IRQ_NOPROBE; + if (!percpu) { + handle = handle_level_irq; + name = "level"; + } else { + handle = handle_percpu_irq; + name = "percpu"; + } set_irq_chip_and_handler_name(irq, &dynirq_chip, - handle_level_irq, - "level"); + handle, name); return irq; } } @@ -384,7 +435,7 @@ static int bind_caller_port_to_irq(unsig spin_lock(&irq_mapping_update_lock); if ((irq = evtchn_to_irq[caller_port]) == -1) { - if ((irq = find_unbound_irq(smp_processor_id())) < 0) + if ((irq = find_unbound_irq(smp_processor_id(), false)) < 0) goto out; evtchn_to_irq[caller_port] = irq; @@ -407,7 +458,7 @@ static int bind_local_port_to_irq(unsign BUG_ON(evtchn_to_irq[local_port] != -1); - if ((irq = find_unbound_irq(smp_processor_id())) < 0) { + if ((irq = find_unbound_irq(smp_processor_id(), false)) < 0) { struct evtchn_close close = { .port = local_port }; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) BUG(); @@ -460,7 +511,7 @@ static int bind_virq_to_irq(unsigned int spin_lock(&irq_mapping_update_lock); if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { - if ((irq = find_unbound_irq(cpu)) < 0) + if ((irq = find_unbound_irq(cpu, false)) < 0) goto out; bind_virq.virq = virq; @@ -485,6 +536,7 @@ static int bind_virq_to_irq(unsigned int return irq; } +#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { struct evtchn_bind_ipi bind_ipi; @@ -493,7 +545,7 @@ static int bind_ipi_to_irq(unsigned int spin_lock(&irq_mapping_update_lock); if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { - if ((irq = find_unbound_irq(cpu)) < 0) + if ((irq = find_unbound_irq(cpu, false)) < 0) goto out; bind_ipi.vcpu = cpu; @@ -516,6 +568,7 @@ static int bind_ipi_to_irq(unsigned int spin_unlock(&irq_mapping_update_lock); return irq; } +#endif static void unbind_from_irq(unsigned int irq) { @@ -523,6 +576,7 @@ static void unbind_from_irq(unsigned int unsigned int cpu; int evtchn = evtchn_from_irq(irq); + BUG_IF_IPI(irq); spin_lock(&irq_mapping_update_lock); if (!--irq_cfg(irq)->bindcount && VALID_EVTCHN(evtchn)) { @@ -536,10 +590,12 @@ static void unbind_from_irq(unsigned int per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) [index_from_irq(irq)] = -1; break; +#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) case IRQT_IPI: per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) [index_from_irq(irq)] = -1; break; +#endif default: break; } @@ -562,6 +618,46 @@ static void unbind_from_irq(unsigned int spin_unlock(&irq_mapping_update_lock); } +#if defined(CONFIG_SMP) && !defined(PER_CPU_IPI_IRQ) +void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu) +{ + struct evtchn_close close; + int evtchn = evtchn_from_per_cpu_irq(irq, cpu); + + spin_lock(&irq_mapping_update_lock); + + if (VALID_EVTCHN(evtchn)) { + struct irq_desc *desc = irq_to_desc(irq); + + mask_evtchn(evtchn); + + BUG_ON(irq_cfg(irq)->bindcount <= 1); + irq_cfg(irq)->bindcount--; + cpumask_clear_cpu(cpu, desc->affinity); + + close.port = evtchn; + if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) + BUG(); + + switch (type_from_irq(irq)) { + case IRQT_IPI: + per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)] = 0; + break; + default: + BUG(); + break; + } + + /* Closed ports are implicitly re-bound to VCPU0. */ + bind_evtchn_to_cpu(evtchn, 0); + + evtchn_to_irq[evtchn] = -1; + } + + spin_unlock(&irq_mapping_update_lock); +} +#endif /* CONFIG_SMP && !PER_CPU_IPI_IRQ */ + int bind_caller_port_to_irqhandler( unsigned int caller_port, irq_handler_t handler, @@ -656,6 +752,8 @@ int bind_virq_to_irqhandler( } EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler); +#ifdef CONFIG_SMP +#ifdef PER_CPU_IPI_IRQ int bind_ipi_to_irqhandler( unsigned int ipi, unsigned int cpu, @@ -679,7 +777,71 @@ int bind_ipi_to_irqhandler( return irq; } -EXPORT_SYMBOL_GPL(bind_ipi_to_irqhandler); +#else +int __cpuinit bind_ipi_to_irqaction( + unsigned int ipi, + unsigned int cpu, + struct irqaction *action) +{ + struct evtchn_bind_ipi bind_ipi; + int evtchn, irq, retval = 0; + + spin_lock(&irq_mapping_update_lock); + + if (VALID_EVTCHN(per_cpu(ipi_to_evtchn, cpu)[ipi])) { + spin_unlock(&irq_mapping_update_lock); + return -EBUSY; + } + + if ((irq = ipi_to_irq[ipi]) == -1) { + if ((irq = find_unbound_irq(cpu, true)) < 0) { + spin_unlock(&irq_mapping_update_lock); + return irq; + } + + /* Extra reference so count will never drop to zero. */ + irq_cfg(irq)->bindcount++; + + ipi_to_irq[ipi] = irq; + irq_cfg(irq)->info = mk_irq_info(IRQT_IPI, ipi, 0); + retval = 1; + } + + bind_ipi.vcpu = cpu; + if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, + &bind_ipi) != 0) + BUG(); + + evtchn = bind_ipi.port; + evtchn_to_irq[evtchn] = irq; + per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn; + + bind_evtchn_to_cpu(evtchn, cpu); + + irq_cfg(irq)->bindcount++; + + spin_unlock(&irq_mapping_update_lock); + + if (retval == 0) { + unsigned long flags; + + local_irq_save(flags); + unmask_evtchn(evtchn); + local_irq_restore(flags); + } else { + action->flags |= IRQF_PERCPU | IRQF_NO_SUSPEND; + retval = setup_irq(irq, action); + if (retval) { + unbind_from_per_cpu_irq(irq, cpu); + BUG_ON(retval > 0); + irq = retval; + } + } + + return irq; +} +#endif /* PER_CPU_IPI_IRQ */ +#endif /* CONFIG_SMP */ void unbind_from_irqhandler(unsigned int irq, void *dev_id) { @@ -705,6 +867,7 @@ static void rebind_irq_to_cpu(unsigned i { int evtchn = evtchn_from_irq(irq); + BUG_IF_IPI(irq); if (VALID_EVTCHN(evtchn)) rebind_evtchn_to_cpu(evtchn, tcpu); } @@ -965,10 +1128,21 @@ int irq_ignore_unhandled(unsigned int ir return !!(irq_status.flags & XENIRQSTAT_shared); } +#if defined(CONFIG_SMP) && !defined(PER_CPU_IPI_IRQ) +void notify_remote_via_ipi(unsigned int ipi, unsigned int cpu) +{ + int evtchn = evtchn_from_per_cpu_irq(ipi_to_irq[ipi], cpu); + + if (VALID_EVTCHN(evtchn)) + notify_remote_via_evtchn(evtchn); +} +#endif + void notify_remote_via_irq(int irq) { int evtchn = evtchn_from_irq(irq); + BUG_IF_IPI(irq); if (VALID_EVTCHN(evtchn)) notify_remote_via_evtchn(evtchn); } @@ -976,6 +1150,7 @@ EXPORT_SYMBOL_GPL(notify_remote_via_irq) int irq_to_evtchn_port(int irq) { + BUG_IF_IPI(irq); return evtchn_from_irq(irq); } EXPORT_SYMBOL_GPL(irq_to_evtchn_port); @@ -1091,11 +1266,17 @@ static void restore_cpu_virqs(unsigned i static void restore_cpu_ipis(unsigned int cpu) { +#ifdef CONFIG_SMP struct evtchn_bind_ipi bind_ipi; int ipi, irq, evtchn; for (ipi = 0; ipi < NR_IPIS; ipi++) { +#ifdef PER_CPU_IPI_IRQ if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) +#else + if ((irq = ipi_to_irq[ipi]) == -1 + || !VALID_EVTCHN(per_cpu(ipi_to_evtchn, cpu)[ipi])) +#endif continue; BUG_ON(irq_cfg(irq)->info != mk_irq_info(IRQT_IPI, ipi, 0)); @@ -1109,13 +1290,18 @@ static void restore_cpu_ipis(unsigned in /* Record the new mapping. */ evtchn_to_irq[evtchn] = irq; +#ifdef PER_CPU_IPI_IRQ irq_cfg(irq)->info = mk_irq_info(IRQT_IPI, ipi, evtchn); +#else + per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn; +#endif bind_evtchn_to_cpu(evtchn, cpu); /* Ready for use. */ if (!(irq_to_desc(irq)->status & IRQ_DISABLED)) unmask_evtchn(evtchn); } +#endif } static int evtchn_resume(struct sys_device *dev) --- head-2010-04-15.orig/drivers/xen/core/smpboot.c 2010-03-19 15:20:15.000000000 +0100 +++ head-2010-04-15/drivers/xen/core/smpboot.c 2010-03-19 15:20:24.000000000 +0100 @@ -40,14 +40,10 @@ cpumask_var_t vcpu_initialized_mask; DEFINE_PER_CPU(struct cpuinfo_x86, cpu_info); EXPORT_PER_CPU_SYMBOL(cpu_info); -static DEFINE_PER_CPU(int, resched_irq); -static DEFINE_PER_CPU(int, callfunc_irq); -static DEFINE_PER_CPU(int, call1func_irq); -static DEFINE_PER_CPU(int, reboot_irq); -static char resched_name[NR_CPUS][15]; -static char callfunc_name[NR_CPUS][15]; -static char call1func_name[NR_CPUS][15]; -static char reboot_name[NR_CPUS][15]; +static int __read_mostly resched_irq = -1; +static int __read_mostly callfunc_irq = -1; +static int __read_mostly call1func_irq = -1; +static int __read_mostly reboot_irq = -1; #ifdef CONFIG_X86_LOCAL_APIC #define set_cpu_to_apicid(cpu, apicid) (per_cpu(x86_cpu_to_apicid, cpu) = (apicid)) @@ -109,58 +105,68 @@ remove_siblinginfo(unsigned int cpu) static int __cpuinit xen_smp_intr_init(unsigned int cpu) { + static struct irqaction resched_action = { + .handler = smp_reschedule_interrupt, + .flags = IRQF_DISABLED, + .name = "resched" + }, callfunc_action = { + .handler = smp_call_function_interrupt, + .flags = IRQF_DISABLED, + .name = "callfunc" + }, call1func_action = { + .handler = smp_call_function_single_interrupt, + .flags = IRQF_DISABLED, + .name = "call1func" + }, reboot_action = { + .handler = smp_reboot_interrupt, + .flags = IRQF_DISABLED, + .name = "reboot" + }; int rc; - per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = - per_cpu(call1func_irq, cpu) = per_cpu(reboot_irq, cpu) = -1; - - sprintf(resched_name[cpu], "resched%u", cpu); - rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, - cpu, - smp_reschedule_interrupt, - IRQF_DISABLED|IRQF_NOBALANCING, - resched_name[cpu], - NULL); + rc = bind_ipi_to_irqaction(RESCHEDULE_VECTOR, + cpu, + &resched_action); if (rc < 0) - goto fail; - per_cpu(resched_irq, cpu) = rc; - - sprintf(callfunc_name[cpu], "callfunc%u", cpu); - rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR, - cpu, - smp_call_function_interrupt, - IRQF_DISABLED|IRQF_NOBALANCING, - callfunc_name[cpu], - NULL); + return rc; + if (resched_irq < 0) + resched_irq = rc; + else + BUG_ON(resched_irq != rc); + + rc = bind_ipi_to_irqaction(CALL_FUNCTION_VECTOR, + cpu, + &callfunc_action); if (rc < 0) - goto fail; - per_cpu(callfunc_irq, cpu) = rc; - - sprintf(call1func_name[cpu], "call1func%u", cpu); - rc = bind_ipi_to_irqhandler(CALL_FUNC_SINGLE_VECTOR, - cpu, - smp_call_function_single_interrupt, - IRQF_DISABLED|IRQF_NOBALANCING, - call1func_name[cpu], - NULL); + goto unbind_resched; + if (callfunc_irq < 0) + callfunc_irq = rc; + else + BUG_ON(callfunc_irq != rc); + + rc = bind_ipi_to_irqaction(CALL_FUNC_SINGLE_VECTOR, + cpu, + &call1func_action); if (rc < 0) - goto fail; - per_cpu(call1func_irq, cpu) = rc; - - sprintf(reboot_name[cpu], "reboot%u", cpu); - rc = bind_ipi_to_irqhandler(REBOOT_VECTOR, - cpu, - smp_reboot_interrupt, - IRQF_DISABLED|IRQF_NOBALANCING, - reboot_name[cpu], - NULL); + goto unbind_call; + if (call1func_irq < 0) + call1func_irq = rc; + else + BUG_ON(call1func_irq != rc); + + rc = bind_ipi_to_irqaction(REBOOT_VECTOR, + cpu, + &reboot_action); if (rc < 0) - goto fail; - per_cpu(reboot_irq, cpu) = rc; + goto unbind_call1; + if (reboot_irq < 0) + reboot_irq = rc; + else + BUG_ON(reboot_irq != rc); rc = xen_spinlock_init(cpu); if (rc < 0) - goto fail; + goto unbind_reboot; if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0)) goto fail; @@ -168,15 +174,15 @@ static int __cpuinit xen_smp_intr_init(u return 0; fail: - if (per_cpu(resched_irq, cpu) >= 0) - unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); - if (per_cpu(callfunc_irq, cpu) >= 0) - unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); - if (per_cpu(call1func_irq, cpu) >= 0) - unbind_from_irqhandler(per_cpu(call1func_irq, cpu), NULL); - if (per_cpu(reboot_irq, cpu) >= 0) - unbind_from_irqhandler(per_cpu(reboot_irq, cpu), NULL); xen_spinlock_cleanup(cpu); + unbind_reboot: + unbind_from_per_cpu_irq(reboot_irq, cpu); + unbind_call1: + unbind_from_per_cpu_irq(call1func_irq, cpu); + unbind_call: + unbind_from_per_cpu_irq(callfunc_irq, cpu); + unbind_resched: + unbind_from_per_cpu_irq(resched_irq, cpu); return rc; } @@ -186,10 +192,10 @@ static void __cpuinit xen_smp_intr_exit( if (cpu != 0) local_teardown_timer(cpu); - unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); - unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); - unbind_from_irqhandler(per_cpu(call1func_irq, cpu), NULL); - unbind_from_irqhandler(per_cpu(reboot_irq, cpu), NULL); + unbind_from_per_cpu_irq(resched_irq, cpu); + unbind_from_per_cpu_irq(callfunc_irq, cpu); + unbind_from_per_cpu_irq(call1func_irq, cpu); + unbind_from_per_cpu_irq(reboot_irq, cpu); xen_spinlock_cleanup(cpu); } #endif --- head-2010-04-15.orig/drivers/xen/core/spinlock.c 2010-04-15 10:14:50.000000000 +0200 +++ head-2010-04-15/drivers/xen/core/spinlock.c 2010-02-24 12:38:00.000000000 +0100 @@ -14,8 +14,7 @@ #ifdef TICKET_SHIFT -static DEFINE_PER_CPU(int, spinlock_irq) = -1; -static char spinlock_name[NR_CPUS][15]; +static int __read_mostly spinlock_irq = -1; struct spinning { arch_spinlock_t *lock; @@ -32,29 +31,31 @@ static DEFINE_PER_CPU(arch_rwlock_t, spi int __cpuinit xen_spinlock_init(unsigned int cpu) { + static struct irqaction spinlock_action = { + .handler = smp_reschedule_interrupt, + .flags = IRQF_DISABLED, + .name = "spinlock" + }; int rc; - sprintf(spinlock_name[cpu], "spinlock%u", cpu); - rc = bind_ipi_to_irqhandler(SPIN_UNLOCK_VECTOR, - cpu, - smp_reschedule_interrupt, - IRQF_DISABLED|IRQF_NOBALANCING, - spinlock_name[cpu], - NULL); + rc = bind_ipi_to_irqaction(SPIN_UNLOCK_VECTOR, + cpu, + &spinlock_action); if (rc < 0) return rc; - disable_irq(rc); /* make sure it's never delivered */ - per_cpu(spinlock_irq, cpu) = rc; + if (spinlock_irq < 0) { + disable_irq(rc); /* make sure it's never delivered */ + spinlock_irq = rc; + } else + BUG_ON(spinlock_irq != rc); return 0; } void __cpuinit xen_spinlock_cleanup(unsigned int cpu) { - if (per_cpu(spinlock_irq, cpu) >= 0) - unbind_from_irqhandler(per_cpu(spinlock_irq, cpu), NULL); - per_cpu(spinlock_irq, cpu) = -1; + unbind_from_per_cpu_irq(spinlock_irq, cpu); } static unsigned int spin_adjust(struct spinning *spinning, @@ -84,7 +85,7 @@ unsigned int xen_spin_adjust(const arch_ bool xen_spin_wait(arch_spinlock_t *lock, unsigned int *ptok, unsigned int flags) { - int irq = percpu_read(spinlock_irq); + int irq = spinlock_irq; bool rc; typeof(vcpu_info(0)->evtchn_upcall_mask) upcall_mask; arch_rwlock_t *rm_lock; @@ -240,7 +241,7 @@ void xen_spin_kick(arch_spinlock_t *lock raw_local_irq_restore(flags); if (unlikely(spinning)) { - notify_remote_via_irq(per_cpu(spinlock_irq, cpu)); + notify_remote_via_ipi(SPIN_UNLOCK_VECTOR, cpu); return; } } --- head-2010-04-15.orig/include/xen/evtchn.h 2010-03-31 14:10:36.000000000 +0200 +++ head-2010-04-15/include/xen/evtchn.h 2010-03-31 14:41:42.000000000 +0200 @@ -93,6 +93,8 @@ int bind_virq_to_irqhandler( unsigned long irqflags, const char *devname, void *dev_id); +#if defined(CONFIG_SMP) && !defined(MODULE) +#ifndef CONFIG_X86 int bind_ipi_to_irqhandler( unsigned int ipi, unsigned int cpu, @@ -100,6 +102,13 @@ int bind_ipi_to_irqhandler( unsigned long irqflags, const char *devname, void *dev_id); +#else +int bind_ipi_to_irqaction( + unsigned int ipi, + unsigned int cpu, + struct irqaction *action); +#endif +#endif /* * Common unbind function for all event sources. Takes IRQ to unbind from. @@ -108,6 +117,11 @@ int bind_ipi_to_irqhandler( */ void unbind_from_irqhandler(unsigned int irq, void *dev_id); +#if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86) +/* Specialized unbind function for per-CPU IRQs. */ +void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu); +#endif + #ifndef CONFIG_XEN void irq_resume(void); #endif @@ -183,5 +197,9 @@ void xen_poll_irq(int irq); void notify_remote_via_irq(int irq); int irq_to_evtchn_port(int irq); +#if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86) +void notify_remote_via_ipi(unsigned int ipi, unsigned int cpu); +#endif + #endif /* __ASM_EVTCHN_H__ */ #endif /* CONFIG_PARAVIRT_XEN */