diff options
author | Keith Packard <keithp@keithp.com> | 2008-07-31 09:48:07 +0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2008-08-12 04:13:38 +0400 |
commit | a8c84df9f71e4a7b14bdd41687a70d366c087eef (patch) | |
tree | fc11f372de1543c6816d783ee8a852fcecf434d7 /drivers/char | |
parent | e3cf69511a2c5369c58f6fd6a065de152c3d4b22 (diff) | |
download | linux-a8c84df9f71e4a7b14bdd41687a70d366c087eef.tar.xz |
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 { char minor_version; struct list_head list; u32 apbase_config; + /* list of agp_memory mapped to the aperture */ + struct list_head mapped_list; + spinlock_t mapped_lock; }; #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) rc = -EINVAL; goto err_out; } + INIT_LIST_HEAD(&bridge->mapped_list); + spin_lock_init(&bridge->mapped_lock); return 0; 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) curr->is_bound = true; curr->pg_start = pg_start; + spin_lock(&agp_bridge->mapped_lock); + list_add(&curr->mapped_list, &agp_bridge->mapped_list); + spin_unlock(&agp_bridge->mapped_lock); + return 0; } EXPORT_SYMBOL(agp_bind_memory); @@ -461,10 +465,34 @@ int agp_unbind_memory(struct agp_memory *curr) curr->is_bound = false; curr->pg_start = 0; + spin_lock(&curr->bridge->mapped_lock); + list_del(&curr->mapped_list); + spin_unlock(&curr->bridge->mapped_lock); return 0; } EXPORT_SYMBOL(agp_unbind_memory); +/** + * agp_rebind_emmory - Rewrite the entire GATT, useful on resume + */ +int agp_rebind_memory(void) +{ + struct agp_memory *curr; + int ret_val = 0; + + spin_lock(&agp_bridge->mapped_lock); + list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) { + ret_val = curr->bridge->driver->insert_memory(curr, + curr->pg_start, + curr->type); + if (ret_val != 0) + break; + } + spin_unlock(&agp_bridge->mapped_lock); + return ret_val; +} +EXPORT_SYMBOL(agp_rebind_memory); + /* End - Routines for handling swapping of agp_memory into the GATT */ 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) static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + int ret_val; pci_restore_state(pdev); @@ -2271,6 +2272,10 @@ static int agp_intel_resume(struct pci_dev *pdev) else if (bridge->driver == &intel_i965_driver) intel_i915_configure(); + ret_val = agp_rebind_memory(); + if (ret_val != 0) + return ret_val; + return 0; } #endif |