Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

intel/agp: rewrite GTT on resume

On my Intel chipset (965GM), the GTT is entirely erased across
suspend/resume. This patch simply re-plays the current mapping at resume
time to restore the table.=20

I noticed this once I started relying on persistent GTT mappings across VT
switch in our GEM work -- the old X server and DRM code carefully unbind
all memory from the GTT on VT switch, but GEM does not bother.

I placed the list management and rewrite code in the generic layer on the
assumption that it will be needed on other hardware, but I did not add the
rewrite call to anything other than the Intel resume function.

Keep a list of current GATT mappings. At resume time, rewrite them into
the GATT. This is needed on Intel (at least) as the entire GATT is
cleared across suspend/resume.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Keith Packard <keithp@keithp.com>
Cc: Dave Jones <davej@codemonkey.org.uk>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Keith Packard and committed by
Dave Airlie
a8c84df9 e3cf6951

+43
+3
drivers/char/agp/agp.h
··· 148 148 char minor_version; 149 149 struct list_head list; 150 150 u32 apbase_config; 151 + /* list of agp_memory mapped to the aperture */ 152 + struct list_head mapped_list; 153 + spinlock_t mapped_lock; 151 154 }; 152 155 153 156 #define KB(x) ((x) * 1024)
+2
drivers/char/agp/backend.c
··· 185 185 rc = -EINVAL; 186 186 goto err_out; 187 187 } 188 + INIT_LIST_HEAD(&bridge->mapped_list); 189 + spin_lock_init(&bridge->mapped_lock); 188 190 189 191 return 0; 190 192
+28
drivers/char/agp/generic.c
··· 429 429 430 430 curr->is_bound = true; 431 431 curr->pg_start = pg_start; 432 + spin_lock(&agp_bridge->mapped_lock); 433 + list_add(&curr->mapped_list, &agp_bridge->mapped_list); 434 + spin_unlock(&agp_bridge->mapped_lock); 435 + 432 436 return 0; 433 437 } 434 438 EXPORT_SYMBOL(agp_bind_memory); ··· 465 461 466 462 curr->is_bound = false; 467 463 curr->pg_start = 0; 464 + spin_lock(&curr->bridge->mapped_lock); 465 + list_del(&curr->mapped_list); 466 + spin_unlock(&curr->bridge->mapped_lock); 468 467 return 0; 469 468 } 470 469 EXPORT_SYMBOL(agp_unbind_memory); 470 + 471 + /** 472 + * agp_rebind_emmory - Rewrite the entire GATT, useful on resume 473 + */ 474 + int agp_rebind_memory(void) 475 + { 476 + struct agp_memory *curr; 477 + int ret_val = 0; 478 + 479 + spin_lock(&agp_bridge->mapped_lock); 480 + list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) { 481 + ret_val = curr->bridge->driver->insert_memory(curr, 482 + curr->pg_start, 483 + curr->type); 484 + if (ret_val != 0) 485 + break; 486 + } 487 + spin_unlock(&agp_bridge->mapped_lock); 488 + return ret_val; 489 + } 490 + EXPORT_SYMBOL(agp_rebind_memory); 471 491 472 492 /* End - Routines for handling swapping of agp_memory into the GATT */ 473 493
+5
drivers/char/agp/intel-agp.c
··· 2244 2244 static int agp_intel_resume(struct pci_dev *pdev) 2245 2245 { 2246 2246 struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 2247 + int ret_val; 2247 2248 2248 2249 pci_restore_state(pdev); 2249 2250 ··· 2271 2270 intel_i810_configure(); 2272 2271 else if (bridge->driver == &intel_i965_driver) 2273 2272 intel_i915_configure(); 2273 + 2274 + ret_val = agp_rebind_memory(); 2275 + if (ret_val != 0) 2276 + return ret_val; 2274 2277 2275 2278 return 0; 2276 2279 }
+5
include/linux/agp_backend.h
··· 30 30 #ifndef _AGP_BACKEND_H 31 31 #define _AGP_BACKEND_H 1 32 32 33 + #include <linux/list.h> 34 + 33 35 enum chipset_type { 34 36 NOT_SUPPORTED, 35 37 SUPPORTED, ··· 80 78 bool is_bound; 81 79 bool is_flushed; 82 80 bool vmalloc_flag; 81 + /* list of agp_memory mapped to the aperture */ 82 + struct list_head mapped_list; 83 83 }; 84 84 85 85 #define AGP_NORMAL_MEMORY 0 ··· 100 96 extern int agp_copy_info(struct agp_bridge_data *, struct agp_kern_info *); 101 97 extern int agp_bind_memory(struct agp_memory *, off_t); 102 98 extern int agp_unbind_memory(struct agp_memory *); 99 + extern int agp_rebind_memory(void); 103 100 extern void agp_enable(struct agp_bridge_data *, u32); 104 101 extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *); 105 102 extern void agp_backend_release(struct agp_bridge_data *);