Commit 6c7c8fb8 authored by Rob Clark's avatar Rob Clark

drm/msm/gem: Protect pin_count/madv by LRU lock

Since the LRU lock is already acquired when moving an obj between LRUs,
we can use it to protect pin_count and madv, without any significant
change in locking (ie. it just expands the scope of the lock by a hand-
ful of instructions).  This prepares the way to decrement the pin_count
in the job_run() path without needing to hold the obj lock, to avoid a
potential deadlock (or rather stall) caused by the fence-signaling path
(job_run()) blocking on shrinker/reclaim.  (Only a stall because the
wait for fence signaling wait_for_idle() is not infinite.)
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
Patchwork: https://patchwork.freedesktop.org/patch/527843/
Link: https://lore.kernel.org/r/20230320144356.803762-9-robdclark@gmail.com
parent 4a02a376
...@@ -61,7 +61,7 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj) ...@@ -61,7 +61,7 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj)
dma_unmap_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0); dma_unmap_sgtable(dev, msm_obj->sgt, DMA_BIDIRECTIONAL, 0);
} }
static void update_lru(struct drm_gem_object *obj) static void update_lru_locked(struct drm_gem_object *obj)
{ {
struct msm_drm_private *priv = obj->dev->dev_private; struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_object *msm_obj = to_msm_bo(obj);
...@@ -71,18 +71,27 @@ static void update_lru(struct drm_gem_object *obj) ...@@ -71,18 +71,27 @@ static void update_lru(struct drm_gem_object *obj)
if (!msm_obj->pages) { if (!msm_obj->pages) {
GEM_WARN_ON(msm_obj->pin_count); GEM_WARN_ON(msm_obj->pin_count);
drm_gem_lru_move_tail(&priv->lru.unbacked, obj); drm_gem_lru_move_tail_locked(&priv->lru.unbacked, obj);
} else if (msm_obj->pin_count) { } else if (msm_obj->pin_count) {
drm_gem_lru_move_tail(&priv->lru.pinned, obj); drm_gem_lru_move_tail_locked(&priv->lru.pinned, obj);
} else if (msm_obj->madv == MSM_MADV_WILLNEED) { } else if (msm_obj->madv == MSM_MADV_WILLNEED) {
drm_gem_lru_move_tail(&priv->lru.willneed, obj); drm_gem_lru_move_tail_locked(&priv->lru.willneed, obj);
} else { } else {
GEM_WARN_ON(msm_obj->madv != MSM_MADV_DONTNEED); GEM_WARN_ON(msm_obj->madv != MSM_MADV_DONTNEED);
drm_gem_lru_move_tail(&priv->lru.dontneed, obj); drm_gem_lru_move_tail_locked(&priv->lru.dontneed, obj);
} }
} }
static void update_lru(struct drm_gem_object *obj)
{
struct msm_drm_private *priv = obj->dev->dev_private;
mutex_lock(&priv->lru.lock);
update_lru_locked(obj);
mutex_unlock(&priv->lru.lock);
}
/* allocate pages from VRAM carveout, used when no IOMMU: */ /* allocate pages from VRAM carveout, used when no IOMMU: */
static struct page **get_pages_vram(struct drm_gem_object *obj, int npages) static struct page **get_pages_vram(struct drm_gem_object *obj, int npages)
{ {
...@@ -200,6 +209,7 @@ static void put_pages(struct drm_gem_object *obj) ...@@ -200,6 +209,7 @@ static void put_pages(struct drm_gem_object *obj)
static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj) static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj)
{ {
struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct page **p; struct page **p;
...@@ -210,10 +220,13 @@ static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj) ...@@ -210,10 +220,13 @@ static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj)
} }
p = get_pages(obj); p = get_pages(obj);
if (!IS_ERR(p)) { if (IS_ERR(p))
to_msm_bo(obj)->pin_count++; return p;
update_lru(obj);
} mutex_lock(&priv->lru.lock);
msm_obj->pin_count++;
update_lru_locked(obj);
mutex_unlock(&priv->lru.lock);
return p; return p;
} }
...@@ -464,14 +477,16 @@ int msm_gem_pin_vma_locked(struct drm_gem_object *obj, struct msm_gem_vma *vma) ...@@ -464,14 +477,16 @@ int msm_gem_pin_vma_locked(struct drm_gem_object *obj, struct msm_gem_vma *vma)
void msm_gem_unpin_locked(struct drm_gem_object *obj) void msm_gem_unpin_locked(struct drm_gem_object *obj)
{ {
struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_gem_assert_locked(obj); msm_gem_assert_locked(obj);
mutex_lock(&priv->lru.lock);
msm_obj->pin_count--; msm_obj->pin_count--;
GEM_WARN_ON(msm_obj->pin_count < 0); GEM_WARN_ON(msm_obj->pin_count < 0);
update_lru_locked(obj);
update_lru(obj); mutex_unlock(&priv->lru.lock);
} }
struct msm_gem_vma *msm_gem_get_vma_locked(struct drm_gem_object *obj, struct msm_gem_vma *msm_gem_get_vma_locked(struct drm_gem_object *obj,
...@@ -739,10 +754,13 @@ void msm_gem_put_vaddr(struct drm_gem_object *obj) ...@@ -739,10 +754,13 @@ void msm_gem_put_vaddr(struct drm_gem_object *obj)
*/ */
int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv)
{ {
struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_gem_lock(obj); msm_gem_lock(obj);
mutex_lock(&priv->lru.lock);
if (msm_obj->madv != __MSM_MADV_PURGED) if (msm_obj->madv != __MSM_MADV_PURGED)
msm_obj->madv = madv; msm_obj->madv = madv;
...@@ -751,7 +769,9 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) ...@@ -751,7 +769,9 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv)
/* If the obj is inactive, we might need to move it /* If the obj is inactive, we might need to move it
* between inactive lists * between inactive lists
*/ */
update_lru(obj); update_lru_locked(obj);
mutex_unlock(&priv->lru.lock);
msm_gem_unlock(obj); msm_gem_unlock(obj);
...@@ -761,6 +781,7 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) ...@@ -761,6 +781,7 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv)
void msm_gem_purge(struct drm_gem_object *obj) void msm_gem_purge(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_gem_assert_locked(obj); msm_gem_assert_locked(obj);
...@@ -777,7 +798,10 @@ void msm_gem_purge(struct drm_gem_object *obj) ...@@ -777,7 +798,10 @@ void msm_gem_purge(struct drm_gem_object *obj)
put_iova_vmas(obj); put_iova_vmas(obj);
mutex_lock(&priv->lru.lock);
/* A one-way transition: */
msm_obj->madv = __MSM_MADV_PURGED; msm_obj->madv = __MSM_MADV_PURGED;
mutex_unlock(&priv->lru.lock);
drm_gem_free_mmap_offset(obj); drm_gem_free_mmap_offset(obj);
......
...@@ -86,7 +86,9 @@ struct msm_gem_object { ...@@ -86,7 +86,9 @@ struct msm_gem_object {
uint32_t flags; uint32_t flags;
/** /**
* Advice: are the backing pages purgeable? * madv: are the backing pages purgeable?
*
* Protected by obj lock and LRU lock
*/ */
uint8_t madv; uint8_t madv;
...@@ -114,6 +116,11 @@ struct msm_gem_object { ...@@ -114,6 +116,11 @@ struct msm_gem_object {
char name[32]; /* Identifier to print for the debugfs files */ char name[32]; /* Identifier to print for the debugfs files */
/**
* pin_count: Number of times the pages are pinned
*
* Protected by LRU lock.
*/
int pin_count; int pin_count;
}; };
#define to_msm_bo(x) container_of(x, struct msm_gem_object, base) #define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment