From: Brice Goglin The bug appeared in -mm when the multi-bridge AGP stuff was merged (2.6.10-mm3). It is still here in 2.6.12-rc1. Here's the scenario I think I'm seeing: agpioc_acquire_wrap is called, it increments the agp_in_use. Then (before agpioc_release_wrap happens), drm_agp_init is called (I don't know how). drm_agp_init uses agp_backend_acquire which fails because agp_in_use is non-null (hold by agpioc_acquire_wrap). The multi-bridge AGP patch actually changed drm_agp_init by adding agp_backend_acquire/release around agp_copy_info. It is why drm_agp_init fails now while it worked before. I don't think we need to "acquire" it during agp_copy_info. Why don't we just get a pointer to the bridge instead ? (is there any chance this bridge gets deleted during drm_agp_init ?) That's what the attached patch implements on top of 2.6.12-rc1. I chose to add a new agp_backend_find() function, but we might also directly call agp_find_bridge() from drm_agp_init(). I don't know what's the best. Signed-off-by: Brice Goglin Signed-off-by: Andrew Morton --- 25-akpm/drivers/char/agp/backend.c | 8 +++++++- 25-akpm/drivers/char/drm/drm_agpsupport.c | 3 +-- 25-akpm/include/linux/agp_backend.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff -puN drivers/char/agp/backend.c~fix-agp_backend-usage-in-drm_agp_init drivers/char/agp/backend.c --- 25/drivers/char/agp/backend.c~fix-agp_backend-usage-in-drm_agp_init 2005-03-18 23:54:18.000000000 -0800 +++ 25-akpm/drivers/char/agp/backend.c 2005-03-18 23:54:18.000000000 -0800 @@ -58,6 +58,12 @@ LIST_HEAD(agp_bridges); EXPORT_SYMBOL(agp_bridge); EXPORT_SYMBOL(agp_bridges); +struct agp_bridge_data *agp_backend_find(struct pci_dev *pdev) +{ + return agp_find_bridge(pdev); +} +EXPORT_SYMBOL(agp_backend_find); + /** * agp_backend_acquire - attempt to acquire an agp backend. * @@ -66,7 +72,7 @@ struct agp_bridge_data *agp_backend_acqu { struct agp_bridge_data *bridge; - bridge = agp_find_bridge(pdev); + bridge = agp_backend_find(pdev); if (!bridge) return NULL; diff -puN drivers/char/drm/drm_agpsupport.c~fix-agp_backend-usage-in-drm_agp_init drivers/char/drm/drm_agpsupport.c --- 25/drivers/char/drm/drm_agpsupport.c~fix-agp_backend-usage-in-drm_agp_init 2005-03-18 23:54:18.000000000 -0800 +++ 25-akpm/drivers/char/drm/drm_agpsupport.c 2005-03-18 23:54:18.000000000 -0800 @@ -387,12 +387,11 @@ drm_agp_head_t *drm_agp_init(drm_device_ if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) return NULL; memset((void *)head, 0, sizeof(*head)); - if (!(head->bridge = agp_backend_acquire(dev->pdev))) { + if (!(head->bridge = agp_backend_find(dev->pdev))) { drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); return NULL; } agp_copy_info(head->bridge, &head->agp_info); - agp_backend_release(head->bridge); if (head->agp_info.chipset == NOT_SUPPORTED) { drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); return NULL; diff -puN include/linux/agp_backend.h~fix-agp_backend-usage-in-drm_agp_init include/linux/agp_backend.h --- 25/include/linux/agp_backend.h~fix-agp_backend-usage-in-drm_agp_init 2005-03-18 23:54:18.000000000 -0800 +++ 25-akpm/include/linux/agp_backend.h 2005-03-18 23:54:18.000000000 -0800 @@ -100,6 +100,7 @@ extern int agp_copy_info(struct agp_brid extern int agp_bind_memory(struct agp_memory *, off_t); extern int agp_unbind_memory(struct agp_memory *); extern void agp_enable(struct agp_bridge_data *, u32); +extern struct agp_bridge_data *agp_backend_find(struct pci_dev *); extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *); extern void agp_backend_release(struct agp_bridge_data *); _