aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/parisc/kernel/irq.c60
-rw-r--r--drivers/parisc/iosapic.c26
-rw-r--r--include/asm-parisc/irq.h5
3 files changed, 86 insertions, 5 deletions
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 865611c15531..2626405e70c4 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -30,6 +30,7 @@
30#include <linux/seq_file.h> 30#include <linux/seq_file.h>
31#include <linux/spinlock.h> 31#include <linux/spinlock.h>
32#include <linux/types.h> 32#include <linux/types.h>
33#include <asm/io.h>
33 34
34#include <asm/smp.h> 35#include <asm/smp.h>
35 36
@@ -84,6 +85,35 @@ static unsigned int cpu_startup_irq(unsigned int irq)
84void no_ack_irq(unsigned int irq) { } 85void no_ack_irq(unsigned int irq) { }
85void no_end_irq(unsigned int irq) { } 86void no_end_irq(unsigned int irq) { }
86 87
88#ifdef CONFIG_SMP
89int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
90{
91 int cpu_dest;
92
93 /* timer and ipi have to always be received on all CPUs */
94 if (irq == TIMER_IRQ || irq == IPI_IRQ) {
95 /* Bad linux design decision. The mask has already
96 * been set; we must reset it */
97 irq_affinity[irq] = CPU_MASK_ALL;
98 return -EINVAL;
99 }
100
101 /* whatever mask they set, we just allow one CPU */
102 cpu_dest = first_cpu(*dest);
103 *dest = cpumask_of_cpu(cpu_dest);
104
105 return 0;
106}
107
108static void cpu_set_affinity_irq(unsigned int irq, cpumask_t dest)
109{
110 if (cpu_check_affinity(irq, &dest))
111 return;
112
113 irq_affinity[irq] = dest;
114}
115#endif
116
87static struct hw_interrupt_type cpu_interrupt_type = { 117static struct hw_interrupt_type cpu_interrupt_type = {
88 .typename = "CPU", 118 .typename = "CPU",
89 .startup = cpu_startup_irq, 119 .startup = cpu_startup_irq,
@@ -92,7 +122,9 @@ static struct hw_interrupt_type cpu_interrupt_type = {
92 .disable = cpu_disable_irq, 122 .disable = cpu_disable_irq,
93 .ack = no_ack_irq, 123 .ack = no_ack_irq,
94 .end = no_end_irq, 124 .end = no_end_irq,
95// .set_affinity = cpu_set_affinity_irq, 125#ifdef CONFIG_SMP
126 .set_affinity = cpu_set_affinity_irq,
127#endif
96}; 128};
97 129
98int show_interrupts(struct seq_file *p, void *v) 130int show_interrupts(struct seq_file *p, void *v)
@@ -229,6 +261,13 @@ int txn_alloc_irq(unsigned int bits_wide)
229 return -1; 261 return -1;
230} 262}
231 263
264unsigned long txn_affinity_addr(unsigned int irq, int cpu)
265{
266 irq_affinity[irq] = cpumask_of_cpu(cpu);
267
268 return cpu_data[cpu].txn_addr;
269}
270
232unsigned long txn_alloc_addr(unsigned int virt_irq) 271unsigned long txn_alloc_addr(unsigned int virt_irq)
233{ 272{
234 static int next_cpu = -1; 273 static int next_cpu = -1;
@@ -243,7 +282,7 @@ unsigned long txn_alloc_addr(unsigned int virt_irq)
243 if (next_cpu >= NR_CPUS) 282 if (next_cpu >= NR_CPUS)
244 next_cpu = 0; /* nothing else, assign monarch */ 283 next_cpu = 0; /* nothing else, assign monarch */
245 284
246 return cpu_data[next_cpu].txn_addr; 285 return txn_affinity_addr(virt_irq, next_cpu);
247} 286}
248 287
249 288
@@ -282,12 +321,29 @@ void do_cpu_irq_mask(struct pt_regs *regs)
282 321
283 /* Work our way from MSb to LSb...same order we alloc EIRs */ 322 /* Work our way from MSb to LSb...same order we alloc EIRs */
284 for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) { 323 for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
324 cpumask_t dest = irq_affinity[irq];
325
285 if (!(bit & eirr_val)) 326 if (!(bit & eirr_val))
286 continue; 327 continue;
287 328
288 /* clear bit in mask - can exit loop sooner */ 329 /* clear bit in mask - can exit loop sooner */
289 eirr_val &= ~bit; 330 eirr_val &= ~bit;
290 331
332 /* FIXME: because generic set affinity mucks
333 * with the affinity before sending it to us
334 * we can get the situation where the affinity is
335 * wrong for our CPU type interrupts */
336 if (irq != TIMER_IRQ && irq != IPI_IRQ &&
337 !cpu_isset(smp_processor_id(), dest)) {
338 int cpu = first_cpu(dest);
339
340 printk("rethrowing irq %d from %d to %d\n",
341 irq, smp_processor_id(), cpu);
342 gsc_writel(irq + CPU_IRQ_BASE,
343 cpu_data[cpu].hpa);
344 continue;
345 }
346
291 __do_IRQ(irq, regs); 347 __do_IRQ(irq, regs);
292 } 348 }
293 } 349 }
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index a39fbfef789a..19657efa8dc3 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -700,6 +700,28 @@ static unsigned int iosapic_startup_irq(unsigned int irq)
700 return 0; 700 return 0;
701} 701}
702 702
703#ifdef CONFIG_SMP
704static void iosapic_set_affinity_irq(unsigned int irq, cpumask_t dest)
705{
706 struct vector_info *vi = iosapic_get_vector(irq);
707 u32 d0, d1, dummy_d0;
708 unsigned long flags;
709
710 if (cpu_check_affinity(irq, &dest))
711 return;
712
713 vi->txn_addr = txn_affinity_addr(irq, first_cpu(dest));
714
715 spin_lock_irqsave(&iosapic_lock, flags);
716 /* d1 contains the destination CPU, so only want to set that
717 * entry */
718 iosapic_rd_irt_entry(vi, &d0, &d1);
719 iosapic_set_irt_data(vi, &dummy_d0, &d1);
720 iosapic_wr_irt_entry(vi, d0, d1);
721 spin_unlock_irqrestore(&iosapic_lock, flags);
722}
723#endif
724
703static struct hw_interrupt_type iosapic_interrupt_type = { 725static struct hw_interrupt_type iosapic_interrupt_type = {
704 .typename = "IO-SAPIC-level", 726 .typename = "IO-SAPIC-level",
705 .startup = iosapic_startup_irq, 727 .startup = iosapic_startup_irq,
@@ -708,7 +730,9 @@ static struct hw_interrupt_type iosapic_interrupt_type = {
708 .disable = iosapic_disable_irq, 730 .disable = iosapic_disable_irq,
709 .ack = no_ack_irq, 731 .ack = no_ack_irq,
710 .end = iosapic_end_irq, 732 .end = iosapic_end_irq,
711// .set_affinity = iosapic_set_affinity_irq, 733#ifdef CONFIG_SMP
734 .set_affinity = iosapic_set_affinity_irq,
735#endif
712}; 736};
713 737
714int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) 738int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
index f876bdf22056..b0a30e2c9813 100644
--- a/include/asm-parisc/irq.h
+++ b/include/asm-parisc/irq.h
@@ -8,6 +8,7 @@
8#define _ASM_PARISC_IRQ_H 8#define _ASM_PARISC_IRQ_H
9 9
10#include <linux/config.h> 10#include <linux/config.h>
11#include <linux/cpumask.h>
11#include <asm/types.h> 12#include <asm/types.h>
12 13
13#define NO_IRQ (-1) 14#define NO_IRQ (-1)
@@ -49,10 +50,10 @@ extern int txn_alloc_irq(unsigned int nbits);
49extern int txn_claim_irq(int); 50extern int txn_claim_irq(int);
50extern unsigned int txn_alloc_data(unsigned int); 51extern unsigned int txn_alloc_data(unsigned int);
51extern unsigned long txn_alloc_addr(unsigned int); 52extern unsigned long txn_alloc_addr(unsigned int);
53extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
52 54
53extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); 55extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
54 56extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest);
55extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
56 57
57/* soft power switch support (power.c) */ 58/* soft power switch support (power.c) */
58extern struct tasklet_struct power_tasklet; 59extern struct tasklet_struct power_tasklet;