diff options
author | Keith Packard <keithp@keithp.com> | 2008-07-31 01:48:07 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2008-08-11 20:13:38 -0400 |
commit | a8c84df9f71e4a7b14bdd41687a70d366c087eef (patch) | |
tree | fc11f372de1543c6816d783ee8a852fcecf434d7 /drivers/char | |
parent | e3cf69511a2c5369c58f6fd6a065de152c3d4b22 (diff) |
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>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/agp/agp.h | 3 | ||||
-rw-r--r-- | drivers/char/agp/backend.c | 2 | ||||
-rw-r--r-- | drivers/char/agp/generic.c | 28 | ||||
-rw-r--r-- | drivers/char/agp/intel-agp.c | 5 |
4 files changed, 38 insertions, 0 deletions
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 81e14bea54bd..4bada0e8b812 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h | |||
@@ -148,6 +148,9 @@ struct agp_bridge_data { | |||
148 | char minor_version; | 148 | char minor_version; |
149 | struct list_head list; | 149 | struct list_head list; |
150 | u32 apbase_config; | 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 | #define KB(x) ((x) * 1024) | 156 | #define KB(x) ((x) * 1024) |
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 9626d3bda096..3a3cc03d401c 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c | |||
@@ -185,6 +185,8 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) | |||
185 | rc = -EINVAL; | 185 | rc = -EINVAL; |
186 | goto err_out; | 186 | goto err_out; |
187 | } | 187 | } |
188 | INIT_LIST_HEAD(&bridge->mapped_list); | ||
189 | spin_lock_init(&bridge->mapped_lock); | ||
188 | 190 | ||
189 | return 0; | 191 | return 0; |
190 | 192 | ||
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 54c91000646f..118dbde25dc7 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c | |||
@@ -429,6 +429,10 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start) | |||
429 | 429 | ||
430 | curr->is_bound = true; | 430 | curr->is_bound = true; |
431 | curr->pg_start = pg_start; | 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 | return 0; | 436 | return 0; |
433 | } | 437 | } |
434 | EXPORT_SYMBOL(agp_bind_memory); | 438 | EXPORT_SYMBOL(agp_bind_memory); |
@@ -461,10 +465,34 @@ int agp_unbind_memory(struct agp_memory *curr) | |||
461 | 465 | ||
462 | curr->is_bound = false; | 466 | curr->is_bound = false; |
463 | curr->pg_start = 0; | 467 | curr->pg_start = 0; |
468 | spin_lock(&curr->bridge->mapped_lock); | ||
469 | list_del(&curr->mapped_list); | ||
470 | spin_unlock(&curr->bridge->mapped_lock); | ||
464 | return 0; | 471 | return 0; |
465 | } | 472 | } |
466 | EXPORT_SYMBOL(agp_unbind_memory); | 473 | EXPORT_SYMBOL(agp_unbind_memory); |
467 | 474 | ||
475 | /** | ||
476 | * agp_rebind_emmory - Rewrite the entire GATT, useful on resume | ||
477 | */ | ||
478 | int agp_rebind_memory(void) | ||
479 | { | ||
480 | struct agp_memory *curr; | ||
481 | int ret_val = 0; | ||
482 | |||
483 | spin_lock(&agp_bridge->mapped_lock); | ||
484 | list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) { | ||
485 | ret_val = curr->bridge->driver->insert_memory(curr, | ||
486 | curr->pg_start, | ||
487 | curr->type); | ||
488 | if (ret_val != 0) | ||
489 | break; | ||
490 | } | ||
491 | spin_unlock(&agp_bridge->mapped_lock); | ||
492 | return ret_val; | ||
493 | } | ||
494 | EXPORT_SYMBOL(agp_rebind_memory); | ||
495 | |||
468 | /* End - Routines for handling swapping of agp_memory into the GATT */ | 496 | /* End - Routines for handling swapping of agp_memory into the GATT */ |
469 | 497 | ||
470 | 498 | ||
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 57c552ee046f..016fdf0623a4 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c | |||
@@ -2244,6 +2244,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) | |||
2244 | static int agp_intel_resume(struct pci_dev *pdev) | 2244 | static int agp_intel_resume(struct pci_dev *pdev) |
2245 | { | 2245 | { |
2246 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 2246 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
2247 | int ret_val; | ||
2247 | 2248 | ||
2248 | pci_restore_state(pdev); | 2249 | pci_restore_state(pdev); |
2249 | 2250 | ||
@@ -2271,6 +2272,10 @@ static int agp_intel_resume(struct pci_dev *pdev) | |||
2271 | else if (bridge->driver == &intel_i965_driver) | 2272 | else if (bridge->driver == &intel_i965_driver) |
2272 | intel_i915_configure(); | 2273 | intel_i915_configure(); |
2273 | 2274 | ||
2275 | ret_val = agp_rebind_memory(); | ||
2276 | if (ret_val != 0) | ||
2277 | return ret_val; | ||
2278 | |||
2274 | return 0; | 2279 | return 0; |
2275 | } | 2280 | } |
2276 | #endif | 2281 | #endif |