From a8c84df9f71e4a7b14bdd41687a70d366c087eef Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 31 Jul 2008 15:48:07 +1000 Subject: 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 Cc: Dave Jones Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie --- drivers/char/agp/agp.h | 3 +++ drivers/char/agp/backend.c | 2 ++ drivers/char/agp/generic.c | 28 ++++++++++++++++++++++++++++ drivers/char/agp/intel-agp.c | 5 +++++ 4 files changed, 38 insertions(+) (limited to 'drivers/char/agp') diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 81e14bea54b..4bada0e8b81 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 9626d3bda09..3a3cc03d401 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 54c91000646..118dbde25dc 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 57c552ee046..016fdf0623a 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 -- cgit v1.2.3