aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFenghua Yu <fenghua.yu@intel.com>2009-03-27 17:22:44 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-04-03 16:45:59 -0400
commitb24696bc55f66fecc30715e003f10fc2555a9271 (patch)
tree3ef565bf041a06106a73d0b27ccc256845ef5644
parenteb4a52bc660ea835482c582eaaf4893742cbd160 (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>
-rw-r--r--arch/x86/include/asm/apic.h4
-rw-r--r--arch/x86/include/asm/io_apic.h11
-rw-r--r--arch/x86/kernel/apic/apic.c70
-rw-r--r--arch/x86/kernel/apic/io_apic.c111
-rw-r--r--drivers/pci/intr_remapping.c61
-rw-r--r--include/linux/dmar.h2
6 files changed, 204 insertions, 55 deletions
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index df8a300dfe6c..f9f0866ed6f8 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -108,6 +108,10 @@ extern void native_apic_icr_write(u32 low, u32 id);
108extern u64 native_apic_icr_read(void); 108extern u64 native_apic_icr_read(void);
109 109
110#ifdef CONFIG_X86_X2APIC 110#ifdef CONFIG_X86_X2APIC
111
112#define EIM_8BIT_APIC_ID 0
113#define EIM_32BIT_APIC_ID 1
114
111/* 115/*
112 * Make previous memory operations globally visible before 116 * Make previous memory operations globally visible before
113 * sending the IPI through x2apic wrmsr. We need a serializing instruction or 117 * sending the IPI through x2apic wrmsr. We need a serializing instruction or
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 373cc2bbcad2..9d826e436010 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -162,10 +162,13 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
162extern void ioapic_init_mappings(void); 162extern void ioapic_init_mappings(void);
163 163
164#ifdef CONFIG_X86_64 164#ifdef CONFIG_X86_64
165extern int save_IO_APIC_setup(void); 165extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
166extern void mask_IO_APIC_setup(void); 166extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
167extern void restore_IO_APIC_setup(void); 167extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
168extern void reinit_intr_remapped_IO_APIC(int); 168extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
169extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
170extern void reinit_intr_remapped_IO_APIC(int intr_remapping,
171 struct IO_APIC_route_entry **ioapic_entries);
169#endif 172#endif
170 173
171extern void probe_nr_irqs_gsi(void); 174extern void probe_nr_irqs_gsi(void);
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}
2051device_initcall(init_lapic_sysfs); 2103
2104/* local apic needs to resume before other devices access its registers. */
2105core_initcall(init_lapic_sysfs);
2052 2106
2053#else /* CONFIG_PM */ 2107#else /* CONFIG_PM */
2054 2108
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 1bb5c6cee3eb..0ad3fe77641a 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -851,63 +851,74 @@ __setup("pirq=", ioapic_pirq_setup);
851#endif /* CONFIG_X86_32 */ 851#endif /* CONFIG_X86_32 */
852 852
853#ifdef CONFIG_INTR_REMAP 853#ifdef CONFIG_INTR_REMAP
854/* I/O APIC RTE contents at the OS boot up */ 854struct IO_APIC_route_entry **alloc_ioapic_entries(void)
855static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS]; 855{
856 int apic;
857 struct IO_APIC_route_entry **ioapic_entries;
858
859 ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
860 GFP_ATOMIC);
861 if (!ioapic_entries)
862 return 0;
863
864 for (apic = 0; apic < nr_ioapics; apic++) {
865 ioapic_entries[apic] =
866 kzalloc(sizeof(struct IO_APIC_route_entry) *
867 nr_ioapic_registers[apic], GFP_ATOMIC);
868 if (!ioapic_entries[apic])
869 goto nomem;
870 }
871
872 return ioapic_entries;
873
874nomem:
875 while (--apic >= 0)
876 kfree(ioapic_entries[apic]);
877 kfree(ioapic_entries);
878
879 return 0;
880}
856 881
857/* 882/*
858 * Saves all the IO-APIC RTE's 883 * Saves all the IO-APIC RTE's
859 */ 884 */
860int save_IO_APIC_setup(void) 885int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
861{ 886{
862 union IO_APIC_reg_01 reg_01;
863 unsigned long flags;
864 int apic, pin; 887 int apic, pin;
865 888
866 /* 889 if (!ioapic_entries)
867 * The number of IO-APIC IRQ registers (== #pins): 890 return -ENOMEM;
868 */
869 for (apic = 0; apic < nr_ioapics; apic++) {
870 spin_lock_irqsave(&ioapic_lock, flags);
871 reg_01.raw = io_apic_read(apic, 1);
872 spin_unlock_irqrestore(&ioapic_lock, flags);
873 nr_ioapic_registers[apic] = reg_01.bits.entries+1;
874 }
875 891
876 for (apic = 0; apic < nr_ioapics; apic++) { 892 for (apic = 0; apic < nr_ioapics; apic++) {
877 early_ioapic_entries[apic] = 893 if (!ioapic_entries[apic])
878 kzalloc(sizeof(struct IO_APIC_route_entry) * 894 return -ENOMEM;
879 nr_ioapic_registers[apic], GFP_KERNEL);
880 if (!early_ioapic_entries[apic])
881 goto nomem;
882 }
883 895
884 for (apic = 0; apic < nr_ioapics; apic++)
885 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) 896 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
886 early_ioapic_entries[apic][pin] = 897 ioapic_entries[apic][pin] =
887 ioapic_read_entry(apic, pin); 898 ioapic_read_entry(apic, pin);
899 }
888 900
889 return 0; 901 return 0;
890
891nomem:
892 while (apic >= 0)
893 kfree(early_ioapic_entries[apic--]);
894 memset(early_ioapic_entries, 0,
895 ARRAY_SIZE(early_ioapic_entries));
896
897 return -ENOMEM;
898} 902}
899 903
900void mask_IO_APIC_setup(void) 904/*
905 * Mask all IO APIC entries.
906 */
907void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
901{ 908{
902 int apic, pin; 909 int apic, pin;
903 910
911 if (!ioapic_entries)
912 return;
913
904 for (apic = 0; apic < nr_ioapics; apic++) { 914 for (apic = 0; apic < nr_ioapics; apic++) {
905 if (!early_ioapic_entries[apic]) 915 if (!ioapic_entries[apic])
906 break; 916 break;
917
907 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { 918 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
908 struct IO_APIC_route_entry entry; 919 struct IO_APIC_route_entry entry;
909 920
910 entry = early_ioapic_entries[apic][pin]; 921 entry = ioapic_entries[apic][pin];
911 if (!entry.mask) { 922 if (!entry.mask) {
912 entry.mask = 1; 923 entry.mask = 1;
913 ioapic_write_entry(apic, pin, entry); 924 ioapic_write_entry(apic, pin, entry);
@@ -916,22 +927,30 @@ void mask_IO_APIC_setup(void)
916 } 927 }
917} 928}
918 929
919void restore_IO_APIC_setup(void) 930/*
931 * Restore IO APIC entries which was saved in ioapic_entries.
932 */
933int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
920{ 934{
921 int apic, pin; 935 int apic, pin;
922 936
937 if (!ioapic_entries)
938 return -ENOMEM;
939
923 for (apic = 0; apic < nr_ioapics; apic++) { 940 for (apic = 0; apic < nr_ioapics; apic++) {
924 if (!early_ioapic_entries[apic]) 941 if (!ioapic_entries[apic])
925 break; 942 return -ENOMEM;
943
926 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) 944 for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
927 ioapic_write_entry(apic, pin, 945 ioapic_write_entry(apic, pin,
928 early_ioapic_entries[apic][pin]); 946 ioapic_entries[apic][pin]);
929 kfree(early_ioapic_entries[apic]);
930 early_ioapic_entries[apic] = NULL;
931 } 947 }
948 return 0;
932} 949}
933 950
934void reinit_intr_remapped_IO_APIC(int intr_remapping) 951void reinit_intr_remapped_IO_APIC(int intr_remapping,
952 struct IO_APIC_route_entry **ioapic_entries)
953
935{ 954{
936 /* 955 /*
937 * for now plain restore of previous settings. 956 * for now plain restore of previous settings.
@@ -940,7 +959,17 @@ void reinit_intr_remapped_IO_APIC(int intr_remapping)
940 * table entries. for now, do a plain restore, and wait for 959 * table entries. for now, do a plain restore, and wait for
941 * the setup_IO_APIC_irqs() to do proper initialization. 960 * the setup_IO_APIC_irqs() to do proper initialization.
942 */ 961 */
943 restore_IO_APIC_setup(); 962 restore_IO_APIC_setup(ioapic_entries);
963}
964
965void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
966{
967 int apic;
968
969 for (apic = 0; apic < nr_ioapics; apic++)
970 kfree(ioapic_entries[apic]);
971
972 kfree(ioapic_entries);
944} 973}
945#endif 974#endif
946 975
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index b041a409f4a7..c26633d7e7da 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -470,7 +470,7 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
470/* 470/*
471 * Disable Interrupt Remapping. 471 * Disable Interrupt Remapping.
472 */ 472 */
473static void disable_intr_remapping(struct intel_iommu *iommu) 473static void iommu_disable_intr_remapping(struct intel_iommu *iommu)
474{ 474{
475 unsigned long flags; 475 unsigned long flags;
476 u32 sts; 476 u32 sts;
@@ -478,6 +478,12 @@ static void disable_intr_remapping(struct intel_iommu *iommu)
478 if (!ecap_ir_support(iommu->ecap)) 478 if (!ecap_ir_support(iommu->ecap))
479 return; 479 return;
480 480
481 /*
482 * global invalidation of interrupt entry cache before disabling
483 * interrupt-remapping.
484 */
485 qi_global_iec(iommu);
486
481 spin_lock_irqsave(&iommu->register_lock, flags); 487 spin_lock_irqsave(&iommu->register_lock, flags);
482 488
483 sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); 489 sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
@@ -511,7 +517,7 @@ int __init enable_intr_remapping(int eim)
511 * Disable intr remapping and queued invalidation, if already 517 * Disable intr remapping and queued invalidation, if already
512 * enabled prior to OS handover. 518 * enabled prior to OS handover.
513 */ 519 */
514 disable_intr_remapping(iommu); 520 iommu_disable_intr_remapping(iommu);
515 521
516 dmar_disable_qi(iommu); 522 dmar_disable_qi(iommu);
517 } 523 }
@@ -639,3 +645,54 @@ int __init parse_ioapics_under_ir(void)
639 645
640 return ir_supported; 646 return ir_supported;
641} 647}
648
649void disable_intr_remapping(void)
650{
651 struct dmar_drhd_unit *drhd;
652 struct intel_iommu *iommu = NULL;
653
654 /*
655 * Disable Interrupt-remapping for all the DRHD's now.
656 */
657 for_each_iommu(iommu, drhd) {
658 if (!ecap_ir_support(iommu->ecap))
659 continue;
660
661 iommu_disable_intr_remapping(iommu);
662 }
663}
664
665int reenable_intr_remapping(int eim)
666{
667 struct dmar_drhd_unit *drhd;
668 int setup = 0;
669 struct intel_iommu *iommu = NULL;
670
671 for_each_iommu(iommu, drhd)
672 if (iommu->qi)
673 dmar_reenable_qi(iommu);
674
675 /*
676 * Setup Interrupt-remapping for all the DRHD's now.
677 */
678 for_each_iommu(iommu, drhd) {
679 if (!ecap_ir_support(iommu->ecap))
680 continue;
681
682 /* Set up interrupt remapping for iommu.*/
683 iommu_set_intr_remapping(iommu, eim);
684 setup = 1;
685 }
686
687 if (!setup)
688 goto error;
689
690 return 0;
691
692error:
693 /*
694 * handle error condition gracefully here!
695 */
696 return -1;
697}
698
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 0b4aa8069985..4a0ce6f27e1b 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -108,6 +108,8 @@ struct irte {
108#ifdef CONFIG_INTR_REMAP 108#ifdef CONFIG_INTR_REMAP
109extern int intr_remapping_enabled; 109extern int intr_remapping_enabled;
110extern int enable_intr_remapping(int); 110extern int enable_intr_remapping(int);
111extern void disable_intr_remapping(void);
112extern int reenable_intr_remapping(int);
111 113
112extern int get_irte(int irq, struct irte *entry); 114extern int get_irte(int irq, struct irte *entry);
113extern int modify_irte(int irq, struct irte *irte_modified); 115extern int modify_irte(int irq, struct irte *irte_modified);