diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2009-03-16 20:05:03 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2009-03-17 18:45:29 -0400 |
commit | 05c3dc2c4b60387769cbe73174347de4cf85f0c9 (patch) | |
tree | 7e5918518c5f22f6121ff885283bef5397a0a842 /arch | |
parent | 29b61be65a33c95564fa82e7e8d60d97adb68ea8 (diff) |
x86, ioapic: Fix non atomic allocation with interrupts disabled
Impact: fix possible race
save_mask_IO_APIC_setup() was using non atomic memory allocation while getting
called with interrupts disabled. Fix this by splitting this into two different
function. Allocation part save_IO_APIC_setup() now happens before
disabling interrupts.
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/io_apic.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 11 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 34 |
3 files changed, 31 insertions, 17 deletions
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index ffcd08f96e47..373cc2bbcad2 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h | |||
@@ -162,7 +162,8 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq); | |||
162 | extern void ioapic_init_mappings(void); | 162 | extern void ioapic_init_mappings(void); |
163 | 163 | ||
164 | #ifdef CONFIG_X86_64 | 164 | #ifdef CONFIG_X86_64 |
165 | extern int save_mask_IO_APIC_setup(void); | 165 | extern int save_IO_APIC_setup(void); |
166 | extern void mask_IO_APIC_setup(void); | ||
166 | extern void restore_IO_APIC_setup(void); | 167 | extern void restore_IO_APIC_setup(void); |
167 | extern void reinit_intr_remapped_IO_APIC(int); | 168 | extern void reinit_intr_remapped_IO_APIC(int); |
168 | #endif | 169 | #endif |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 699f8cf76bbb..85eb8e100818 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1334,15 +1334,16 @@ void __init enable_IR_x2apic(void) | |||
1334 | return; | 1334 | return; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | local_irq_save(flags); | 1337 | ret = save_IO_APIC_setup(); |
1338 | mask_8259A(); | ||
1339 | |||
1340 | ret = save_mask_IO_APIC_setup(); | ||
1341 | if (ret) { | 1338 | if (ret) { |
1342 | pr_info("Saving IO-APIC state failed: %d\n", ret); | 1339 | pr_info("Saving IO-APIC state failed: %d\n", ret); |
1343 | goto end; | 1340 | goto end; |
1344 | } | 1341 | } |
1345 | 1342 | ||
1343 | local_irq_save(flags); | ||
1344 | mask_IO_APIC_setup(); | ||
1345 | mask_8259A(); | ||
1346 | |||
1346 | ret = enable_intr_remapping(1); | 1347 | ret = enable_intr_remapping(1); |
1347 | 1348 | ||
1348 | if (ret && x2apic_preenabled) { | 1349 | if (ret && x2apic_preenabled) { |
@@ -1367,10 +1368,10 @@ end_restore: | |||
1367 | else | 1368 | else |
1368 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | 1369 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); |
1369 | 1370 | ||
1370 | end: | ||
1371 | unmask_8259A(); | 1371 | unmask_8259A(); |
1372 | local_irq_restore(flags); | 1372 | local_irq_restore(flags); |
1373 | 1373 | ||
1374 | end: | ||
1374 | if (!ret) { | 1375 | if (!ret) { |
1375 | if (!x2apic_preenabled) | 1376 | if (!x2apic_preenabled) |
1376 | pr_info("Enabled x2apic and interrupt-remapping\n"); | 1377 | pr_info("Enabled x2apic and interrupt-remapping\n"); |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index cf27795c641c..ff1759a1128e 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -853,9 +853,9 @@ __setup("pirq=", ioapic_pirq_setup); | |||
853 | static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS]; | 853 | static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS]; |
854 | 854 | ||
855 | /* | 855 | /* |
856 | * Saves and masks all the unmasked IO-APIC RTE's | 856 | * Saves all the IO-APIC RTE's |
857 | */ | 857 | */ |
858 | int save_mask_IO_APIC_setup(void) | 858 | int save_IO_APIC_setup(void) |
859 | { | 859 | { |
860 | union IO_APIC_reg_01 reg_01; | 860 | union IO_APIC_reg_01 reg_01; |
861 | unsigned long flags; | 861 | unsigned long flags; |
@@ -880,16 +880,9 @@ int save_mask_IO_APIC_setup(void) | |||
880 | } | 880 | } |
881 | 881 | ||
882 | for (apic = 0; apic < nr_ioapics; apic++) | 882 | for (apic = 0; apic < nr_ioapics; apic++) |
883 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { | 883 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) |
884 | struct IO_APIC_route_entry entry; | 884 | early_ioapic_entries[apic][pin] = |
885 | |||
886 | entry = early_ioapic_entries[apic][pin] = | ||
887 | ioapic_read_entry(apic, pin); | 885 | ioapic_read_entry(apic, pin); |
888 | if (!entry.mask) { | ||
889 | entry.mask = 1; | ||
890 | ioapic_write_entry(apic, pin, entry); | ||
891 | } | ||
892 | } | ||
893 | 886 | ||
894 | return 0; | 887 | return 0; |
895 | 888 | ||
@@ -902,6 +895,25 @@ nomem: | |||
902 | return -ENOMEM; | 895 | return -ENOMEM; |
903 | } | 896 | } |
904 | 897 | ||
898 | void mask_IO_APIC_setup(void) | ||
899 | { | ||
900 | int apic, pin; | ||
901 | |||
902 | for (apic = 0; apic < nr_ioapics; apic++) { | ||
903 | if (!early_ioapic_entries[apic]) | ||
904 | break; | ||
905 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { | ||
906 | struct IO_APIC_route_entry entry; | ||
907 | |||
908 | entry = early_ioapic_entries[apic][pin]; | ||
909 | if (!entry.mask) { | ||
910 | entry.mask = 1; | ||
911 | ioapic_write_entry(apic, pin, entry); | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | } | ||
916 | |||
905 | void restore_IO_APIC_setup(void) | 917 | void restore_IO_APIC_setup(void) |
906 | { | 918 | { |
907 | int apic, pin; | 919 | int apic, pin; |