aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <jejb@parisc-linux.org>2005-11-17 16:28:37 -0500
committerKyle McMartin <kyle@parisc-linux.org>2005-11-17 16:28:37 -0500
commitc2ab64d09815cc4d48347ee3679658f197455a2a (patch)
tree7b6bde77c712c4db52717f70d593c5d8f4ce6bf9
parent1d4c452a85503cdb4bca5925cf698b61d3aa43a0 (diff)
[PARISC] Add IRQ affinities
This really only adds them for the machines I can check SMP on, which is CPU interrupts and IOSAPIC (so not any of the GSC based machines). With this patch, irqbalanced can be used to maintain irq balancing. Unfortunately, irqbalanced is a bit x86 centric, so it doesn't do an incredibly good job, but it does work. Signed-off-by: James Bottomley <jejb@parisc-linux.org> Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
-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;