diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:50:25 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:52 -0400 |
commit | da51a821314dd0ec7126f2bf9a62117146fbb6b9 (patch) | |
tree | e44a0a3fe05b6cea98c328419c20f2a6d9e16018 /arch/x86 | |
parent | a1420f395d7721895c05ba3dedf150294d2c0e4d (diff) |
x86: make 32bit use irq_cfg_alloc, etc
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/io_apic_32.c | 180 |
1 files changed, 160 insertions, 20 deletions
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index 033ad953bee3..5a83d7f5b147 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c | |||
@@ -94,41 +94,172 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); | |||
94 | 94 | ||
95 | static int disable_timer_pin_1 __initdata; | 95 | static int disable_timer_pin_1 __initdata; |
96 | 96 | ||
97 | struct irq_cfg; | ||
98 | |||
97 | struct irq_cfg { | 99 | struct irq_cfg { |
100 | unsigned int irq; | ||
101 | struct irq_cfg *next; | ||
98 | u8 vector; | 102 | u8 vector; |
99 | }; | 103 | }; |
100 | 104 | ||
101 | 105 | ||
102 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ | 106 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ |
103 | static struct irq_cfg irq_cfg_legacy[] __initdata = { | 107 | static struct irq_cfg irq_cfg_legacy[] __initdata = { |
104 | [0] = { .vector = FIRST_DEVICE_VECTOR, }, | 108 | [0] = { .irq = 0, .vector = IRQ0_VECTOR, }, |
109 | [1] = { .irq = 1, .vector = IRQ1_VECTOR, }, | ||
110 | [2] = { .irq = 2, .vector = IRQ2_VECTOR, }, | ||
111 | [3] = { .irq = 3, .vector = IRQ3_VECTOR, }, | ||
112 | [4] = { .irq = 4, .vector = IRQ4_VECTOR, }, | ||
113 | [5] = { .irq = 5, .vector = IRQ5_VECTOR, }, | ||
114 | [6] = { .irq = 6, .vector = IRQ6_VECTOR, }, | ||
115 | [7] = { .irq = 7, .vector = IRQ7_VECTOR, }, | ||
116 | [8] = { .irq = 8, .vector = IRQ8_VECTOR, }, | ||
117 | [9] = { .irq = 9, .vector = IRQ9_VECTOR, }, | ||
118 | [10] = { .irq = 10, .vector = IRQ10_VECTOR, }, | ||
119 | [11] = { .irq = 11, .vector = IRQ11_VECTOR, }, | ||
120 | [12] = { .irq = 12, .vector = IRQ12_VECTOR, }, | ||
121 | [13] = { .irq = 13, .vector = IRQ13_VECTOR, }, | ||
122 | [14] = { .irq = 14, .vector = IRQ14_VECTOR, }, | ||
123 | [15] = { .irq = 15, .vector = IRQ15_VECTOR, }, | ||
105 | }; | 124 | }; |
106 | 125 | ||
126 | static struct irq_cfg irq_cfg_init = { .irq = -1U, }; | ||
127 | /* need to be biger than size of irq_cfg_legacy */ | ||
128 | static int nr_irq_cfg = 32; | ||
129 | |||
130 | static int __init parse_nr_irq_cfg(char *arg) | ||
131 | { | ||
132 | if (arg) { | ||
133 | nr_irq_cfg = simple_strtoul(arg, NULL, 0); | ||
134 | if (nr_irq_cfg < 32) | ||
135 | nr_irq_cfg = 32; | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | early_param("nr_irq_cfg", parse_nr_irq_cfg); | ||
141 | |||
142 | static void init_one_irq_cfg(struct irq_cfg *cfg) | ||
143 | { | ||
144 | memcpy(cfg, &irq_cfg_init, sizeof(struct irq_cfg)); | ||
145 | } | ||
146 | |||
147 | static struct irq_cfg *irq_cfgx; | ||
148 | static struct irq_cfg *irq_cfgx_free; | ||
107 | static void __init init_work(void *data) | 149 | static void __init init_work(void *data) |
108 | { | 150 | { |
109 | struct dyn_array *da = data; | 151 | struct dyn_array *da = data; |
110 | struct irq_cfg *cfg; | 152 | struct irq_cfg *cfg; |
111 | int legacy_count; | 153 | int legacy_count; |
112 | int i; | 154 | int i; |
155 | |||
156 | cfg = *da->name; | ||
113 | 157 | ||
114 | cfg = *da->name; | 158 | memcpy(cfg, irq_cfg_legacy, sizeof(irq_cfg_legacy)); |
115 | 159 | ||
116 | legacy_count = sizeof(irq_cfg_legacy)/sizeof(irq_cfg_legacy[0]); | 160 | legacy_count = sizeof(irq_cfg_legacy)/sizeof(irq_cfg_legacy[0]); |
161 | for (i = legacy_count; i < *da->nr; i++) | ||
162 | init_one_irq_cfg(&cfg[i]); | ||
117 | 163 | ||
118 | BUG_ON(legacy_count > nr_irqs); | 164 | for (i = 1; i < *da->nr; i++) |
165 | cfg[i-1].next = &cfg[i]; | ||
119 | 166 | ||
120 | memcpy(cfg, irq_cfg_legacy, sizeof(irq_cfg_legacy)); | 167 | irq_cfgx_free = &irq_cfgx[legacy_count]; |
168 | irq_cfgx[legacy_count - 1].next = NULL; | ||
121 | } | 169 | } |
122 | 170 | ||
123 | static struct irq_cfg *irq_cfgx; | 171 | #define for_each_irq_cfg(cfg) \ |
124 | DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irqs, PAGE_SIZE, init_work); | 172 | for (cfg = irq_cfgx; cfg; cfg = cfg->next) |
173 | |||
174 | DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work); | ||
125 | 175 | ||
126 | static struct irq_cfg *irq_cfg(unsigned int irq) | 176 | static struct irq_cfg *irq_cfg(unsigned int irq) |
127 | { | 177 | { |
128 | if (irq >= nr_irqs) | 178 | struct irq_cfg *cfg; |
129 | return NULL; | 179 | |
180 | cfg = irq_cfgx; | ||
181 | while (cfg) { | ||
182 | if (cfg->irq == irq) | ||
183 | return cfg; | ||
130 | 184 | ||
131 | return &irq_cfgx[irq]; | 185 | cfg = cfg->next; |
186 | } | ||
187 | |||
188 | return NULL; | ||
189 | } | ||
190 | |||
191 | static struct irq_cfg *irq_cfg_alloc(unsigned int irq) | ||
192 | { | ||
193 | struct irq_cfg *cfg, *cfg_pri; | ||
194 | int i; | ||
195 | int count = 0; | ||
196 | |||
197 | cfg_pri = cfg = irq_cfgx; | ||
198 | while (cfg) { | ||
199 | if (cfg->irq == irq) | ||
200 | return cfg; | ||
201 | |||
202 | cfg_pri = cfg; | ||
203 | cfg = cfg->next; | ||
204 | count++; | ||
205 | } | ||
206 | |||
207 | if (!irq_cfgx_free) { | ||
208 | unsigned long phys; | ||
209 | unsigned long total_bytes; | ||
210 | /* | ||
211 | * we run out of pre-allocate ones, allocate more | ||
212 | */ | ||
213 | printk(KERN_DEBUG "try to get more irq_cfg %d\n", nr_irq_cfg); | ||
214 | |||
215 | total_bytes = sizeof(struct irq_cfg) * nr_irq_cfg; | ||
216 | if (after_bootmem) | ||
217 | cfg = kzalloc(total_bytes, GFP_ATOMIC); | ||
218 | else | ||
219 | cfg = __alloc_bootmem_nopanic(total_bytes, PAGE_SIZE, 0); | ||
220 | |||
221 | if (!cfg) | ||
222 | panic("please boot with nr_irq_cfg= %d\n", count * 2); | ||
223 | |||
224 | phys = __pa(cfg); | ||
225 | printk(KERN_DEBUG "irq_irq ==> [%#lx - %#lx]\n", phys, phys + total_bytes); | ||
226 | |||
227 | for (i = 0; i < nr_irq_cfg; i++) | ||
228 | init_one_irq_cfg(&cfg[i]); | ||
229 | |||
230 | for (i = 1; i < nr_irq_cfg; i++) | ||
231 | cfg[i-1].next = &cfg[i]; | ||
232 | |||
233 | irq_cfgx_free = cfg; | ||
234 | } | ||
235 | |||
236 | cfg = irq_cfgx_free; | ||
237 | irq_cfgx_free = irq_cfgx_free->next; | ||
238 | cfg->next = NULL; | ||
239 | if (cfg_pri) | ||
240 | cfg_pri->next = cfg; | ||
241 | else | ||
242 | irq_cfgx = cfg; | ||
243 | cfg->irq = irq; | ||
244 | printk(KERN_DEBUG "found new irq_cfg for irq %d\n", cfg->irq); | ||
245 | |||
246 | #ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG | ||
247 | { | ||
248 | /* dump the results */ | ||
249 | struct irq_cfg *cfg; | ||
250 | unsigned long phys; | ||
251 | unsigned long bytes = sizeof(struct irq_cfg); | ||
252 | |||
253 | printk(KERN_DEBUG "=========================== %d\n", irq); | ||
254 | printk(KERN_DEBUG "irq_cfg dump after get that for %d\n", irq); | ||
255 | for_each_irq_cfg(cfg) { | ||
256 | phys = __pa(cfg); | ||
257 | printk(KERN_DEBUG "irq_cfg %d ==> [%#lx - %#lx]\n", cfg->irq, phys, phys + bytes); | ||
258 | } | ||
259 | printk(KERN_DEBUG "===========================\n"); | ||
260 | } | ||
261 | #endif | ||
262 | return cfg; | ||
132 | } | 263 | } |
133 | 264 | ||
134 | /* | 265 | /* |
@@ -254,6 +385,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin) | |||
254 | { | 385 | { |
255 | struct irq_pin_list *entry = irq_2_pin + irq; | 386 | struct irq_pin_list *entry = irq_2_pin + irq; |
256 | 387 | ||
388 | irq_cfg_alloc(irq); | ||
257 | while (entry->next) | 389 | while (entry->next) |
258 | entry = irq_2_pin + entry->next; | 390 | entry = irq_2_pin + entry->next; |
259 | 391 | ||
@@ -836,11 +968,13 @@ static int __assign_irq_vector(int irq) | |||
836 | { | 968 | { |
837 | static int current_vector = FIRST_DEVICE_VECTOR, current_offset; | 969 | static int current_vector = FIRST_DEVICE_VECTOR, current_offset; |
838 | int vector, offset; | 970 | int vector, offset; |
971 | struct irq_cfg *cfg; | ||
839 | 972 | ||
840 | BUG_ON((unsigned)irq >= nr_irqs); | 973 | BUG_ON((unsigned)irq >= nr_irqs); |
841 | 974 | ||
842 | if (irq_cfg(irq)->vector > 0) | 975 | cfg = irq_cfg(irq); |
843 | return irq_cfg(irq)->vector; | 976 | if (cfg->vector > 0) |
977 | return cfg->vector; | ||
844 | 978 | ||
845 | vector = current_vector; | 979 | vector = current_vector; |
846 | offset = current_offset; | 980 | offset = current_offset; |
@@ -857,7 +991,7 @@ next: | |||
857 | 991 | ||
858 | current_vector = vector; | 992 | current_vector = vector; |
859 | current_offset = offset; | 993 | current_offset = offset; |
860 | irq_cfg(irq)->vector = vector; | 994 | cfg->vector = vector; |
861 | 995 | ||
862 | return vector; | 996 | return vector; |
863 | } | 997 | } |
@@ -1659,6 +1793,7 @@ static inline void init_IO_APIC_traps(void) | |||
1659 | { | 1793 | { |
1660 | int irq; | 1794 | int irq; |
1661 | struct irq_desc *desc; | 1795 | struct irq_desc *desc; |
1796 | struct irq_cfg *cfg; | ||
1662 | 1797 | ||
1663 | /* | 1798 | /* |
1664 | * NOTE! The local APIC isn't very good at handling | 1799 | * NOTE! The local APIC isn't very good at handling |
@@ -1671,8 +1806,9 @@ static inline void init_IO_APIC_traps(void) | |||
1671 | * Also, we've got to be careful not to trash gate | 1806 | * Also, we've got to be careful not to trash gate |
1672 | * 0x80, because int 0x80 is hm, kind of importantish. ;) | 1807 | * 0x80, because int 0x80 is hm, kind of importantish. ;) |
1673 | */ | 1808 | */ |
1674 | for (irq = 0; irq < nr_irqs ; irq++) { | 1809 | for_each_irq_cfg(cfg) { |
1675 | if (IO_APIC_IRQ(irq) && !irq_cfg(irq)->vector) { | 1810 | irq = cfg->irq; |
1811 | if (IO_APIC_IRQ(irq) && !cfg->vector) { | ||
1676 | /* | 1812 | /* |
1677 | * Hmm.. We don't have an entry for this, | 1813 | * Hmm.. We don't have an entry for this, |
1678 | * so default to an old-fashioned 8259 | 1814 | * so default to an old-fashioned 8259 |
@@ -2117,14 +2253,18 @@ int create_irq(void) | |||
2117 | /* Allocate an unused irq */ | 2253 | /* Allocate an unused irq */ |
2118 | int irq, new, vector = 0; | 2254 | int irq, new, vector = 0; |
2119 | unsigned long flags; | 2255 | unsigned long flags; |
2256 | struct irq_cfg *cfg_new; | ||
2120 | 2257 | ||
2121 | irq = -ENOSPC; | 2258 | irq = -ENOSPC; |
2122 | spin_lock_irqsave(&vector_lock, flags); | 2259 | spin_lock_irqsave(&vector_lock, flags); |
2123 | for (new = (nr_irqs - 1); new >= 0; new--) { | 2260 | for (new = (nr_irqs - 1); new >= 0; new--) { |
2124 | if (platform_legacy_irq(new)) | 2261 | if (platform_legacy_irq(new)) |
2125 | continue; | 2262 | continue; |
2126 | if (irq_cfg(new)->vector != 0) | 2263 | cfg_new = irq_cfg(new); |
2264 | if (cfg_new && cfg_new->vector != 0) | ||
2127 | continue; | 2265 | continue; |
2266 | if (!cfg_new) | ||
2267 | cfg_new = irq_cfg_alloc(new); | ||
2128 | vector = __assign_irq_vector(new); | 2268 | vector = __assign_irq_vector(new); |
2129 | if (likely(vector > 0)) | 2269 | if (likely(vector > 0)) |
2130 | irq = new; | 2270 | irq = new; |