Re: amd64-agp vs. swsusp

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Pavel Machek wrote:
Long time ago there were i386 problems because we assumed that kernel
is mapped in one big mapping and agp broke that assumption. Copying
pages backwards "fixed" it (and then we done proper fix). It should
not be, but it seems similar to this problem....

Do you mean this patch of yours?:
http://www.ussg.iu.edu/hypermail/linux/kernel/0404.3/0640.html

I'm trying to do something similar for x86_64. See the attached patch.
Unfortunately, it doesn't help. The behaviour seems unchanged (resume still works iff amd64-agp wasn't loaded before suspend).

Michal
diff -Nurp -X dontdiff.new linux-mm/arch/x86_64/kernel/suspend_asm.S linux-mm.mich/arch/x86_64/kernel/suspend_asm.S
--- linux-mm/arch/x86_64/kernel/suspend_asm.S	2005-06-30 01:00:53.000000000 +0200
+++ linux-mm.mich/arch/x86_64/kernel/suspend_asm.S	2005-07-21 11:53:17.000000000 +0200
@@ -41,7 +41,7 @@ ENTRY(swsusp_arch_suspend)
 
 ENTRY(swsusp_arch_resume)
 	/* set up cr3 */	
-	leaq	init_level4_pgt(%rip),%rax
+	leaq	swsusp_level4_pgt(%rip),%rax
 	subq	$__START_KERNEL_map,%rax
 	movq	%rax,%cr3
 
diff -Nurp -X dontdiff.new linux-mm/arch/x86_64/mm/init.c linux-mm.mich/arch/x86_64/mm/init.c
--- linux-mm/arch/x86_64/mm/init.c	2005-07-18 19:48:12.000000000 +0200
+++ linux-mm.mich/arch/x86_64/mm/init.c	2005-07-21 11:21:36.000000000 +0200
@@ -310,10 +310,32 @@ void __init init_memory_mapping(unsigned
 
 extern struct x8664_pda cpu_pda[NR_CPUS];
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+/*
+ * Swap suspend & friends need this for resume because things like the intel-agp
+ * driver might have split up a kernel 4MB mapping.
+ */
+char __nosavedata swsusp_level4_pgt[PAGE_SIZE]
+	__attribute__ ((aligned (PAGE_SIZE)));
+
+static inline void save_pg_dir(void)
+{
+	memcpy(swsusp_level4_pgt, init_level4_pgt, PAGE_SIZE);
+}
+#else
+static inline void save_pg_dir(void)
+{
+}
+#endif
+
 /* Assumes all CPUs still execute in init_mm */
 void zap_low_mappings(void)
 {
-	pgd_t *pgd = pgd_offset_k(0UL);
+	pgd_t *pgd;
+
+	save_pg_dir();
+
+	pgd = pgd_offset_k(0UL);
 	pgd_clear(pgd);
 	flush_tlb_all();
 }

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux