diff options
author | Fenghua Yu <fenghua.yu@intel.com> | 2009-03-27 17:22:44 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-04-03 16:45:59 -0400 |
commit | b24696bc55f66fecc30715e003f10fc2555a9271 (patch) | |
tree | 3ef565bf041a06106a73d0b27ccc256845ef5644 /arch/x86/kernel/apic/apic.c | |
parent | eb4a52bc660ea835482c582eaaf4893742cbd160 (diff) |
Intel IOMMU Suspend/Resume Support - Interrupt Remapping
This patch enables suspend/resume for interrupt remapping. During suspend,
interrupt remapping is disabled. When resume, interrupt remapping is enabled
again.
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 85eb8e100818..098ec84b8c00 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1304,6 +1304,7 @@ void __init enable_IR_x2apic(void) | |||
1304 | #ifdef CONFIG_INTR_REMAP | 1304 | #ifdef CONFIG_INTR_REMAP |
1305 | int ret; | 1305 | int ret; |
1306 | unsigned long flags; | 1306 | unsigned long flags; |
1307 | struct IO_APIC_route_entry **ioapic_entries = NULL; | ||
1307 | 1308 | ||
1308 | if (!cpu_has_x2apic) | 1309 | if (!cpu_has_x2apic) |
1309 | return; | 1310 | return; |
@@ -1334,17 +1335,23 @@ void __init enable_IR_x2apic(void) | |||
1334 | return; | 1335 | return; |
1335 | } | 1336 | } |
1336 | 1337 | ||
1337 | ret = save_IO_APIC_setup(); | 1338 | ioapic_entries = alloc_ioapic_entries(); |
1339 | if (!ioapic_entries) { | ||
1340 | pr_info("Allocate ioapic_entries failed: %d\n", ret); | ||
1341 | goto end; | ||
1342 | } | ||
1343 | |||
1344 | ret = save_IO_APIC_setup(ioapic_entries); | ||
1338 | if (ret) { | 1345 | if (ret) { |
1339 | pr_info("Saving IO-APIC state failed: %d\n", ret); | 1346 | pr_info("Saving IO-APIC state failed: %d\n", ret); |
1340 | goto end; | 1347 | goto end; |
1341 | } | 1348 | } |
1342 | 1349 | ||
1343 | local_irq_save(flags); | 1350 | local_irq_save(flags); |
1344 | mask_IO_APIC_setup(); | 1351 | mask_IO_APIC_setup(ioapic_entries); |
1345 | mask_8259A(); | 1352 | mask_8259A(); |
1346 | 1353 | ||
1347 | ret = enable_intr_remapping(1); | 1354 | ret = enable_intr_remapping(EIM_32BIT_APIC_ID); |
1348 | 1355 | ||
1349 | if (ret && x2apic_preenabled) { | 1356 | if (ret && x2apic_preenabled) { |
1350 | local_irq_restore(flags); | 1357 | local_irq_restore(flags); |
@@ -1364,9 +1371,9 @@ end_restore: | |||
1364 | /* | 1371 | /* |
1365 | * IR enabling failed | 1372 | * IR enabling failed |
1366 | */ | 1373 | */ |
1367 | restore_IO_APIC_setup(); | 1374 | restore_IO_APIC_setup(ioapic_entries); |
1368 | else | 1375 | else |
1369 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | 1376 | reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries); |
1370 | 1377 | ||
1371 | unmask_8259A(); | 1378 | unmask_8259A(); |
1372 | local_irq_restore(flags); | 1379 | local_irq_restore(flags); |
@@ -1379,6 +1386,8 @@ end: | |||
1379 | pr_info("Enabled Interrupt-remapping\n"); | 1386 | pr_info("Enabled Interrupt-remapping\n"); |
1380 | } else | 1387 | } else |
1381 | pr_err("Failed to enable Interrupt-remapping and x2apic\n"); | 1388 | pr_err("Failed to enable Interrupt-remapping and x2apic\n"); |
1389 | if (ioapic_entries) | ||
1390 | free_ioapic_entries(ioapic_entries); | ||
1382 | #else | 1391 | #else |
1383 | if (!cpu_has_x2apic) | 1392 | if (!cpu_has_x2apic) |
1384 | return; | 1393 | return; |
@@ -1954,6 +1963,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
1954 | 1963 | ||
1955 | local_irq_save(flags); | 1964 | local_irq_save(flags); |
1956 | disable_local_APIC(); | 1965 | disable_local_APIC(); |
1966 | #ifdef CONFIG_INTR_REMAP | ||
1967 | if (intr_remapping_enabled) | ||
1968 | disable_intr_remapping(); | ||
1969 | #endif | ||
1957 | local_irq_restore(flags); | 1970 | local_irq_restore(flags); |
1958 | return 0; | 1971 | return 0; |
1959 | } | 1972 | } |
@@ -1964,15 +1977,41 @@ static int lapic_resume(struct sys_device *dev) | |||
1964 | unsigned long flags; | 1977 | unsigned long flags; |
1965 | int maxlvt; | 1978 | int maxlvt; |
1966 | 1979 | ||
1980 | #ifdef CONFIG_INTR_REMAP | ||
1981 | int ret; | ||
1982 | struct IO_APIC_route_entry **ioapic_entries = NULL; | ||
1983 | |||
1967 | if (!apic_pm_state.active) | 1984 | if (!apic_pm_state.active) |
1968 | return 0; | 1985 | return 0; |
1969 | 1986 | ||
1970 | maxlvt = lapic_get_maxlvt(); | ||
1971 | |||
1972 | local_irq_save(flags); | 1987 | local_irq_save(flags); |
1988 | if (x2apic) { | ||
1989 | ioapic_entries = alloc_ioapic_entries(); | ||
1990 | if (!ioapic_entries) { | ||
1991 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); | ||
1992 | return -ENOMEM; | ||
1993 | } | ||
1994 | |||
1995 | ret = save_IO_APIC_setup(ioapic_entries); | ||
1996 | if (ret) { | ||
1997 | WARN(1, "Saving IO-APIC state failed: %d\n", ret); | ||
1998 | free_ioapic_entries(ioapic_entries); | ||
1999 | return ret; | ||
2000 | } | ||
2001 | |||
2002 | mask_IO_APIC_setup(ioapic_entries); | ||
2003 | mask_8259A(); | ||
2004 | enable_x2apic(); | ||
2005 | } | ||
2006 | #else | ||
2007 | if (!apic_pm_state.active) | ||
2008 | return 0; | ||
1973 | 2009 | ||
2010 | local_irq_save(flags); | ||
1974 | if (x2apic) | 2011 | if (x2apic) |
1975 | enable_x2apic(); | 2012 | enable_x2apic(); |
2013 | #endif | ||
2014 | |||
1976 | else { | 2015 | else { |
1977 | /* | 2016 | /* |
1978 | * Make sure the APICBASE points to the right address | 2017 | * Make sure the APICBASE points to the right address |
@@ -1986,6 +2025,7 @@ static int lapic_resume(struct sys_device *dev) | |||
1986 | wrmsr(MSR_IA32_APICBASE, l, h); | 2025 | wrmsr(MSR_IA32_APICBASE, l, h); |
1987 | } | 2026 | } |
1988 | 2027 | ||
2028 | maxlvt = lapic_get_maxlvt(); | ||
1989 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); | 2029 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); |
1990 | apic_write(APIC_ID, apic_pm_state.apic_id); | 2030 | apic_write(APIC_ID, apic_pm_state.apic_id); |
1991 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); | 2031 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); |
@@ -2009,8 +2049,20 @@ static int lapic_resume(struct sys_device *dev) | |||
2009 | apic_write(APIC_ESR, 0); | 2049 | apic_write(APIC_ESR, 0); |
2010 | apic_read(APIC_ESR); | 2050 | apic_read(APIC_ESR); |
2011 | 2051 | ||
2052 | #ifdef CONFIG_INTR_REMAP | ||
2053 | if (intr_remapping_enabled) | ||
2054 | reenable_intr_remapping(EIM_32BIT_APIC_ID); | ||
2055 | |||
2056 | if (x2apic) { | ||
2057 | unmask_8259A(); | ||
2058 | restore_IO_APIC_setup(ioapic_entries); | ||
2059 | free_ioapic_entries(ioapic_entries); | ||
2060 | } | ||
2061 | #endif | ||
2062 | |||
2012 | local_irq_restore(flags); | 2063 | local_irq_restore(flags); |
2013 | 2064 | ||
2065 | |||
2014 | return 0; | 2066 | return 0; |
2015 | } | 2067 | } |
2016 | 2068 | ||
@@ -2048,7 +2100,9 @@ static int __init init_lapic_sysfs(void) | |||
2048 | error = sysdev_register(&device_lapic); | 2100 | error = sysdev_register(&device_lapic); |
2049 | return error; | 2101 | return error; |
2050 | } | 2102 | } |
2051 | device_initcall(init_lapic_sysfs); | 2103 | |
2104 | /* local apic needs to resume before other devices access its registers. */ | ||
2105 | core_initcall(init_lapic_sysfs); | ||
2052 | 2106 | ||
2053 | #else /* CONFIG_PM */ | 2107 | #else /* CONFIG_PM */ |
2054 | 2108 | ||