diff options
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 b0e5e712a7af..fb504f843e58 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1308,6 +1308,7 @@ void __init enable_IR_x2apic(void) | |||
1308 | #ifdef CONFIG_INTR_REMAP | 1308 | #ifdef CONFIG_INTR_REMAP |
1309 | int ret; | 1309 | int ret; |
1310 | unsigned long flags; | 1310 | unsigned long flags; |
1311 | struct IO_APIC_route_entry **ioapic_entries = NULL; | ||
1311 | 1312 | ||
1312 | if (!cpu_has_x2apic) | 1313 | if (!cpu_has_x2apic) |
1313 | return; | 1314 | return; |
@@ -1338,17 +1339,23 @@ void __init enable_IR_x2apic(void) | |||
1338 | return; | 1339 | return; |
1339 | } | 1340 | } |
1340 | 1341 | ||
1341 | ret = save_IO_APIC_setup(); | 1342 | ioapic_entries = alloc_ioapic_entries(); |
1343 | if (!ioapic_entries) { | ||
1344 | pr_info("Allocate ioapic_entries failed: %d\n", ret); | ||
1345 | goto end; | ||
1346 | } | ||
1347 | |||
1348 | ret = save_IO_APIC_setup(ioapic_entries); | ||
1342 | if (ret) { | 1349 | if (ret) { |
1343 | pr_info("Saving IO-APIC state failed: %d\n", ret); | 1350 | pr_info("Saving IO-APIC state failed: %d\n", ret); |
1344 | goto end; | 1351 | goto end; |
1345 | } | 1352 | } |
1346 | 1353 | ||
1347 | local_irq_save(flags); | 1354 | local_irq_save(flags); |
1348 | mask_IO_APIC_setup(); | 1355 | mask_IO_APIC_setup(ioapic_entries); |
1349 | mask_8259A(); | 1356 | mask_8259A(); |
1350 | 1357 | ||
1351 | ret = enable_intr_remapping(1); | 1358 | ret = enable_intr_remapping(EIM_32BIT_APIC_ID); |
1352 | 1359 | ||
1353 | if (ret && x2apic_preenabled) { | 1360 | if (ret && x2apic_preenabled) { |
1354 | local_irq_restore(flags); | 1361 | local_irq_restore(flags); |
@@ -1368,9 +1375,9 @@ end_restore: | |||
1368 | /* | 1375 | /* |
1369 | * IR enabling failed | 1376 | * IR enabling failed |
1370 | */ | 1377 | */ |
1371 | restore_IO_APIC_setup(); | 1378 | restore_IO_APIC_setup(ioapic_entries); |
1372 | else | 1379 | else |
1373 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | 1380 | reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries); |
1374 | 1381 | ||
1375 | unmask_8259A(); | 1382 | unmask_8259A(); |
1376 | local_irq_restore(flags); | 1383 | local_irq_restore(flags); |
@@ -1383,6 +1390,8 @@ end: | |||
1383 | pr_info("Enabled Interrupt-remapping\n"); | 1390 | pr_info("Enabled Interrupt-remapping\n"); |
1384 | } else | 1391 | } else |
1385 | pr_err("Failed to enable Interrupt-remapping and x2apic\n"); | 1392 | pr_err("Failed to enable Interrupt-remapping and x2apic\n"); |
1393 | if (ioapic_entries) | ||
1394 | free_ioapic_entries(ioapic_entries); | ||
1386 | #else | 1395 | #else |
1387 | if (!cpu_has_x2apic) | 1396 | if (!cpu_has_x2apic) |
1388 | return; | 1397 | return; |
@@ -1958,6 +1967,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
1958 | 1967 | ||
1959 | local_irq_save(flags); | 1968 | local_irq_save(flags); |
1960 | disable_local_APIC(); | 1969 | disable_local_APIC(); |
1970 | #ifdef CONFIG_INTR_REMAP | ||
1971 | if (intr_remapping_enabled) | ||
1972 | disable_intr_remapping(); | ||
1973 | #endif | ||
1961 | local_irq_restore(flags); | 1974 | local_irq_restore(flags); |
1962 | return 0; | 1975 | return 0; |
1963 | } | 1976 | } |
@@ -1968,15 +1981,41 @@ static int lapic_resume(struct sys_device *dev) | |||
1968 | unsigned long flags; | 1981 | unsigned long flags; |
1969 | int maxlvt; | 1982 | int maxlvt; |
1970 | 1983 | ||
1984 | #ifdef CONFIG_INTR_REMAP | ||
1985 | int ret; | ||
1986 | struct IO_APIC_route_entry **ioapic_entries = NULL; | ||
1987 | |||
1971 | if (!apic_pm_state.active) | 1988 | if (!apic_pm_state.active) |
1972 | return 0; | 1989 | return 0; |
1973 | 1990 | ||
1974 | maxlvt = lapic_get_maxlvt(); | ||
1975 | |||
1976 | local_irq_save(flags); | 1991 | local_irq_save(flags); |
1992 | if (x2apic) { | ||
1993 | ioapic_entries = alloc_ioapic_entries(); | ||
1994 | if (!ioapic_entries) { | ||
1995 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); | ||
1996 | return -ENOMEM; | ||
1997 | } | ||
1998 | |||
1999 | ret = save_IO_APIC_setup(ioapic_entries); | ||
2000 | if (ret) { | ||
2001 | WARN(1, "Saving IO-APIC state failed: %d\n", ret); | ||
2002 | free_ioapic_entries(ioapic_entries); | ||
2003 | return ret; | ||
2004 | } | ||
2005 | |||
2006 | mask_IO_APIC_setup(ioapic_entries); | ||
2007 | mask_8259A(); | ||
2008 | enable_x2apic(); | ||
2009 | } | ||
2010 | #else | ||
2011 | if (!apic_pm_state.active) | ||
2012 | return 0; | ||
1977 | 2013 | ||
2014 | local_irq_save(flags); | ||
1978 | if (x2apic) | 2015 | if (x2apic) |
1979 | enable_x2apic(); | 2016 | enable_x2apic(); |
2017 | #endif | ||
2018 | |||
1980 | else { | 2019 | else { |
1981 | /* | 2020 | /* |
1982 | * Make sure the APICBASE points to the right address | 2021 | * Make sure the APICBASE points to the right address |
@@ -1990,6 +2029,7 @@ static int lapic_resume(struct sys_device *dev) | |||
1990 | wrmsr(MSR_IA32_APICBASE, l, h); | 2029 | wrmsr(MSR_IA32_APICBASE, l, h); |
1991 | } | 2030 | } |
1992 | 2031 | ||
2032 | maxlvt = lapic_get_maxlvt(); | ||
1993 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); | 2033 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); |
1994 | apic_write(APIC_ID, apic_pm_state.apic_id); | 2034 | apic_write(APIC_ID, apic_pm_state.apic_id); |
1995 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); | 2035 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); |
@@ -2013,8 +2053,20 @@ static int lapic_resume(struct sys_device *dev) | |||
2013 | apic_write(APIC_ESR, 0); | 2053 | apic_write(APIC_ESR, 0); |
2014 | apic_read(APIC_ESR); | 2054 | apic_read(APIC_ESR); |
2015 | 2055 | ||
2056 | #ifdef CONFIG_INTR_REMAP | ||
2057 | if (intr_remapping_enabled) | ||
2058 | reenable_intr_remapping(EIM_32BIT_APIC_ID); | ||
2059 | |||
2060 | if (x2apic) { | ||
2061 | unmask_8259A(); | ||
2062 | restore_IO_APIC_setup(ioapic_entries); | ||
2063 | free_ioapic_entries(ioapic_entries); | ||
2064 | } | ||
2065 | #endif | ||
2066 | |||
2016 | local_irq_restore(flags); | 2067 | local_irq_restore(flags); |
2017 | 2068 | ||
2069 | |||
2018 | return 0; | 2070 | return 0; |
2019 | } | 2071 | } |
2020 | 2072 | ||
@@ -2052,7 +2104,9 @@ static int __init init_lapic_sysfs(void) | |||
2052 | error = sysdev_register(&device_lapic); | 2104 | error = sysdev_register(&device_lapic); |
2053 | return error; | 2105 | return error; |
2054 | } | 2106 | } |
2055 | device_initcall(init_lapic_sysfs); | 2107 | |
2108 | /* local apic needs to resume before other devices access its registers. */ | ||
2109 | core_initcall(init_lapic_sysfs); | ||
2056 | 2110 | ||
2057 | #else /* CONFIG_PM */ | 2111 | #else /* CONFIG_PM */ |
2058 | 2112 | ||