]>
Commit | Line | Data |
---|---|---|
445bafdd | 1 | diff -ruN linux-2.4.20.orig/arch/i386/kernel/io_apic.c linux-2.4.20/arch/i386/kernel/io_apic.c |
2 | --- linux-2.4.20.orig/arch/i386/kernel/io_apic.c Thu Nov 28 16:53:09 2002 | |
3 | +++ linux-2.4.20/arch/i386/kernel/io_apic.c Tue Dec 17 10:37:58 2002 | |
4 | @@ -28,6 +28,7 @@ | |
5 | #include <linux/config.h> | |
6 | #include <linux/smp_lock.h> | |
7 | #include <linux/mc146818rtc.h> | |
8 | +#include <linux/compiler.h> | |
9 | ||
10 | #include <asm/io.h> | |
11 | #include <asm/smp.h> | |
12 | @@ -188,6 +189,86 @@ | |
13 | clear_IO_APIC_pin(apic, pin); | |
14 | } | |
15 | ||
16 | +static void set_ioapic_affinity (unsigned int irq, unsigned long mask) | |
17 | +{ | |
18 | + unsigned long flags; | |
19 | + | |
20 | + /* | |
21 | + * Only the first 8 bits are valid. | |
22 | + */ | |
23 | + mask = mask << 24; | |
24 | + spin_lock_irqsave(&ioapic_lock, flags); | |
25 | + __DO_ACTION(1, = mask, ) | |
26 | + spin_unlock_irqrestore(&ioapic_lock, flags); | |
27 | +} | |
28 | + | |
29 | +#if CONFIG_SMP | |
30 | + | |
31 | +typedef struct { | |
32 | + unsigned int cpu; | |
33 | + unsigned long timestamp; | |
34 | +} ____cacheline_aligned irq_balance_t; | |
35 | + | |
36 | +static irq_balance_t irq_balance[NR_IRQS] __cacheline_aligned | |
37 | + = { [ 0 ... NR_IRQS-1 ] = { 1, 0 } }; | |
38 | + | |
39 | +extern unsigned long irq_affinity [NR_IRQS]; | |
40 | + | |
41 | +#endif | |
42 | + | |
43 | +#define IDLE_ENOUGH(cpu,now) \ | |
44 | + (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) | |
45 | + | |
46 | +#define IRQ_ALLOWED(cpu,allowed_mask) \ | |
47 | + ((1 << cpu) & (allowed_mask)) | |
48 | + | |
49 | +static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction) | |
50 | +{ | |
51 | + int search_idle = 1; | |
52 | + int cpu = curr_cpu; | |
53 | + | |
54 | + goto inside; | |
55 | + | |
56 | + do { | |
57 | + if (unlikely(cpu == curr_cpu)) | |
58 | + search_idle = 0; | |
59 | +inside: | |
60 | + if (direction == 1) { | |
61 | + cpu++; | |
62 | + if (cpu >= smp_num_cpus) | |
63 | + cpu = 0; | |
64 | + } else { | |
65 | + cpu--; | |
66 | + if (cpu == -1) | |
67 | + cpu = smp_num_cpus-1; | |
68 | + } | |
69 | + } while (!IRQ_ALLOWED(cpu,allowed_mask) || | |
70 | + (search_idle && !IDLE_ENOUGH(cpu,now))); | |
71 | + | |
72 | + return cpu; | |
73 | +} | |
74 | + | |
75 | +static inline void balance_irq(int irq) | |
76 | +{ | |
77 | +#if CONFIG_SMP | |
78 | + irq_balance_t *entry = irq_balance + irq; | |
79 | + unsigned long now = jiffies; | |
80 | + | |
81 | + if (unlikely(entry->timestamp != now)) { | |
82 | + unsigned long allowed_mask; | |
83 | + int random_number; | |
84 | + | |
85 | + rdtscl(random_number); | |
86 | + random_number &= 1; | |
87 | + | |
88 | + allowed_mask = cpu_online_map & irq_affinity[irq]; | |
89 | + entry->timestamp = now; | |
90 | + entry->cpu = move(entry->cpu, allowed_mask, now, random_number); | |
91 | + set_ioapic_affinity(irq, 1 << entry->cpu); | |
92 | + } | |
93 | +#endif | |
94 | +} | |
95 | + | |
96 | /* | |
97 | * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to | |
98 | * specific CPU-side IRQs. | |
99 | @@ -693,8 +774,7 @@ | |
100 | } | |
101 | ||
102 | /* | |
103 | - * Set up the 8259A-master output pin as broadcast to all | |
104 | - * CPUs. | |
105 | + * Set up the 8259A-master output pin: | |
106 | */ | |
107 | void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) | |
108 | { | |
109 | @@ -1214,6 +1294,7 @@ | |
110 | */ | |
111 | static void ack_edge_ioapic_irq(unsigned int irq) | |
112 | { | |
113 | + balance_irq(irq); | |
114 | if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) | |
115 | == (IRQ_PENDING | IRQ_DISABLED)) | |
116 | mask_IO_APIC_irq(irq); | |
117 | @@ -1253,6 +1334,7 @@ | |
118 | unsigned long v; | |
119 | int i; | |
120 | ||
121 | + balance_irq(irq); | |
122 | /* | |
123 | * It appears there is an erratum which affects at least version 0x11 | |
124 | * of I/O APIC (that's the 82093AA and cores integrated into various | |
125 | @@ -1309,19 +1391,6 @@ | |
126 | ||
127 | static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } | |
128 | ||
129 | -static void set_ioapic_affinity (unsigned int irq, unsigned long mask) | |
130 | -{ | |
131 | - unsigned long flags; | |
132 | - /* | |
133 | - * Only the first 8 bits are valid. | |
134 | - */ | |
135 | - mask = mask << 24; | |
136 | - | |
137 | - spin_lock_irqsave(&ioapic_lock, flags); | |
138 | - __DO_ACTION(1, = mask, ) | |
139 | - spin_unlock_irqrestore(&ioapic_lock, flags); | |
140 | -} | |
141 | - | |
142 | /* | |
143 | * Level and edge triggered IO-APIC interrupts need different handling, | |
144 | * so we use two separate IRQ descriptors. Edge triggered IRQs can be | |
145 | diff -ruN linux-2.4.20.orig/arch/i386/kernel/irq.c linux-2.4.20/arch/i386/kernel/irq.c | |
146 | --- linux-2.4.20.orig/arch/i386/kernel/irq.c Thu Nov 28 16:53:09 2002 | |
147 | +++ linux-2.4.20/arch/i386/kernel/irq.c Tue Dec 17 10:37:58 2002 | |
148 | @@ -1090,7 +1090,7 @@ | |
149 | ||
150 | static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; | |
151 | ||
152 | -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; | |
153 | +unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; | |
154 | static int irq_affinity_read_proc (char *page, char **start, off_t off, | |
155 | int count, int *eof, void *data) | |
156 | { | |
157 | diff -ruN linux-2.4.20.orig/include/asm-i386/hardirq.h linux-2.4.20/include/asm-i386/hardirq.h | |
158 | --- linux-2.4.20.orig/include/asm-i386/hardirq.h Thu Nov 22 12:46:19 2001 | |
159 | +++ linux-2.4.20/include/asm-i386/hardirq.h Tue Dec 17 10:37:58 2002 | |
160 | @@ -12,6 +12,7 @@ | |
161 | unsigned int __local_bh_count; | |
162 | unsigned int __syscall_count; | |
163 | struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ | |
164 | + unsigned long idle_timestamp; | |
165 | unsigned int __nmi_count; /* arch dependent */ | |
166 | } ____cacheline_aligned irq_cpustat_t; | |
167 | ||
168 | diff -ruN linux-2.4.20.orig/include/linux/sched.h linux-2.4.20/include/linux/sched.h | |
169 | --- linux-2.4.20.orig/include/linux/sched.h Thu Nov 28 16:53:15 2002 | |
170 | +++ linux-2.4.20/include/linux/sched.h Tue Dec 17 10:37:58 2002 | |
171 | @@ -147,6 +147,7 @@ | |
172 | ||
173 | extern void sched_init(void); | |
174 | extern void init_idle(void); | |
175 | +extern int idle_cpu(int cpu); | |
176 | extern void show_state(void); | |
177 | extern void cpu_init (void); | |
178 | extern void trap_init(void); | |
179 | diff -ruN linux-2.4.20.orig/kernel/sched.c linux-2.4.20/kernel/sched.c | |
180 | --- linux-2.4.20.orig/kernel/sched.c Thu Nov 28 16:53:15 2002 | |
181 | +++ linux-2.4.20/kernel/sched.c Tue Dec 17 10:37:58 2002 | |
182 | @@ -118,6 +118,11 @@ | |
183 | #define can_schedule(p,cpu) \ | |
184 | ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu)) | |
185 | ||
186 | +int idle_cpu(int cpu) | |
187 | +{ | |
188 | + return cpu_curr(cpu) == idle_task(cpu); | |
189 | +} | |
190 | + | |
191 | #else | |
192 | ||
193 | #define idle_task(cpu) (&init_task) |