diff options
| author | Johannes Berg <johannes@sipsolutions.net> | 2007-05-03 08:28:32 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2007-05-07 06:31:14 -0400 |
| commit | 7e11580b362fc64693de7ad5c11fbf3d1d9d0e50 (patch) | |
| tree | 8f1c12a24bec21ce5a5912f6b75d58c1ffc1ddd0 | |
| parent | 55b61fec22caa3e7872caea6c4100fc75cb8f49b (diff) | |
[POWERPC] DART iommu suspend
This implements save and restore hooks for IOMMUs and implements
it the DART iommu.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Olof Johansson <olof@lixom.net>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/powerpc/sysdev/dart_iommu.c | 46 | ||||
| -rw-r--r-- | include/asm-powerpc/iommu.h | 14 | ||||
| -rw-r--r-- | include/asm-powerpc/machdep.h | 5 |
3 files changed, 65 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 336186dd7f10..a1d2042bb304 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
| 37 | #include <linux/dma-mapping.h> | 37 | #include <linux/dma-mapping.h> |
| 38 | #include <linux/vmalloc.h> | 38 | #include <linux/vmalloc.h> |
| 39 | #include <linux/suspend.h> | ||
| 39 | #include <asm/io.h> | 40 | #include <asm/io.h> |
| 40 | #include <asm/prom.h> | 41 | #include <asm/prom.h> |
| 41 | #include <asm/iommu.h> | 42 | #include <asm/iommu.h> |
| @@ -54,6 +55,9 @@ static unsigned long dart_tablesize; | |||
| 54 | 55 | ||
| 55 | /* Virtual base address of the DART table */ | 56 | /* Virtual base address of the DART table */ |
| 56 | static u32 *dart_vbase; | 57 | static u32 *dart_vbase; |
| 58 | #ifdef CONFIG_PM | ||
| 59 | static u32 *dart_copy; | ||
| 60 | #endif | ||
| 57 | 61 | ||
| 58 | /* Mapped base address for the dart */ | 62 | /* Mapped base address for the dart */ |
| 59 | static unsigned int __iomem *dart; | 63 | static unsigned int __iomem *dart; |
| @@ -346,6 +350,48 @@ void iommu_init_early_dart(void) | |||
| 346 | set_pci_dma_ops(&dma_direct_ops); | 350 | set_pci_dma_ops(&dma_direct_ops); |
| 347 | } | 351 | } |
| 348 | 352 | ||
| 353 | #ifdef CONFIG_PM | ||
| 354 | static void iommu_dart_save(void) | ||
| 355 | { | ||
| 356 | memcpy(dart_copy, dart_vbase, 2*1024*1024); | ||
| 357 | } | ||
| 358 | |||
| 359 | static void iommu_dart_restore(void) | ||
| 360 | { | ||
| 361 | memcpy(dart_vbase, dart_copy, 2*1024*1024); | ||
| 362 | dart_tlb_invalidate_all(); | ||
| 363 | } | ||
| 364 | |||
| 365 | static int __init iommu_init_late_dart(void) | ||
| 366 | { | ||
| 367 | unsigned long tbasepfn; | ||
| 368 | struct page *p; | ||
| 369 | |||
| 370 | /* if no dart table exists then we won't need to save it | ||
| 371 | * and the area has also not been reserved */ | ||
| 372 | if (!dart_tablebase) | ||
| 373 | return 0; | ||
| 374 | |||
| 375 | tbasepfn = __pa(dart_tablebase) >> PAGE_SHIFT; | ||
| 376 | register_nosave_region_late(tbasepfn, | ||
| 377 | tbasepfn + ((1<<24) >> PAGE_SHIFT)); | ||
| 378 | |||
| 379 | /* For suspend we need to copy the dart contents because | ||
| 380 | * it is not part of the regular mapping (see above) and | ||
| 381 | * thus not saved automatically. The memory for this copy | ||
| 382 | * must be allocated early because we need 2 MB. */ | ||
| 383 | p = alloc_pages(GFP_KERNEL, 21 - PAGE_SHIFT); | ||
| 384 | BUG_ON(!p); | ||
| 385 | dart_copy = page_address(p); | ||
| 386 | |||
| 387 | ppc_md.iommu_save = iommu_dart_save; | ||
| 388 | ppc_md.iommu_restore = iommu_dart_restore; | ||
| 389 | |||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | late_initcall(iommu_init_late_dart); | ||
| 394 | #endif | ||
| 349 | 395 | ||
| 350 | void __init alloc_dart_table(void) | 396 | void __init alloc_dart_table(void) |
| 351 | { | 397 | { |
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index b2e56b30306a..870967e47204 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
| 27 | #include <linux/device.h> | 27 | #include <linux/device.h> |
| 28 | #include <linux/dma-mapping.h> | 28 | #include <linux/dma-mapping.h> |
| 29 | #include <asm/machdep.h> | ||
| 29 | #include <asm/types.h> | 30 | #include <asm/types.h> |
| 30 | #include <asm/bitops.h> | 31 | #include <asm/bitops.h> |
| 31 | 32 | ||
| @@ -109,6 +110,19 @@ static inline void pci_iommu_init(void) { } | |||
| 109 | #endif | 110 | #endif |
| 110 | 111 | ||
| 111 | extern void alloc_dart_table(void); | 112 | extern void alloc_dart_table(void); |
| 113 | #if defined(CONFIG_PPC64) && defined(CONFIG_PM) | ||
| 114 | static inline void iommu_save(void) | ||
| 115 | { | ||
| 116 | if (ppc_md.iommu_save) | ||
| 117 | ppc_md.iommu_save(); | ||
| 118 | } | ||
| 119 | |||
| 120 | static inline void iommu_restore(void) | ||
| 121 | { | ||
| 122 | if (ppc_md.iommu_restore) | ||
| 123 | ppc_md.iommu_restore(); | ||
| 124 | } | ||
| 125 | #endif | ||
| 112 | 126 | ||
| 113 | #endif /* __KERNEL__ */ | 127 | #endif /* __KERNEL__ */ |
| 114 | #endif /* _ASM_IOMMU_H */ | 128 | #endif /* _ASM_IOMMU_H */ |
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index bbd17d0e170d..6fdabd6dfb3e 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h | |||
| @@ -91,6 +91,11 @@ struct machdep_calls { | |||
| 91 | void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size, | 91 | void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size, |
| 92 | unsigned long flags); | 92 | unsigned long flags); |
| 93 | void (*iounmap)(volatile void __iomem *token); | 93 | void (*iounmap)(volatile void __iomem *token); |
| 94 | |||
| 95 | #ifdef CONFIG_PM | ||
| 96 | void (*iommu_save)(void); | ||
| 97 | void (*iommu_restore)(void); | ||
| 98 | #endif | ||
| 94 | #endif /* CONFIG_PPC64 */ | 99 | #endif /* CONFIG_PPC64 */ |
| 95 | 100 | ||
| 96 | int (*probe)(void); | 101 | int (*probe)(void); |
