diff options
-rw-r--r-- | arch/parisc/kernel/irq.c | 60 | ||||
-rw-r--r-- | drivers/parisc/iosapic.c | 26 | ||||
-rw-r--r-- | include/asm-parisc/irq.h | 5 |
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) | |||
84 | void no_ack_irq(unsigned int irq) { } | 85 | void no_ack_irq(unsigned int irq) { } |
85 | void no_end_irq(unsigned int irq) { } | 86 | void no_end_irq(unsigned int irq) { } |
86 | 87 | ||
88 | #ifdef CONFIG_SMP | ||
89 | int 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 | |||
108 | static 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 | |||
87 | static struct hw_interrupt_type cpu_interrupt_type = { | 117 | static 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 | ||
98 | int show_interrupts(struct seq_file *p, void *v) | 130 | int 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 | ||
264 | unsigned 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 | |||
232 | unsigned long txn_alloc_addr(unsigned int virt_irq) | 271 | unsigned 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 | ||
704 | static 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 | |||
703 | static struct hw_interrupt_type iosapic_interrupt_type = { | 725 | static 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 | ||
714 | int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) | 738 | int 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); | |||
49 | extern int txn_claim_irq(int); | 50 | extern int txn_claim_irq(int); |
50 | extern unsigned int txn_alloc_data(unsigned int); | 51 | extern unsigned int txn_alloc_data(unsigned int); |
51 | extern unsigned long txn_alloc_addr(unsigned int); | 52 | extern unsigned long txn_alloc_addr(unsigned int); |
53 | extern unsigned long txn_affinity_addr(unsigned int irq, int cpu); | ||
52 | 54 | ||
53 | extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); | 55 | extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); |
54 | 56 | extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest); | |
55 | extern 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) */ |
58 | extern struct tasklet_struct power_tasklet; | 59 | extern struct tasklet_struct power_tasklet; |