diff options
author | Andi Kleen <ak@suse.de> | 2006-09-26 04:52:30 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:30 -0400 |
commit | cf4c6a2f27f5db810b69dcb1da7f194489e8ff88 (patch) | |
tree | 5fa0570be61c6250065e2d895978ded86631c87d /arch/i386 | |
parent | eea0e11c1f0d6ef89e64182b2f1223a4ca2b74a2 (diff) |
[PATCH] i386: Factor out common io apic routing entry access
The IO APIC code had lots of duplicated code to read/write 64bit
routing entries into the IO-APIC. Factor this out int common read/write
functions
In a few cases the IO APIC lock is taken more often now, but this
isn't a problem because it's all initialization/shutdown only
slow path code.
Similar to earlier x86-64 patch.
Includes a fix by Jiri Slaby for a mistake that broke resume
Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/io_apic.c | 100 |
1 files changed, 43 insertions, 57 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 4eacd52eeb74..b713f27d7e86 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -94,6 +94,34 @@ int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; | |||
94 | #define vector_to_irq(vector) (vector) | 94 | #define vector_to_irq(vector) (vector) |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | |||
98 | union entry_union { | ||
99 | struct { u32 w1, w2; }; | ||
100 | struct IO_APIC_route_entry entry; | ||
101 | }; | ||
102 | |||
103 | static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) | ||
104 | { | ||
105 | union entry_union eu; | ||
106 | unsigned long flags; | ||
107 | spin_lock_irqsave(&ioapic_lock, flags); | ||
108 | eu.w1 = io_apic_read(apic, 0x10 + 2 * pin); | ||
109 | eu.w2 = io_apic_read(apic, 0x11 + 2 * pin); | ||
110 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
111 | return eu.entry; | ||
112 | } | ||
113 | |||
114 | static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) | ||
115 | { | ||
116 | unsigned long flags; | ||
117 | union entry_union eu; | ||
118 | eu.entry = e; | ||
119 | spin_lock_irqsave(&ioapic_lock, flags); | ||
120 | io_apic_write(apic, 0x10 + 2*pin, eu.w1); | ||
121 | io_apic_write(apic, 0x11 + 2*pin, eu.w2); | ||
122 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
123 | } | ||
124 | |||
97 | /* | 125 | /* |
98 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are | 126 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are |
99 | * shared ISA-space IRQs, so we have to support them. We are super | 127 | * shared ISA-space IRQs, so we have to support them. We are super |
@@ -201,13 +229,9 @@ static void unmask_IO_APIC_irq (unsigned int irq) | |||
201 | static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | 229 | static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) |
202 | { | 230 | { |
203 | struct IO_APIC_route_entry entry; | 231 | struct IO_APIC_route_entry entry; |
204 | unsigned long flags; | ||
205 | 232 | ||
206 | /* Check delivery_mode to be sure we're not clearing an SMI pin */ | 233 | /* Check delivery_mode to be sure we're not clearing an SMI pin */ |
207 | spin_lock_irqsave(&ioapic_lock, flags); | 234 | entry = ioapic_read_entry(apic, pin); |
208 | *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); | ||
209 | *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); | ||
210 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
211 | if (entry.delivery_mode == dest_SMI) | 235 | if (entry.delivery_mode == dest_SMI) |
212 | return; | 236 | return; |
213 | 237 | ||
@@ -216,10 +240,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | |||
216 | */ | 240 | */ |
217 | memset(&entry, 0, sizeof(entry)); | 241 | memset(&entry, 0, sizeof(entry)); |
218 | entry.mask = 1; | 242 | entry.mask = 1; |
219 | spin_lock_irqsave(&ioapic_lock, flags); | 243 | ioapic_write_entry(apic, pin, entry); |
220 | io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); | ||
221 | io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); | ||
222 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
223 | } | 244 | } |
224 | 245 | ||
225 | static void clear_IO_APIC (void) | 246 | static void clear_IO_APIC (void) |
@@ -1284,9 +1305,8 @@ static void __init setup_IO_APIC_irqs(void) | |||
1284 | if (!apic && (irq < 16)) | 1305 | if (!apic && (irq < 16)) |
1285 | disable_8259A_irq(irq); | 1306 | disable_8259A_irq(irq); |
1286 | } | 1307 | } |
1308 | ioapic_write_entry(apic, pin, entry); | ||
1287 | spin_lock_irqsave(&ioapic_lock, flags); | 1309 | spin_lock_irqsave(&ioapic_lock, flags); |
1288 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); | ||
1289 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); | ||
1290 | set_native_irq_info(irq, TARGET_CPUS); | 1310 | set_native_irq_info(irq, TARGET_CPUS); |
1291 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1311 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1292 | } | 1312 | } |
@@ -1302,7 +1322,6 @@ static void __init setup_IO_APIC_irqs(void) | |||
1302 | static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) | 1322 | static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) |
1303 | { | 1323 | { |
1304 | struct IO_APIC_route_entry entry; | 1324 | struct IO_APIC_route_entry entry; |
1305 | unsigned long flags; | ||
1306 | 1325 | ||
1307 | memset(&entry,0,sizeof(entry)); | 1326 | memset(&entry,0,sizeof(entry)); |
1308 | 1327 | ||
@@ -1332,10 +1351,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in | |||
1332 | /* | 1351 | /* |
1333 | * Add it to the IO-APIC irq-routing table: | 1352 | * Add it to the IO-APIC irq-routing table: |
1334 | */ | 1353 | */ |
1335 | spin_lock_irqsave(&ioapic_lock, flags); | 1354 | ioapic_write_entry(apic, pin, entry); |
1336 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); | ||
1337 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); | ||
1338 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1339 | 1355 | ||
1340 | enable_8259A_irq(0); | 1356 | enable_8259A_irq(0); |
1341 | } | 1357 | } |
@@ -1445,10 +1461,7 @@ void __init print_IO_APIC(void) | |||
1445 | for (i = 0; i <= reg_01.bits.entries; i++) { | 1461 | for (i = 0; i <= reg_01.bits.entries; i++) { |
1446 | struct IO_APIC_route_entry entry; | 1462 | struct IO_APIC_route_entry entry; |
1447 | 1463 | ||
1448 | spin_lock_irqsave(&ioapic_lock, flags); | 1464 | entry = ioapic_read_entry(apic, i); |
1449 | *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); | ||
1450 | *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); | ||
1451 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1452 | 1465 | ||
1453 | printk(KERN_DEBUG " %02x %03X %02X ", | 1466 | printk(KERN_DEBUG " %02x %03X %02X ", |
1454 | i, | 1467 | i, |
@@ -1667,10 +1680,7 @@ static void __init enable_IO_APIC(void) | |||
1667 | /* See if any of the pins is in ExtINT mode */ | 1680 | /* See if any of the pins is in ExtINT mode */ |
1668 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { | 1681 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { |
1669 | struct IO_APIC_route_entry entry; | 1682 | struct IO_APIC_route_entry entry; |
1670 | spin_lock_irqsave(&ioapic_lock, flags); | 1683 | entry = ioapic_read_entry(apic, pin); |
1671 | *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); | ||
1672 | *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); | ||
1673 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1674 | 1684 | ||
1675 | 1685 | ||
1676 | /* If the interrupt line is enabled and in ExtInt mode | 1686 | /* If the interrupt line is enabled and in ExtInt mode |
@@ -1727,7 +1737,6 @@ void disable_IO_APIC(void) | |||
1727 | */ | 1737 | */ |
1728 | if (ioapic_i8259.pin != -1) { | 1738 | if (ioapic_i8259.pin != -1) { |
1729 | struct IO_APIC_route_entry entry; | 1739 | struct IO_APIC_route_entry entry; |
1730 | unsigned long flags; | ||
1731 | 1740 | ||
1732 | memset(&entry, 0, sizeof(entry)); | 1741 | memset(&entry, 0, sizeof(entry)); |
1733 | entry.mask = 0; /* Enabled */ | 1742 | entry.mask = 0; /* Enabled */ |
@@ -1744,12 +1753,7 @@ void disable_IO_APIC(void) | |||
1744 | /* | 1753 | /* |
1745 | * Add it to the IO-APIC irq-routing table: | 1754 | * Add it to the IO-APIC irq-routing table: |
1746 | */ | 1755 | */ |
1747 | spin_lock_irqsave(&ioapic_lock, flags); | 1756 | ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); |
1748 | io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin, | ||
1749 | *(((int *)&entry)+1)); | ||
1750 | io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin, | ||
1751 | *(((int *)&entry)+0)); | ||
1752 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1753 | } | 1757 | } |
1754 | disconnect_bsp_APIC(ioapic_i8259.pin != -1); | 1758 | disconnect_bsp_APIC(ioapic_i8259.pin != -1); |
1755 | } | 1759 | } |
@@ -2214,17 +2218,13 @@ static inline void unlock_ExtINT_logic(void) | |||
2214 | int apic, pin, i; | 2218 | int apic, pin, i; |
2215 | struct IO_APIC_route_entry entry0, entry1; | 2219 | struct IO_APIC_route_entry entry0, entry1; |
2216 | unsigned char save_control, save_freq_select; | 2220 | unsigned char save_control, save_freq_select; |
2217 | unsigned long flags; | ||
2218 | 2221 | ||
2219 | pin = find_isa_irq_pin(8, mp_INT); | 2222 | pin = find_isa_irq_pin(8, mp_INT); |
2220 | apic = find_isa_irq_apic(8, mp_INT); | 2223 | apic = find_isa_irq_apic(8, mp_INT); |
2221 | if (pin == -1) | 2224 | if (pin == -1) |
2222 | return; | 2225 | return; |
2223 | 2226 | ||
2224 | spin_lock_irqsave(&ioapic_lock, flags); | 2227 | entry0 = ioapic_read_entry(apic, pin); |
2225 | *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin); | ||
2226 | *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin); | ||
2227 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2228 | clear_IO_APIC_pin(apic, pin); | 2228 | clear_IO_APIC_pin(apic, pin); |
2229 | 2229 | ||
2230 | memset(&entry1, 0, sizeof(entry1)); | 2230 | memset(&entry1, 0, sizeof(entry1)); |
@@ -2237,10 +2237,7 @@ static inline void unlock_ExtINT_logic(void) | |||
2237 | entry1.trigger = 0; | 2237 | entry1.trigger = 0; |
2238 | entry1.vector = 0; | 2238 | entry1.vector = 0; |
2239 | 2239 | ||
2240 | spin_lock_irqsave(&ioapic_lock, flags); | 2240 | ioapic_write_entry(apic, pin, entry1); |
2241 | io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); | ||
2242 | io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); | ||
2243 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2244 | 2241 | ||
2245 | save_control = CMOS_READ(RTC_CONTROL); | 2242 | save_control = CMOS_READ(RTC_CONTROL); |
2246 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | 2243 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); |
@@ -2259,10 +2256,7 @@ static inline void unlock_ExtINT_logic(void) | |||
2259 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | 2256 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); |
2260 | clear_IO_APIC_pin(apic, pin); | 2257 | clear_IO_APIC_pin(apic, pin); |
2261 | 2258 | ||
2262 | spin_lock_irqsave(&ioapic_lock, flags); | 2259 | ioapic_write_entry(apic, pin, entry0); |
2263 | io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); | ||
2264 | io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); | ||
2265 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2266 | } | 2260 | } |
2267 | 2261 | ||
2268 | int timer_uses_ioapic_pin_0; | 2262 | int timer_uses_ioapic_pin_0; |
@@ -2462,17 +2456,12 @@ static int ioapic_suspend(struct sys_device *dev, pm_message_t state) | |||
2462 | { | 2456 | { |
2463 | struct IO_APIC_route_entry *entry; | 2457 | struct IO_APIC_route_entry *entry; |
2464 | struct sysfs_ioapic_data *data; | 2458 | struct sysfs_ioapic_data *data; |
2465 | unsigned long flags; | ||
2466 | int i; | 2459 | int i; |
2467 | 2460 | ||
2468 | data = container_of(dev, struct sysfs_ioapic_data, dev); | 2461 | data = container_of(dev, struct sysfs_ioapic_data, dev); |
2469 | entry = data->entry; | 2462 | entry = data->entry; |
2470 | spin_lock_irqsave(&ioapic_lock, flags); | 2463 | for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) |
2471 | for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { | 2464 | entry[i] = ioapic_read_entry(dev->id, i); |
2472 | *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); | ||
2473 | *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); | ||
2474 | } | ||
2475 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2476 | 2465 | ||
2477 | return 0; | 2466 | return 0; |
2478 | } | 2467 | } |
@@ -2494,11 +2483,9 @@ static int ioapic_resume(struct sys_device *dev) | |||
2494 | reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; | 2483 | reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; |
2495 | io_apic_write(dev->id, 0, reg_00.raw); | 2484 | io_apic_write(dev->id, 0, reg_00.raw); |
2496 | } | 2485 | } |
2497 | for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { | ||
2498 | io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); | ||
2499 | io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); | ||
2500 | } | ||
2501 | spin_unlock_irqrestore(&ioapic_lock, flags); | 2486 | spin_unlock_irqrestore(&ioapic_lock, flags); |
2487 | for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) | ||
2488 | ioapic_write_entry(dev->id, i, entry[i]); | ||
2502 | 2489 | ||
2503 | return 0; | 2490 | return 0; |
2504 | } | 2491 | } |
@@ -2695,9 +2682,8 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a | |||
2695 | if (!ioapic && (irq < 16)) | 2682 | if (!ioapic && (irq < 16)) |
2696 | disable_8259A_irq(irq); | 2683 | disable_8259A_irq(irq); |
2697 | 2684 | ||
2685 | ioapic_write_entry(ioapic, pin, entry); | ||
2698 | spin_lock_irqsave(&ioapic_lock, flags); | 2686 | spin_lock_irqsave(&ioapic_lock, flags); |
2699 | io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); | ||
2700 | io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); | ||
2701 | set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); | 2687 | set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); |
2702 | spin_unlock_irqrestore(&ioapic_lock, flags); | 2688 | spin_unlock_irqrestore(&ioapic_lock, flags); |
2703 | 2689 | ||