aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/io_apic_32.c
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-08-19 23:50:25 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-16 10:52:52 -0400
commitda51a821314dd0ec7126f2bf9a62117146fbb6b9 (patch)
treee44a0a3fe05b6cea98c328419c20f2a6d9e16018 /arch/x86/kernel/io_apic_32.c
parenta1420f395d7721895c05ba3dedf150294d2c0e4d (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/kernel/io_apic_32.c')
-rw-r--r--arch/x86/kernel/io_apic_32.c180
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 033ad953bee..5a83d7f5b14 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
95static int disable_timer_pin_1 __initdata; 95static int disable_timer_pin_1 __initdata;
96 96
97struct irq_cfg;
98
97struct irq_cfg { 99struct 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. */
103static struct irq_cfg irq_cfg_legacy[] __initdata = { 107static 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
126static struct irq_cfg irq_cfg_init = { .irq = -1U, };
127/* need to be biger than size of irq_cfg_legacy */
128static int nr_irq_cfg = 32;
129
130static 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
140early_param("nr_irq_cfg", parse_nr_irq_cfg);
141
142static void init_one_irq_cfg(struct irq_cfg *cfg)
143{
144 memcpy(cfg, &irq_cfg_init, sizeof(struct irq_cfg));
145}
146
147static struct irq_cfg *irq_cfgx;
148static struct irq_cfg *irq_cfgx_free;
107static void __init init_work(void *data) 149static 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
123static struct irq_cfg *irq_cfgx; 171#define for_each_irq_cfg(cfg) \
124DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irqs, PAGE_SIZE, init_work); 172 for (cfg = irq_cfgx; cfg; cfg = cfg->next)
173
174DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work);
125 175
126static struct irq_cfg *irq_cfg(unsigned int irq) 176static 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
191static 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;