diff options
author | Kirill Artamonov <kartamonov@nvidia.com> | 2011-06-15 03:40:32 +0300 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:47:23 -0800 |
commit | 9cb88b1cea01dda012134c76d0a1d56a263b02ca (patch) | |
tree | 1b2108820d183b235633dfc37a86bce9ddca6710 /drivers/video/tegra/nvmap/nvmap_mru.c | |
parent | 4604a9ef07f231a41c28e52add8e5d92ae840d79 (diff) |
video: tegra: nvmap: fix GART pin lockups
Fix GART lockups caused by fragmentation by evicting
mapped areas from iovm space after unsuccessful array
pinning attempt.
Fix double unpin error happening during interrupted
submit.
Fix possible sleep in atomic context in iovmm code
(semaphore inside spinlock) by replacing spinlock
with mutex.
Fix race between handle_unpin and pin_handle.
bug 838579
bug 838073
bug 818058
Original-Change-Id: I420447ffb4e02fb78a7987e22a537eefc16ff524
Reviewed-on: http://git-master/r/36129
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Rebase-Id: R893c97003f2ec2f69e224f35d99d3488f673d620
Diffstat (limited to 'drivers/video/tegra/nvmap/nvmap_mru.c')
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_mru.c | 15 |
1 files changed, 2 insertions, 13 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap_mru.c b/drivers/video/tegra/nvmap/nvmap_mru.c index 02e8f1402a1d..55b79644223a 100644 --- a/drivers/video/tegra/nvmap/nvmap_mru.c +++ b/drivers/video/tegra/nvmap/nvmap_mru.c @@ -90,7 +90,7 @@ void nvmap_mru_remove(struct nvmap_share *s, struct nvmap_handle *h) * and if that fails, iteratively evict handles from the MRU lists and free * their allocations, until the new allocation succeeds. */ -struct tegra_iovmm_area *nvmap_handle_iovmm(struct nvmap_client *c, +struct tegra_iovmm_area *nvmap_handle_iovmm_locked(struct nvmap_client *c, struct nvmap_handle *h) { struct list_head *mru; @@ -104,14 +104,9 @@ struct tegra_iovmm_area *nvmap_handle_iovmm(struct nvmap_client *c, prot = nvmap_pgprot(h, pgprot_kernel); if (h->pgalloc.area) { - /* since this is only called inside the pin lock, and the - * handle is gotten before it is pinned, there are no races - * where h->pgalloc.area is changed after the comparison */ - nvmap_mru_lock(c->share); BUG_ON(list_empty(&h->pgalloc.mru_list)); list_del(&h->pgalloc.mru_list); INIT_LIST_HEAD(&h->pgalloc.mru_list); - nvmap_mru_unlock(c->share); return h->pgalloc.area; } @@ -130,8 +125,6 @@ struct tegra_iovmm_area *nvmap_handle_iovmm(struct nvmap_client *c, * same size bin as the current handle. If that fails, iteratively * evict handles (starting from the current bin) until an allocation * succeeds or no more areas can be evicted */ - - nvmap_mru_lock(c->share); mru = mru_list(c->share, h->size); if (!list_empty(mru)) evict = list_first_entry(mru, struct nvmap_handle, @@ -142,7 +135,6 @@ struct tegra_iovmm_area *nvmap_handle_iovmm(struct nvmap_client *c, vm = evict->pgalloc.area; evict->pgalloc.area = NULL; INIT_LIST_HEAD(&evict->pgalloc.mru_list); - nvmap_mru_unlock(c->share); return vm; } @@ -160,23 +152,20 @@ struct tegra_iovmm_area *nvmap_handle_iovmm(struct nvmap_client *c, BUG_ON(!evict->pgalloc.area); list_del(&evict->pgalloc.mru_list); INIT_LIST_HEAD(&evict->pgalloc.mru_list); - nvmap_mru_unlock(c->share); tegra_iovmm_free_vm(evict->pgalloc.area); evict->pgalloc.area = NULL; vm = tegra_iovmm_create_vm(c->share->iovmm, NULL, h->size, h->align, prot, h->pgalloc.iovm_addr); - nvmap_mru_lock(c->share); } } - nvmap_mru_unlock(c->share); return vm; } int nvmap_mru_init(struct nvmap_share *share) { int i; - spin_lock_init(&share->mru_lock); + mutex_init(&share->mru_lock); share->nr_mru = ARRAY_SIZE(mru_cutoff) + 1; share->mru_lists = kzalloc(sizeof(struct list_head) * share->nr_mru, |