2010-07-07 11:12:45 +00:00
|
|
|
From: jbeulich@novell.com
|
|
|
|
Subject: fold per-CPU VIRQs onto a single IRQ each
|
2011-04-19 20:09:59 +00:00
|
|
|
Patch-mainline: n/a
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
--- head-2011-02-17.orig/arch/x86/kernel/time-xen.c 2010-11-23 15:07:01.000000000 +0100
|
|
|
|
+++ head-2011-02-17/arch/x86/kernel/time-xen.c 2010-10-05 16:57:34.000000000 +0200
|
|
|
|
@@ -671,19 +671,17 @@ int xen_update_persistent_clock(void)
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Dynamically-mapped IRQ. */
|
|
|
|
-DEFINE_PER_CPU(int, timer_irq);
|
|
|
|
+static int __read_mostly timer_irq = -1;
|
|
|
|
+static struct irqaction timer_action = {
|
|
|
|
+ .handler = timer_interrupt,
|
|
|
|
+ .flags = IRQF_DISABLED|IRQF_TIMER,
|
|
|
|
+ .name = "timer"
|
|
|
|
+};
|
|
|
|
|
|
|
|
static void __init setup_cpu0_timer_irq(void)
|
|
|
|
{
|
|
|
|
- per_cpu(timer_irq, 0) =
|
|
|
|
- bind_virq_to_irqhandler(
|
|
|
|
- VIRQ_TIMER,
|
|
|
|
- 0,
|
|
|
|
- timer_interrupt,
|
|
|
|
- IRQF_DISABLED|IRQF_TIMER|IRQF_NOBALANCING,
|
|
|
|
- "timer0",
|
|
|
|
- NULL);
|
|
|
|
- BUG_ON(per_cpu(timer_irq, 0) < 0);
|
|
|
|
+ timer_irq = bind_virq_to_irqaction(VIRQ_TIMER, 0, &timer_action);
|
|
|
|
+ BUG_ON(timer_irq < 0);
|
|
|
|
}
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
static void __init _late_time_init(void)
|
|
|
|
@@ -829,8 +827,6 @@ void xen_halt(void)
|
|
|
|
}
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
-static char timer_name[NR_CPUS][15];
|
|
|
|
-
|
|
|
|
int __cpuinit local_setup_timer(unsigned int cpu)
|
|
|
|
{
|
|
|
|
int seq, irq;
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -856,16 +852,10 @@ int __cpuinit local_setup_timer(unsigned
|
2010-07-07 11:12:45 +00:00
|
|
|
init_missing_ticks_accounting(cpu);
|
|
|
|
} while (read_seqretry(&xtime_lock, seq));
|
|
|
|
|
|
|
|
- sprintf(timer_name[cpu], "timer%u", cpu);
|
|
|
|
- irq = bind_virq_to_irqhandler(VIRQ_TIMER,
|
|
|
|
- cpu,
|
|
|
|
- timer_interrupt,
|
|
|
|
- IRQF_DISABLED|IRQF_TIMER|IRQF_NOBALANCING,
|
|
|
|
- timer_name[cpu],
|
|
|
|
- NULL);
|
|
|
|
+ irq = bind_virq_to_irqaction(VIRQ_TIMER, cpu, &timer_action);
|
|
|
|
if (irq < 0)
|
|
|
|
return irq;
|
|
|
|
- per_cpu(timer_irq, cpu) = irq;
|
|
|
|
+ BUG_ON(timer_irq != irq);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -873,7 +863,7 @@ int __cpuinit local_setup_timer(unsigned
|
2010-07-07 11:12:45 +00:00
|
|
|
void __cpuinit local_teardown_timer(unsigned int cpu)
|
|
|
|
{
|
|
|
|
BUG_ON(cpu == 0);
|
|
|
|
- unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL);
|
|
|
|
+ unbind_from_per_cpu_irq(timer_irq, cpu, &timer_action);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
--- head-2011-02-17.orig/drivers/xen/core/evtchn.c 2011-02-15 17:52:39.000000000 +0100
|
|
|
|
+++ head-2011-02-17/drivers/xen/core/evtchn.c 2011-02-16 08:29:06.000000000 +0100
|
2010-07-07 11:12:45 +00:00
|
|
|
@@ -59,6 +59,23 @@ static DEFINE_SPINLOCK(irq_mapping_updat
|
|
|
|
static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
|
|
|
|
[0 ... NR_EVENT_CHANNELS-1] = -1 };
|
|
|
|
|
|
|
|
+#if defined(CONFIG_SMP) && defined(CONFIG_X86)
|
2011-04-19 20:09:59 +00:00
|
|
|
+static struct percpu_irqaction {
|
2010-07-07 11:12:45 +00:00
|
|
|
+ struct irqaction action; /* must be first */
|
2011-04-19 20:09:59 +00:00
|
|
|
+ struct percpu_irqaction *next;
|
|
|
|
+ cpumask_var_t cpus;
|
2010-07-07 11:12:45 +00:00
|
|
|
+} *virq_actions[NR_VIRQS];
|
|
|
|
+/* IRQ <-> VIRQ mapping. */
|
|
|
|
+static DECLARE_BITMAP(virq_per_cpu, NR_VIRQS) __read_mostly;
|
2011-04-19 20:09:59 +00:00
|
|
|
+static DEFINE_PER_CPU_READ_MOSTLY(int[NR_VIRQS], virq_to_evtchn);
|
|
|
|
+#define BUG_IF_VIRQ_PER_CPU(irq_cfg) \
|
|
|
|
+ BUG_ON(type_from_irq_cfg(irq_cfg) == IRQT_VIRQ \
|
|
|
|
+ && test_bit(index_from_irq_cfg(irq_cfg), virq_per_cpu))
|
2010-07-07 11:12:45 +00:00
|
|
|
+#else
|
2011-04-19 20:09:59 +00:00
|
|
|
+#define BUG_IF_VIRQ_PER_CPU(irq_cfg) ((void)0)
|
2010-07-07 11:12:45 +00:00
|
|
|
+#define PER_CPU_VIRQ_IRQ
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
/* IRQ <-> IPI mapping. */
|
2011-04-19 20:09:59 +00:00
|
|
|
#if defined(CONFIG_SMP) && defined(CONFIG_X86)
|
|
|
|
static int __read_mostly ipi_irq = -1;
|
|
|
|
@@ -160,21 +177,34 @@ static inline unsigned int type_from_irq
|
|
|
|
return cfg ? type_from_irq_cfg(cfg) : IRQT_UNBOUND;
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
-#ifndef PER_CPU_IPI_IRQ
|
2011-04-19 20:09:59 +00:00
|
|
|
static inline unsigned int evtchn_from_per_cpu_irq(const struct irq_cfg *cfg,
|
|
|
|
unsigned int cpu)
|
2010-07-07 11:12:45 +00:00
|
|
|
{
|
2011-04-19 20:09:59 +00:00
|
|
|
- BUG_ON(type_from_irq_cfg(cfg) != IRQT_IPI);
|
|
|
|
- return per_cpu(ipi_evtchn, cpu);
|
|
|
|
-}
|
|
|
|
+ switch (type_from_irq_cfg(cfg)) {
|
2010-07-07 11:12:45 +00:00
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ case IRQT_VIRQ:
|
2011-04-19 20:09:59 +00:00
|
|
|
+ return per_cpu(virq_to_evtchn, cpu)[index_from_irq_cfg(cfg)];
|
2010-07-07 11:12:45 +00:00
|
|
|
+#endif
|
|
|
|
+#ifndef PER_CPU_IPI_IRQ
|
|
|
|
+ case IRQT_IPI:
|
2011-04-19 20:09:59 +00:00
|
|
|
+ return per_cpu(ipi_evtchn, cpu);
|
|
|
|
#endif
|
2010-07-07 11:12:45 +00:00
|
|
|
+ }
|
|
|
|
+ BUG();
|
|
|
|
+ return 0;
|
2011-04-19 20:09:59 +00:00
|
|
|
+}
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
static inline unsigned int evtchn_from_irq_cfg(const struct irq_cfg *cfg)
|
2010-07-07 11:12:45 +00:00
|
|
|
{
|
2011-04-19 20:09:59 +00:00
|
|
|
+ switch (type_from_irq_cfg(cfg)) {
|
2010-07-07 11:12:45 +00:00
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ case IRQT_VIRQ:
|
|
|
|
+#endif
|
2011-04-19 20:09:59 +00:00
|
|
|
#ifndef PER_CPU_IPI_IRQ
|
|
|
|
- if (type_from_irq_cfg(cfg) == IRQT_IPI)
|
|
|
|
- return evtchn_from_per_cpu_irq(cfg, smp_processor_id());
|
2010-07-07 11:12:45 +00:00
|
|
|
+ case IRQT_IPI:
|
2011-04-19 20:09:59 +00:00
|
|
|
#endif
|
|
|
|
+ return evtchn_from_per_cpu_irq(cfg, smp_processor_id());
|
|
|
|
+ }
|
|
|
|
return cfg->info & ((1U << _EVTCHN_BITS) - 1);
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -357,13 +387,22 @@ asmlinkage void __irq_entry evtchn_do_up
|
|
|
|
* hardirq handlers see an up-to-date system time even if we
|
|
|
|
* have just woken from a long idle period.
|
|
|
|
*/
|
|
|
|
+#ifdef PER_CPU_VIRQ_IRQ
|
|
|
|
if ((irq = percpu_read(virq_to_irq[VIRQ_TIMER])) != -1) {
|
|
|
|
port = evtchn_from_irq(irq);
|
|
|
|
+#else
|
|
|
|
+ port = percpu_read(virq_to_evtchn[VIRQ_TIMER]);
|
|
|
|
+ if (VALID_EVTCHN(port)) {
|
|
|
|
+#endif
|
|
|
|
l1i = port / BITS_PER_LONG;
|
|
|
|
l2i = port % BITS_PER_LONG;
|
|
|
|
if (active_evtchns(l1i) & (1ul<<l2i)) {
|
|
|
|
mask_evtchn(port);
|
|
|
|
clear_evtchn(port);
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ irq = evtchn_to_irq[port];
|
|
|
|
+ BUG_ON(irq == -1);
|
|
|
|
+#endif
|
|
|
|
if (!handle_irq(irq, regs))
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
@@ -588,6 +627,14 @@ static int bind_virq_to_irq(unsigned int
|
2010-07-07 11:12:45 +00:00
|
|
|
evtchn = bind_virq.port;
|
|
|
|
|
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ {
|
|
|
|
+ unsigned int cpu;
|
|
|
|
+
|
|
|
|
+ for_each_possible_cpu(cpu)
|
|
|
|
+ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn;
|
|
|
|
+ }
|
|
|
|
+#endif
|
2011-04-19 20:09:59 +00:00
|
|
|
cfg->info = mk_irq_info(IRQT_VIRQ, virq, evtchn);
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
per_cpu(virq_to_irq, cpu)[virq] = irq;
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -646,7 +693,9 @@ static void unbind_from_irq(unsigned int
|
|
|
|
struct irq_cfg *cfg = irq_cfg(irq);
|
|
|
|
int evtchn = evtchn_from_irq_cfg(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
+ BUG_IF_VIRQ_PER_CPU(cfg);
|
|
|
|
BUG_IF_IPI(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
spin_lock(&irq_mapping_update_lock);
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
if (!--cfg->bindcount && VALID_EVTCHN(evtchn)) {
|
|
|
|
@@ -658,6 +707,11 @@ static void unbind_from_irq(unsigned int
|
2010-07-07 11:12:45 +00:00
|
|
|
case IRQT_VIRQ:
|
|
|
|
per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
|
2011-04-19 20:09:59 +00:00
|
|
|
[index_from_irq_cfg(cfg)] = -1;
|
2010-07-07 11:12:45 +00:00
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ for_each_possible_cpu(cpu)
|
|
|
|
+ per_cpu(virq_to_evtchn, cpu)
|
2011-04-19 20:09:59 +00:00
|
|
|
+ [index_from_irq_cfg(cfg)] = 0;
|
2010-07-07 11:12:45 +00:00
|
|
|
+#endif
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ)
|
|
|
|
case IRQT_IPI:
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -691,13 +745,34 @@ static void unbind_from_irq(unsigned int
|
2010-07-07 11:12:45 +00:00
|
|
|
spin_unlock(&irq_mapping_update_lock);
|
|
|
|
}
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
-#ifndef PER_CPU_IPI_IRQ
|
2010-07-07 11:12:45 +00:00
|
|
|
-void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu)
|
2011-04-19 20:09:59 +00:00
|
|
|
+#if !defined(PER_CPU_IPI_IRQ) || !defined(PER_CPU_VIRQ_IRQ)
|
|
|
|
+static inline struct percpu_irqaction *alloc_percpu_irqaction(gfp_t gfp)
|
|
|
|
+{
|
|
|
|
+ struct percpu_irqaction *new = kzalloc(sizeof(*new), GFP_ATOMIC);
|
|
|
|
+
|
|
|
|
+ if (new && !zalloc_cpumask_var(&new->cpus, gfp)) {
|
|
|
|
+ kfree(new);
|
|
|
|
+ new = NULL;
|
|
|
|
+ }
|
|
|
|
+ return new;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void free_percpu_irqaction(struct percpu_irqaction *action)
|
|
|
|
+{
|
|
|
|
+ if (!action)
|
|
|
|
+ return;
|
|
|
|
+ free_cpumask_var(action->cpus);
|
|
|
|
+ kfree(action);
|
|
|
|
+}
|
|
|
|
+
|
2010-07-07 11:12:45 +00:00
|
|
|
+void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu,
|
|
|
|
+ struct irqaction *action)
|
|
|
|
{
|
|
|
|
struct evtchn_close close;
|
2011-04-19 20:09:59 +00:00
|
|
|
struct irq_data *data = irq_get_irq_data(irq);
|
|
|
|
struct irq_cfg *cfg = irq_data_cfg(data);
|
|
|
|
int evtchn = evtchn_from_per_cpu_irq(cfg, cpu);
|
|
|
|
+ struct percpu_irqaction *free_action = NULL;
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
spin_lock(&irq_mapping_update_lock);
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -706,6 +781,34 @@ void unbind_from_per_cpu_irq(unsigned in
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
BUG_ON(cfg->bindcount <= 1);
|
|
|
|
cfg->bindcount--;
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
2011-04-19 20:09:59 +00:00
|
|
|
+ if (type_from_irq_cfg(cfg) == IRQT_VIRQ) {
|
|
|
|
+ unsigned int virq = index_from_irq_cfg(cfg);
|
|
|
|
+ struct percpu_irqaction *cur, *prev = NULL;
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+ cur = virq_actions[virq];
|
|
|
|
+ while (cur) {
|
|
|
|
+ if (cur->action.dev_id == action) {
|
2011-04-19 20:09:59 +00:00
|
|
|
+ cpumask_clear_cpu(cpu, cur->cpus);
|
|
|
|
+ if (cpumask_empty(cur->cpus)) {
|
|
|
|
+ WARN_ON(free_action);
|
2010-07-07 11:12:45 +00:00
|
|
|
+ if (prev)
|
|
|
|
+ prev->next = cur->next;
|
|
|
|
+ else
|
2011-04-19 20:09:59 +00:00
|
|
|
+ virq_actions[virq]
|
|
|
|
+ = cur->next;
|
|
|
|
+ free_action = cur;
|
2010-07-07 11:12:45 +00:00
|
|
|
+ }
|
2011-04-19 20:09:59 +00:00
|
|
|
+ } else if (cpumask_test_cpu(cpu, cur->cpus))
|
2010-07-07 11:12:45 +00:00
|
|
|
+ evtchn = 0;
|
|
|
|
+ cur = (prev = cur)->next;
|
|
|
|
+ }
|
|
|
|
+ if (!VALID_EVTCHN(evtchn))
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
cpumask_clear_cpu(cpu, data->affinity);
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
close.port = evtchn;
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -713,9 +816,17 @@ void unbind_from_per_cpu_irq(unsigned in
|
2010-07-07 11:12:45 +00:00
|
|
|
BUG();
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
switch (type_from_irq_cfg(cfg)) {
|
2010-07-07 11:12:45 +00:00
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ case IRQT_VIRQ:
|
2011-04-19 20:09:59 +00:00
|
|
|
+ per_cpu(virq_to_evtchn, cpu)
|
|
|
|
+ [index_from_irq_cfg(cfg)] = 0;
|
2010-07-07 11:12:45 +00:00
|
|
|
+ break;
|
|
|
|
+#endif
|
|
|
|
+#ifndef PER_CPU_IPI_IRQ
|
|
|
|
case IRQT_IPI:
|
2011-04-19 20:09:59 +00:00
|
|
|
per_cpu(ipi_evtchn, cpu) = 0;
|
2010-07-07 11:12:45 +00:00
|
|
|
break;
|
|
|
|
+#endif
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
break;
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -727,9 +838,18 @@ void unbind_from_per_cpu_irq(unsigned in
|
2010-07-07 11:12:45 +00:00
|
|
|
evtchn_to_irq[evtchn] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+done:
|
|
|
|
+#endif
|
|
|
|
spin_unlock(&irq_mapping_update_lock);
|
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
+ if (free_action) {
|
|
|
|
+ free_irq(irq, free_action->action.dev_id);
|
|
|
|
+ free_percpu_irqaction(free_action);
|
|
|
|
+ }
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
-#endif /* !PER_CPU_IPI_IRQ */
|
2010-07-07 11:12:45 +00:00
|
|
|
+EXPORT_SYMBOL_GPL(unbind_from_per_cpu_irq);
|
2011-04-19 20:09:59 +00:00
|
|
|
+#endif /* !PER_CPU_IPI_IRQ || !PER_CPU_VIRQ_IRQ */
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
int bind_caller_port_to_irqhandler(
|
|
|
|
unsigned int caller_port,
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -811,6 +931,10 @@ int bind_virq_to_irqhandler(
|
2010-07-07 11:12:45 +00:00
|
|
|
{
|
|
|
|
int irq, retval;
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ BUG_ON(test_bit(virq, virq_per_cpu));
|
|
|
|
+#endif
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
irq = bind_virq_to_irq(virq, cpu);
|
|
|
|
if (irq < 0)
|
|
|
|
return irq;
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -826,6 +950,109 @@ int bind_virq_to_irqhandler(
|
2010-07-07 11:12:45 +00:00
|
|
|
EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+int bind_virq_to_irqaction(
|
|
|
|
+ unsigned int virq,
|
|
|
|
+ unsigned int cpu,
|
|
|
|
+ struct irqaction *action)
|
|
|
|
+{
|
|
|
|
+ struct evtchn_bind_virq bind_virq;
|
2011-04-19 20:09:59 +00:00
|
|
|
+ struct irq_cfg *cfg;
|
2010-07-07 11:12:45 +00:00
|
|
|
+ int evtchn, irq, retval = 0;
|
2011-04-19 20:09:59 +00:00
|
|
|
+ struct percpu_irqaction *cur = NULL, *new;
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+ BUG_ON(!test_bit(virq, virq_per_cpu));
|
|
|
|
+
|
|
|
|
+ if (action->dev_id)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
+ new = alloc_percpu_irqaction(GFP_ATOMIC);
|
2010-07-07 11:12:45 +00:00
|
|
|
+ if (new) {
|
|
|
|
+ new->action = *action;
|
|
|
|
+ new->action.dev_id = action;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ spin_lock(&irq_mapping_update_lock);
|
|
|
|
+
|
|
|
|
+ for (cur = virq_actions[virq]; cur; cur = cur->next)
|
|
|
|
+ if (cur->action.dev_id == action)
|
|
|
|
+ break;
|
|
|
|
+ if (!cur) {
|
|
|
|
+ if (!new) {
|
|
|
|
+ spin_unlock(&irq_mapping_update_lock);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+ new->next = virq_actions[virq];
|
|
|
|
+ virq_actions[virq] = cur = new;
|
2011-04-19 20:09:59 +00:00
|
|
|
+ new = NULL;
|
2010-07-07 11:12:45 +00:00
|
|
|
+ retval = 1;
|
|
|
|
+ }
|
2011-04-19 20:09:59 +00:00
|
|
|
+ cpumask_set_cpu(cpu, cur->cpus);
|
2010-07-07 11:12:45 +00:00
|
|
|
+ action = &cur->action;
|
|
|
|
+
|
|
|
|
+ if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) {
|
|
|
|
+ unsigned int nr;
|
|
|
|
+
|
|
|
|
+ BUG_ON(!retval);
|
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
+ if ((irq = find_unbound_irq(cpu_to_node(cpu), &cfg,
|
|
|
|
+ &dynirq_chip, true)) < 0) {
|
|
|
|
+ virq_actions[virq] = cur->next;
|
2010-07-07 11:12:45 +00:00
|
|
|
+ spin_unlock(&irq_mapping_update_lock);
|
2011-04-19 20:09:59 +00:00
|
|
|
+ free_percpu_irqaction(new);
|
2010-07-07 11:12:45 +00:00
|
|
|
+ return irq;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Extra reference so count will never drop to zero. */
|
2011-04-19 20:09:59 +00:00
|
|
|
+ cfg->bindcount++;
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+ for_each_possible_cpu(nr)
|
|
|
|
+ per_cpu(virq_to_irq, nr)[virq] = irq;
|
2011-04-19 20:09:59 +00:00
|
|
|
+ cfg->info = mk_irq_info(IRQT_VIRQ, virq, 0);
|
|
|
|
+ } else
|
|
|
|
+ cfg = irq_cfg(irq);
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+ evtchn = per_cpu(virq_to_evtchn, cpu)[virq];
|
|
|
|
+ if (!VALID_EVTCHN(evtchn)) {
|
|
|
|
+ bind_virq.virq = virq;
|
|
|
|
+ bind_virq.vcpu = cpu;
|
|
|
|
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
|
|
|
|
+ &bind_virq) != 0)
|
|
|
|
+ BUG();
|
|
|
|
+ evtchn = bind_virq.port;
|
|
|
|
+ evtchn_to_irq[evtchn] = irq;
|
|
|
|
+ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn;
|
|
|
|
+
|
|
|
|
+ bind_evtchn_to_cpu(evtchn, cpu);
|
|
|
|
+ }
|
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
+ cfg->bindcount++;
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+ spin_unlock(&irq_mapping_update_lock);
|
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
+ free_percpu_irqaction(new);
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
+ if (retval == 0) {
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ local_irq_save(flags);
|
|
|
|
+ unmask_evtchn(evtchn);
|
|
|
|
+ local_irq_restore(flags);
|
|
|
|
+ } else {
|
|
|
|
+ action->flags |= IRQF_PERCPU;
|
|
|
|
+ retval = setup_irq(irq, action);
|
|
|
|
+ if (retval) {
|
2011-04-19 20:09:59 +00:00
|
|
|
+ unbind_from_per_cpu_irq(irq, cpu, action);
|
2010-07-07 11:12:45 +00:00
|
|
|
+ BUG_ON(retval > 0);
|
|
|
|
+ irq = retval;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return irq;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(bind_virq_to_irqaction);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
#ifdef PER_CPU_IPI_IRQ
|
|
|
|
int bind_ipi_to_irqhandler(
|
|
|
|
unsigned int ipi,
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -905,7 +1132,7 @@ int __cpuinit bind_ipi_to_irqaction(
|
2010-07-07 11:12:45 +00:00
|
|
|
action->flags |= IRQF_PERCPU | IRQF_NO_SUSPEND;
|
2011-04-19 20:09:59 +00:00
|
|
|
retval = setup_irq(ipi_irq, action);
|
2010-07-07 11:12:45 +00:00
|
|
|
if (retval) {
|
2011-04-19 20:09:59 +00:00
|
|
|
- unbind_from_per_cpu_irq(ipi_irq, cpu);
|
|
|
|
+ unbind_from_per_cpu_irq(ipi_irq, cpu, NULL);
|
2010-07-07 11:12:45 +00:00
|
|
|
BUG_ON(retval > 0);
|
2011-04-19 20:09:59 +00:00
|
|
|
ipi_irq = retval;
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -941,7 +1168,9 @@ static void rebind_irq_to_cpu(struct irq
|
|
|
|
const struct irq_cfg *cfg = irq_data_cfg(data);
|
|
|
|
int evtchn = evtchn_from_irq_cfg(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
+ BUG_IF_VIRQ_PER_CPU(cfg);
|
|
|
|
BUG_IF_IPI(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
|
|
|
if (VALID_EVTCHN(evtchn))
|
|
|
|
rebind_evtchn_to_cpu(evtchn, tcpu);
|
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1233,7 +1462,9 @@ void notify_remote_via_irq(int irq)
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
if (WARN_ON_ONCE(!cfg))
|
|
|
|
return;
|
|
|
|
+ BUG_ON(type_from_irq_cfg(cfg) == IRQT_VIRQ);
|
|
|
|
BUG_IF_IPI(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
+
|
2011-04-19 20:09:59 +00:00
|
|
|
evtchn = evtchn_from_irq_cfg(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
if (VALID_EVTCHN(evtchn))
|
|
|
|
notify_remote_via_evtchn(evtchn);
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1246,6 +1477,7 @@ int irq_to_evtchn_port(int irq)
|
2010-07-07 11:12:45 +00:00
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
if (!cfg)
|
|
|
|
return 0;
|
|
|
|
+ BUG_IF_VIRQ_PER_CPU(cfg);
|
|
|
|
BUG_IF_IPI(cfg);
|
|
|
|
return evtchn_from_irq_cfg(cfg);
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1313,6 +1545,12 @@ static void restore_cpu_virqs(unsigned i
|
2010-07-07 11:12:45 +00:00
|
|
|
if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ if (test_bit(virq, virq_per_cpu)
|
|
|
|
+ && !VALID_EVTCHN(per_cpu(virq_to_evtchn, cpu)[virq]))
|
|
|
|
+ continue;
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
BUG_ON(irq_cfg(irq)->info != mk_irq_info(IRQT_VIRQ, virq, 0));
|
|
|
|
|
|
|
|
/* Get a new binding from Xen. */
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1325,7 +1563,20 @@ static void restore_cpu_virqs(unsigned i
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
/* Record the new mapping. */
|
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
|
+#ifdef PER_CPU_VIRQ_IRQ
|
|
|
|
irq_cfg(irq)->info = mk_irq_info(IRQT_VIRQ, virq, evtchn);
|
|
|
|
+#else
|
|
|
|
+ if (test_bit(virq, virq_per_cpu))
|
|
|
|
+ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn;
|
|
|
|
+ else {
|
|
|
|
+ unsigned int cpu;
|
|
|
|
+
|
|
|
|
+ irq_cfg(irq)->info = mk_irq_info(IRQT_VIRQ, virq,
|
|
|
|
+ evtchn);
|
|
|
|
+ for_each_possible_cpu(cpu)
|
|
|
|
+ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
bind_evtchn_to_cpu(evtchn, cpu);
|
|
|
|
|
|
|
|
/* Ready for use. */
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1389,7 +1640,11 @@ static int evtchn_resume(struct sys_devi
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
/* Avoid doing anything in the 'suspend cancelled' case. */
|
|
|
|
status.dom = DOMID_SELF;
|
|
|
|
+#ifdef PER_CPU_VIRQ_IRQ
|
|
|
|
status.port = evtchn_from_irq(percpu_read(virq_to_irq[VIRQ_TIMER]));
|
|
|
|
+#else
|
|
|
|
+ status.port = percpu_read(virq_to_evtchn[VIRQ_TIMER]);
|
|
|
|
+#endif
|
|
|
|
if (HYPERVISOR_event_channel_op(EVTCHNOP_status, &status))
|
|
|
|
BUG();
|
|
|
|
if (status.status == EVTCHNSTAT_virq
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1666,6 +1921,15 @@ void __init xen_init_IRQ(void)
|
2010-07-07 11:12:45 +00:00
|
|
|
unsigned int i;
|
|
|
|
struct physdev_pirq_eoi_gmfn eoi_gmfn;
|
|
|
|
|
|
|
|
+#ifndef PER_CPU_VIRQ_IRQ
|
|
|
|
+ __set_bit(VIRQ_TIMER, virq_per_cpu);
|
|
|
|
+ __set_bit(VIRQ_DEBUG, virq_per_cpu);
|
|
|
|
+ __set_bit(VIRQ_XENOPROF, virq_per_cpu);
|
|
|
|
+#ifdef CONFIG_IA64
|
|
|
|
+ __set_bit(VIRQ_ITC, virq_per_cpu);
|
|
|
|
+#endif
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
init_evtchn_cpu_bindings();
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
#ifdef CONFIG_SPARSE_IRQ
|
|
|
|
--- head-2011-02-17.orig/drivers/xen/core/smpboot.c 2011-03-03 16:14:20.000000000 +0100
|
|
|
|
+++ head-2011-02-17/drivers/xen/core/smpboot.c 2011-03-03 16:14:51.000000000 +0100
|
|
|
|
@@ -125,7 +125,7 @@ static int __cpuinit xen_smp_intr_init(u
|
2010-07-07 11:12:45 +00:00
|
|
|
fail:
|
|
|
|
xen_spinlock_cleanup(cpu);
|
2011-04-19 20:09:59 +00:00
|
|
|
unbind_ipi:
|
|
|
|
- unbind_from_per_cpu_irq(ipi_irq, cpu);
|
|
|
|
+ unbind_from_per_cpu_irq(ipi_irq, cpu, NULL);
|
2010-07-07 11:12:45 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -135,7 +135,7 @@ static void __cpuinit xen_smp_intr_exit(
|
2010-07-07 11:12:45 +00:00
|
|
|
if (cpu != 0)
|
|
|
|
local_teardown_timer(cpu);
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
- unbind_from_per_cpu_irq(ipi_irq, cpu);
|
|
|
|
+ unbind_from_per_cpu_irq(ipi_irq, cpu, NULL);
|
2010-07-07 11:12:45 +00:00
|
|
|
xen_spinlock_cleanup(cpu);
|
|
|
|
}
|
|
|
|
#endif
|
2011-04-19 20:09:59 +00:00
|
|
|
--- head-2011-02-17.orig/drivers/xen/netback/netback.c 2011-03-01 11:52:43.000000000 +0100
|
|
|
|
+++ head-2011-02-17/drivers/xen/netback/netback.c 2011-03-01 11:53:15.000000000 +0100
|
|
|
|
@@ -1630,6 +1630,12 @@ static irqreturn_t netif_be_dbg(int irq,
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+static struct irqaction netif_be_dbg_action = {
|
|
|
|
+ .handler = netif_be_dbg,
|
|
|
|
+ .flags = IRQF_SHARED,
|
|
|
|
+ .name = "net-be-dbg"
|
|
|
|
+};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int __init netback_init(void)
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -1689,12 +1695,9 @@ static int __init netback_init(void)
|
2010-07-07 11:12:45 +00:00
|
|
|
netif_xenbus_init();
|
|
|
|
|
|
|
|
#ifdef NETBE_DEBUG_INTERRUPT
|
|
|
|
- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
|
|
|
|
- 0,
|
|
|
|
- netif_be_dbg,
|
|
|
|
- IRQF_SHARED,
|
|
|
|
- "net-be-dbg",
|
|
|
|
- &netif_be_dbg);
|
|
|
|
+ (void)bind_virq_to_irqaction(VIRQ_DEBUG,
|
|
|
|
+ 0,
|
|
|
|
+ &netif_be_dbg_action);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
2011-04-19 20:09:59 +00:00
|
|
|
--- head-2011-02-17.orig/drivers/xen/xenoprof/xenoprofile.c 2011-02-01 14:42:26.000000000 +0100
|
|
|
|
+++ head-2011-02-17/drivers/xen/xenoprof/xenoprofile.c 2010-09-09 16:53:30.000000000 +0200
|
|
|
|
@@ -209,6 +209,11 @@ static irqreturn_t xenoprof_ovf_interrup
|
2010-07-07 11:12:45 +00:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static struct irqaction ovf_action = {
|
|
|
|
+ .handler = xenoprof_ovf_interrupt,
|
|
|
|
+ .flags = IRQF_DISABLED,
|
|
|
|
+ .name = "xenoprof"
|
|
|
|
+};
|
|
|
|
|
|
|
|
static void unbind_virq(void)
|
|
|
|
{
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -216,7 +221,7 @@ static void unbind_virq(void)
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
for_each_online_cpu(i) {
|
|
|
|
if (ovf_irq[i] >= 0) {
|
|
|
|
- unbind_from_irqhandler(ovf_irq[i], NULL);
|
|
|
|
+ unbind_from_per_cpu_irq(ovf_irq[i], i, &ovf_action);
|
|
|
|
ovf_irq[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -229,12 +234,7 @@ static int bind_virq(void)
|
2010-07-07 11:12:45 +00:00
|
|
|
int result;
|
|
|
|
|
|
|
|
for_each_online_cpu(i) {
|
|
|
|
- result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
|
|
|
|
- i,
|
|
|
|
- xenoprof_ovf_interrupt,
|
|
|
|
- IRQF_DISABLED|IRQF_NOBALANCING,
|
|
|
|
- "xenoprof",
|
|
|
|
- NULL);
|
|
|
|
+ result = bind_virq_to_irqaction(VIRQ_XENOPROF, i, &ovf_action);
|
|
|
|
|
|
|
|
if (result < 0) {
|
|
|
|
unbind_virq();
|
2011-04-19 20:09:59 +00:00
|
|
|
--- head-2011-02-17.orig/include/xen/evtchn.h 2011-02-02 15:09:43.000000000 +0100
|
|
|
|
+++ head-2011-02-17/include/xen/evtchn.h 2010-11-23 16:18:23.000000000 +0100
|
|
|
|
@@ -94,6 +94,17 @@ int bind_virq_to_irqhandler(
|
2010-07-07 11:12:45 +00:00
|
|
|
unsigned long irqflags,
|
|
|
|
const char *devname,
|
|
|
|
void *dev_id);
|
|
|
|
+#if defined(CONFIG_SMP) && defined(CONFIG_XEN) && defined(CONFIG_X86)
|
|
|
|
+int bind_virq_to_irqaction(
|
|
|
|
+ unsigned int virq,
|
|
|
|
+ unsigned int cpu,
|
|
|
|
+ struct irqaction *action);
|
|
|
|
+#else
|
|
|
|
+#define bind_virq_to_irqaction(virq, cpu, action) \
|
|
|
|
+ bind_virq_to_irqhandler(virq, cpu, (action)->handler, \
|
|
|
|
+ (action)->flags | IRQF_NOBALANCING, \
|
|
|
|
+ (action)->name, action)
|
|
|
|
+#endif
|
|
|
|
#if defined(CONFIG_SMP) && !defined(MODULE)
|
|
|
|
#ifndef CONFIG_X86
|
|
|
|
int bind_ipi_to_irqhandler(
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -118,9 +129,13 @@ DECLARE_PER_CPU(DECLARE_BITMAP(, NR_IPIS
|
2010-07-07 11:12:45 +00:00
|
|
|
*/
|
|
|
|
void unbind_from_irqhandler(unsigned int irq, void *dev_id);
|
|
|
|
|
|
|
|
-#if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86)
|
|
|
|
+#if defined(CONFIG_SMP) && defined(CONFIG_XEN) && defined(CONFIG_X86)
|
|
|
|
/* Specialized unbind function for per-CPU IRQs. */
|
|
|
|
-void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu);
|
|
|
|
+void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu,
|
|
|
|
+ struct irqaction *);
|
|
|
|
+#else
|
|
|
|
+#define unbind_from_per_cpu_irq(irq, cpu, action) \
|
|
|
|
+ unbind_from_irqhandler(irq, action)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef CONFIG_XEN
|