diff mbox series

[1/4] drm/vmwgfx: Assign eviction priorities to resources

Message ID 20190618062442.14647-1-thomas@shipmail.org (mailing list archive)
State New, archived
Headers show
Series [1/4] drm/vmwgfx: Assign eviction priorities to resources | expand

Commit Message

Thomas Hellström (VMware) June 18, 2019, 6:24 a.m. UTC
From: Thomas Hellstrom <thellstrom@vmware.com>

TTM provides a means to assign eviction priorities to buffer object. This
means that all buffer objects with a lower priority will be evicted first
on memory pressure.
Use this to make sure surfaces and in particular non-dirty surfaces are
evicted first. Evicting in particular shaders, cotables and contexts imply
a significant performance hit on vmwgfx, so make sure these resources are
evicted last.
Some buffer objects are sub-allocated in user-space which means we can have
many resources attached to a single buffer object or resource. In that case
the buffer object is given the highest priority of the attached resources.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Deepak Rawat <drawat@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_bo.c            |  2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_context.c       |  4 ++
 drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c       | 13 ++--
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h           | 72 +++++++++++++++++++
 drivers/gpu/drm/vmwgfx/vmwgfx_resource.c      | 56 +++++++++++----
 drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h |  2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_shader.c        |  8 ++-
 drivers/gpu/drm/vmwgfx/vmwgfx_surface.c       |  4 ++
 8 files changed, 141 insertions(+), 20 deletions(-)

Comments

Emil Velikov June 18, 2019, 10:54 a.m. UTC | #1
Hi Thomas,

On 2019/06/18, Thomas Hellström (VMware) wrote:
> From: Thomas Hellstrom <thellstrom@vmware.com>
> 
> TTM provides a means to assign eviction priorities to buffer object. This
> means that all buffer objects with a lower priority will be evicted first
> on memory pressure.
> Use this to make sure surfaces and in particular non-dirty surfaces are
> evicted first. Evicting in particular shaders, cotables and contexts imply
> a significant performance hit on vmwgfx, so make sure these resources are
> evicted last.
> Some buffer objects are sub-allocated in user-space which means we can have
> many resources attached to a single buffer object or resource. In that case
> the buffer object is given the highest priority of the attached resources.
> 
> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
> Reviewed-by: Deepak Rawat <drawat@vmware.com>
Fwiw patches 1-3 are:
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>

Patch 4 is:
Acked-by: Emil Velikov <emil.velikov@collabora.com>

Huge thanks for sorting this out.
Emil
Daniel Vetter June 18, 2019, 12:19 p.m. UTC | #2
On Tue, Jun 18, 2019 at 11:54:08AM +0100, Emil Velikov wrote:
> Hi Thomas,
> 
> On 2019/06/18, Thomas Hellström (VMware) wrote:
> > From: Thomas Hellstrom <thellstrom@vmware.com>
> > 
> > TTM provides a means to assign eviction priorities to buffer object. This
> > means that all buffer objects with a lower priority will be evicted first
> > on memory pressure.
> > Use this to make sure surfaces and in particular non-dirty surfaces are
> > evicted first. Evicting in particular shaders, cotables and contexts imply
> > a significant performance hit on vmwgfx, so make sure these resources are
> > evicted last.
> > Some buffer objects are sub-allocated in user-space which means we can have
> > many resources attached to a single buffer object or resource. In that case
> > the buffer object is given the highest priority of the attached resources.
> > 
> > Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
> > Reviewed-by: Deepak Rawat <drawat@vmware.com>
> Fwiw patches 1-3 are:
> Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
> 
> Patch 4 is:
> Acked-by: Emil Velikov <emil.velikov@collabora.com>
> 
> Huge thanks for sorting this out.

Oh, does this mean we can remove the varios master* callbacks from
drm_driver now? Iirc vmwgfx was the only user, and those callbacks seem
very tempting to various folks for implementing questionable driver hacks
... Happy to type the patches, but maybe simpler if you do that since all
this gets merged through the vmwgfx tree.

Cheers, Daniel
Thomas Hellström (VMware) June 18, 2019, 1:08 p.m. UTC | #3
On 6/18/19 2:19 PM, Daniel Vetter wrote:
> On Tue, Jun 18, 2019 at 11:54:08AM +0100, Emil Velikov wrote:
>> Hi Thomas,
>>
>> On 2019/06/18, Thomas Hellström (VMware) wrote:
>>> From: Thomas Hellstrom <thellstrom@vmware.com>
>>>
>>> TTM provides a means to assign eviction priorities to buffer object. This
>>> means that all buffer objects with a lower priority will be evicted first
>>> on memory pressure.
>>> Use this to make sure surfaces and in particular non-dirty surfaces are
>>> evicted first. Evicting in particular shaders, cotables and contexts imply
>>> a significant performance hit on vmwgfx, so make sure these resources are
>>> evicted last.
>>> Some buffer objects are sub-allocated in user-space which means we can have
>>> many resources attached to a single buffer object or resource. In that case
>>> the buffer object is given the highest priority of the attached resources.
>>>
>>> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
>>> Reviewed-by: Deepak Rawat <drawat@vmware.com>
>> Fwiw patches 1-3 are:
>> Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
>>
>> Patch 4 is:
>> Acked-by: Emil Velikov <emil.velikov@collabora.com>
>>
>> Huge thanks for sorting this out.
> Oh, does this mean we can remove the varios master* callbacks from
> drm_driver now? Iirc vmwgfx was the only user, and those callbacks seem
> very tempting to various folks for implementing questionable driver hacks
> ... Happy to type the patches, but maybe simpler if you do that since all
> this gets merged through the vmwgfx tree.
>
> Cheers, Daniel

In case someone follow this, I'll paste in the commit message of 4/4 
which is the relevant one here..

8<--------------------------------------------

At one point, the GPU command verifier and user-space handle manager
couldn't properly protect GPU clients from accessing each other's data.
Instead there was an elaborate mechanism to make sure only the active
master's primary clients could render. The other clients were either
put to sleep or even killed (if the master had exited). VRAM was
evicted on master switch. With the advent of render-node functionality,
we relaxed the VRAM eviction, but the other mechanisms stayed in place.

Now that the GPU  command verifier and ttm object manager properly
isolates primary clients from different master realms we can remove the
master switch related code and drop those legacy features.

8<-------------------------------------------

I think we can at least take a look. I'm out on a fairly long vacation 
soon so in any case it won't be before August or so.

One use we still have for master_set() is that if a master is switched 
away, and then the mode list changes, and then the master is switched 
back, it will typically not remember to act on the sysfs event received 
while switched out, and come back in an incorrect mode. Since mode-list 
changes happen quite frequently with virtual display adapters that's bad.

But perhaps we can consider moving that to core, if that's what needed 
to get rid of the master switch callbacks.

/Thomas
Thomas Hellström (VMware) June 18, 2019, 1:27 p.m. UTC | #4
On 6/18/19 12:54 PM, Emil Velikov wrote:
> Hi Thomas,
>
> On 2019/06/18, Thomas Hellström (VMware) wrote:
>> From: Thomas Hellstrom <thellstrom@vmware.com>
>>
>> TTM provides a means to assign eviction priorities to buffer object. This
>> means that all buffer objects with a lower priority will be evicted first
>> on memory pressure.
>> Use this to make sure surfaces and in particular non-dirty surfaces are
>> evicted first. Evicting in particular shaders, cotables and contexts imply
>> a significant performance hit on vmwgfx, so make sure these resources are
>> evicted last.
>> Some buffer objects are sub-allocated in user-space which means we can have
>> many resources attached to a single buffer object or resource. In that case
>> the buffer object is given the highest priority of the attached resources.
>>
>> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
>> Reviewed-by: Deepak Rawat <drawat@vmware.com>
> Fwiw patches 1-3 are:
> Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
>
> Patch 4 is:
> Acked-by: Emil Velikov <emil.velikov@collabora.com>
>
> Huge thanks for sorting this out.
> Emil

Thanks for reviewing, Emil.

/Thomas
Daniel Vetter June 18, 2019, 1:27 p.m. UTC | #5
On Tue, Jun 18, 2019 at 03:08:01PM +0200, Thomas Hellstrom wrote:
> On 6/18/19 2:19 PM, Daniel Vetter wrote:
> > On Tue, Jun 18, 2019 at 11:54:08AM +0100, Emil Velikov wrote:
> > > Hi Thomas,
> > > 
> > > On 2019/06/18, Thomas Hellström (VMware) wrote:
> > > > From: Thomas Hellstrom <thellstrom@vmware.com>
> > > > 
> > > > TTM provides a means to assign eviction priorities to buffer object. This
> > > > means that all buffer objects with a lower priority will be evicted first
> > > > on memory pressure.
> > > > Use this to make sure surfaces and in particular non-dirty surfaces are
> > > > evicted first. Evicting in particular shaders, cotables and contexts imply
> > > > a significant performance hit on vmwgfx, so make sure these resources are
> > > > evicted last.
> > > > Some buffer objects are sub-allocated in user-space which means we can have
> > > > many resources attached to a single buffer object or resource. In that case
> > > > the buffer object is given the highest priority of the attached resources.
> > > > 
> > > > Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
> > > > Reviewed-by: Deepak Rawat <drawat@vmware.com>
> > > Fwiw patches 1-3 are:
> > > Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
> > > 
> > > Patch 4 is:
> > > Acked-by: Emil Velikov <emil.velikov@collabora.com>
> > > 
> > > Huge thanks for sorting this out.
> > Oh, does this mean we can remove the varios master* callbacks from
> > drm_driver now? Iirc vmwgfx was the only user, and those callbacks seem
> > very tempting to various folks for implementing questionable driver hacks
> > ... Happy to type the patches, but maybe simpler if you do that since all
> > this gets merged through the vmwgfx tree.
> > 
> > Cheers, Daniel
> 
> In case someone follow this, I'll paste in the commit message of 4/4 which
> is the relevant one here..
> 
> 8<--------------------------------------------
> 
> At one point, the GPU command verifier and user-space handle manager
> couldn't properly protect GPU clients from accessing each other's data.
> Instead there was an elaborate mechanism to make sure only the active
> master's primary clients could render. The other clients were either
> put to sleep or even killed (if the master had exited). VRAM was
> evicted on master switch. With the advent of render-node functionality,
> we relaxed the VRAM eviction, but the other mechanisms stayed in place.
> 
> Now that the GPU  command verifier and ttm object manager properly
> isolates primary clients from different master realms we can remove the
> master switch related code and drop those legacy features.
> 
> 8<-------------------------------------------
> 
> I think we can at least take a look. I'm out on a fairly long vacation soon
> so in any case it won't be before August or so.

Ah don't worry, if this all lands in the 5.3 merge window I can take a
look in a few weeks.

> One use we still have for master_set() is that if a master is switched away,
> and then the mode list changes, and then the master is switched back, it
> will typically not remember to act on the sysfs event received while
> switched out, and come back in an incorrect mode. Since mode-list changes
> happen quite frequently with virtual display adapters that's bad.
> 
> But perhaps we can consider moving that to core, if that's what needed to
> get rid of the master switch callbacks.

Hm, this sounds a bit like papering over userspace bugs, at least if
you're referring to drm_sysfs_hotplug_event(). Userspace is supposed to
either keep listening or to re-acquire all the kms output state and do the
hotplugg processing in one go when becoming active again.

Ofc it exists, so we can't just remove it. I wouldn't want to make this
part of the uapi though, feels like duct-taping around sloppy userspace.
Maybe we could work on a gradual plan to deprecate this, with limiting it
only to older vmwgfx versions as a start?

These kind of tiny but important differences in how drivers implement kms
is why I'd much, much prefer it's not even possible to do stuff like this.

Thanks, Daniel
Thomas Hellström (VMware) June 18, 2019, 2:14 p.m. UTC | #6
On 6/18/19 3:27 PM, Daniel Vetter wrote:
> On Tue, Jun 18, 2019 at 03:08:01PM +0200, Thomas Hellstrom wrote:
>> On 6/18/19 2:19 PM, Daniel Vetter wrote:
>>> On Tue, Jun 18, 2019 at 11:54:08AM +0100, Emil Velikov wrote:
>>>> Hi Thomas,
>>>>
>>>> On 2019/06/18, Thomas Hellström (VMware) wrote:
>>>>> From: Thomas Hellstrom <thellstrom@vmware.com>
>>>>>
>>>>> TTM provides a means to assign eviction priorities to buffer object. This
>>>>> means that all buffer objects with a lower priority will be evicted first
>>>>> on memory pressure.
>>>>> Use this to make sure surfaces and in particular non-dirty surfaces are
>>>>> evicted first. Evicting in particular shaders, cotables and contexts imply
>>>>> a significant performance hit on vmwgfx, so make sure these resources are
>>>>> evicted last.
>>>>> Some buffer objects are sub-allocated in user-space which means we can have
>>>>> many resources attached to a single buffer object or resource. In that case
>>>>> the buffer object is given the highest priority of the attached resources.
>>>>>
>>>>> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
>>>>> Reviewed-by: Deepak Rawat <drawat@vmware.com>
>>>> Fwiw patches 1-3 are:
>>>> Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
>>>>
>>>> Patch 4 is:
>>>> Acked-by: Emil Velikov <emil.velikov@collabora.com>
>>>>
>>>> Huge thanks for sorting this out.
>>> Oh, does this mean we can remove the varios master* callbacks from
>>> drm_driver now? Iirc vmwgfx was the only user, and those callbacks seem
>>> very tempting to various folks for implementing questionable driver hacks
>>> ... Happy to type the patches, but maybe simpler if you do that since all
>>> this gets merged through the vmwgfx tree.
>>>
>>> Cheers, Daniel
>> In case someone follow this, I'll paste in the commit message of 4/4 which
>> is the relevant one here..
>>
>> 8<--------------------------------------------
>>
>> At one point, the GPU command verifier and user-space handle manager
>> couldn't properly protect GPU clients from accessing each other's data.
>> Instead there was an elaborate mechanism to make sure only the active
>> master's primary clients could render. The other clients were either
>> put to sleep or even killed (if the master had exited). VRAM was
>> evicted on master switch. With the advent of render-node functionality,
>> we relaxed the VRAM eviction, but the other mechanisms stayed in place.
>>
>> Now that the GPU  command verifier and ttm object manager properly
>> isolates primary clients from different master realms we can remove the
>> master switch related code and drop those legacy features.
>>
>> 8<-------------------------------------------
>>
>> I think we can at least take a look. I'm out on a fairly long vacation soon
>> so in any case it won't be before August or so.
> Ah don't worry, if this all lands in the 5.3 merge window I can take a
> look in a few weeks.
>
>> One use we still have for master_set() is that if a master is switched away,
>> and then the mode list changes, and then the master is switched back, it
>> will typically not remember to act on the sysfs event received while
>> switched out, and come back in an incorrect mode. Since mode-list changes
>> happen quite frequently with virtual display adapters that's bad.
>>
>> But perhaps we can consider moving that to core, if that's what needed to
>> get rid of the master switch callbacks.
> Hm, this sounds a bit like papering over userspace bugs, at least if
> you're referring to drm_sysfs_hotplug_event(). Userspace is supposed to
> either keep listening or to re-acquire all the kms output state and do the
> hotplugg processing in one go when becoming active again.
>
> Ofc it exists, so we can't just remove it. I wouldn't want to make this
> part of the uapi though, feels like duct-taping around sloppy userspace.
> Maybe we could work on a gradual plan to deprecate this, with limiting it
> only to older vmwgfx versions as a start?

Sounds ok with me. First I guess I need to figure out what compositors / 
user-space drivers actually suffer from this. If there are many, it 
might be a pain trying to fix them all.

Thanks,

Thomas


>
> These kind of tiny but important differences in how drivers implement kms
> is why I'd much, much prefer it's not even possible to do stuff like this.
>
> Thanks, Daniel
Daniel Vetter June 18, 2019, 2:26 p.m. UTC | #7
On Tue, Jun 18, 2019 at 04:14:27PM +0200, Thomas Hellstrom wrote:
> On 6/18/19 3:27 PM, Daniel Vetter wrote:
> > On Tue, Jun 18, 2019 at 03:08:01PM +0200, Thomas Hellstrom wrote:
> > > On 6/18/19 2:19 PM, Daniel Vetter wrote:
> > > > On Tue, Jun 18, 2019 at 11:54:08AM +0100, Emil Velikov wrote:
> > > > > Hi Thomas,
> > > > > 
> > > > > On 2019/06/18, Thomas Hellström (VMware) wrote:
> > > > > > From: Thomas Hellstrom <thellstrom@vmware.com>
> > > > > > 
> > > > > > TTM provides a means to assign eviction priorities to buffer object. This
> > > > > > means that all buffer objects with a lower priority will be evicted first
> > > > > > on memory pressure.
> > > > > > Use this to make sure surfaces and in particular non-dirty surfaces are
> > > > > > evicted first. Evicting in particular shaders, cotables and contexts imply
> > > > > > a significant performance hit on vmwgfx, so make sure these resources are
> > > > > > evicted last.
> > > > > > Some buffer objects are sub-allocated in user-space which means we can have
> > > > > > many resources attached to a single buffer object or resource. In that case
> > > > > > the buffer object is given the highest priority of the attached resources.
> > > > > > 
> > > > > > Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
> > > > > > Reviewed-by: Deepak Rawat <drawat@vmware.com>
> > > > > Fwiw patches 1-3 are:
> > > > > Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
> > > > > 
> > > > > Patch 4 is:
> > > > > Acked-by: Emil Velikov <emil.velikov@collabora.com>
> > > > > 
> > > > > Huge thanks for sorting this out.
> > > > Oh, does this mean we can remove the varios master* callbacks from
> > > > drm_driver now? Iirc vmwgfx was the only user, and those callbacks seem
> > > > very tempting to various folks for implementing questionable driver hacks
> > > > ... Happy to type the patches, but maybe simpler if you do that since all
> > > > this gets merged through the vmwgfx tree.
> > > > 
> > > > Cheers, Daniel
> > > In case someone follow this, I'll paste in the commit message of 4/4 which
> > > is the relevant one here..
> > > 
> > > 8<--------------------------------------------
> > > 
> > > At one point, the GPU command verifier and user-space handle manager
> > > couldn't properly protect GPU clients from accessing each other's data.
> > > Instead there was an elaborate mechanism to make sure only the active
> > > master's primary clients could render. The other clients were either
> > > put to sleep or even killed (if the master had exited). VRAM was
> > > evicted on master switch. With the advent of render-node functionality,
> > > we relaxed the VRAM eviction, but the other mechanisms stayed in place.
> > > 
> > > Now that the GPU  command verifier and ttm object manager properly
> > > isolates primary clients from different master realms we can remove the
> > > master switch related code and drop those legacy features.
> > > 
> > > 8<-------------------------------------------
> > > 
> > > I think we can at least take a look. I'm out on a fairly long vacation soon
> > > so in any case it won't be before August or so.
> > Ah don't worry, if this all lands in the 5.3 merge window I can take a
> > look in a few weeks.
> > 
> > > One use we still have for master_set() is that if a master is switched away,
> > > and then the mode list changes, and then the master is switched back, it
> > > will typically not remember to act on the sysfs event received while
> > > switched out, and come back in an incorrect mode. Since mode-list changes
> > > happen quite frequently with virtual display adapters that's bad.
> > > 
> > > But perhaps we can consider moving that to core, if that's what needed to
> > > get rid of the master switch callbacks.
> > Hm, this sounds a bit like papering over userspace bugs, at least if
> > you're referring to drm_sysfs_hotplug_event(). Userspace is supposed to
> > either keep listening or to re-acquire all the kms output state and do the
> > hotplugg processing in one go when becoming active again.
> > 
> > Ofc it exists, so we can't just remove it. I wouldn't want to make this
> > part of the uapi though, feels like duct-taping around sloppy userspace.
> > Maybe we could work on a gradual plan to deprecate this, with limiting it
> > only to older vmwgfx versions as a start?
> 
> Sounds ok with me. First I guess I need to figure out what compositors /
> user-space drivers actually suffer from this. If there are many, it might be
> a pain trying to fix them all.

Yeah if this shipped already sailed for most compositors, then I guess we
need to upgrade this to cross-driver behavior. If it's just some vmwgfx
thing, then we should try to phase it out slowly somehow.

Either way I much prefer consistent behaviour for anything that is
relevant for kms clients and compositors.

Anyway, great progress on the other master callbacks, thanks a lot for
doing that!

Cheers, Daniel

> 
> Thanks,
> 
> Thomas
> 
> 
> > 
> > These kind of tiny but important differences in how drivers implement kms
> > is why I'd much, much prefer it's not even possible to do stuff like this.
> > 
> > Thanks, Daniel
> 
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 5d5c2bce01f3..c0829d50eecc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -510,6 +510,8 @@  int vmw_bo_init(struct vmw_private *dev_priv,
 
 	acc_size = vmw_bo_acc_size(dev_priv, size, user);
 	memset(vmw_bo, 0, sizeof(*vmw_bo));
+	BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3);
+	vmw_bo->base.priority = 3;
 
 	INIT_LIST_HEAD(&vmw_bo->res_list);
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
index 63f111068a44..a56c9d802382 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
@@ -88,6 +88,8 @@  static const struct vmw_res_func vmw_gb_context_func = {
 	.res_type = vmw_res_context,
 	.needs_backup = true,
 	.may_evict = true,
+	.prio = 3,
+	.dirty_prio = 3,
 	.type_name = "guest backed contexts",
 	.backup_placement = &vmw_mob_placement,
 	.create = vmw_gb_context_create,
@@ -100,6 +102,8 @@  static const struct vmw_res_func vmw_dx_context_func = {
 	.res_type = vmw_res_dx_context,
 	.needs_backup = true,
 	.may_evict = true,
+	.prio = 3,
+	.dirty_prio = 3,
 	.type_name = "dx contexts",
 	.backup_placement = &vmw_mob_placement,
 	.create = vmw_dx_context_create,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
index b4f6e1217c9d..8c699cb2565b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
@@ -116,6 +116,8 @@  static const struct vmw_res_func vmw_cotable_func = {
 	.res_type = vmw_res_cotable,
 	.needs_backup = true,
 	.may_evict = true,
+	.prio = 3,
+	.dirty_prio = 3,
 	.type_name = "context guest backed object tables",
 	.backup_placement = &vmw_mob_placement,
 	.create = vmw_cotable_create,
@@ -307,7 +309,7 @@  static int vmw_cotable_unbind(struct vmw_resource *res,
 	struct ttm_buffer_object *bo = val_buf->bo;
 	struct vmw_fence_obj *fence;
 
-	if (list_empty(&res->mob_head))
+	if (!vmw_resource_mob_attached(res))
 		return 0;
 
 	WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB);
@@ -453,6 +455,7 @@  static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
 		goto out_wait;
 	}
 
+	vmw_resource_mob_detach(res);
 	res->backup = buf;
 	res->backup_size = new_size;
 	vcotbl->size_read_back = cur_size_read_back;
@@ -467,12 +470,12 @@  static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
 		res->backup = old_buf;
 		res->backup_size = old_size;
 		vcotbl->size_read_back = old_size_read_back;
+		vmw_resource_mob_attach(res);
 		goto out_wait;
 	}
 
+	vmw_resource_mob_attach(res);
 	/* Let go of the old mob. */
-	list_del(&res->mob_head);
-	list_add_tail(&res->mob_head, &buf->res_list);
 	vmw_bo_unreference(&old_buf);
 	res->id = vcotbl->type;
 
@@ -496,7 +499,7 @@  static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
  * is called before bind() in the validation sequence is instead used for two
  * things.
  * 1) Unscrub the cotable if it is scrubbed and still attached to a backup
- *    buffer, that is, if @res->mob_head is non-empty.
+ *    buffer.
  * 2) Resize the cotable if needed.
  */
 static int vmw_cotable_create(struct vmw_resource *res)
@@ -512,7 +515,7 @@  static int vmw_cotable_create(struct vmw_resource *res)
 		new_size *= 2;
 
 	if (likely(new_size <= res->backup_size)) {
-		if (vcotbl->scrubbed && !list_empty(&res->mob_head)) {
+		if (vcotbl->scrubbed && vmw_resource_mob_attached(res)) {
 			ret = vmw_cotable_unscrub(res);
 			if (ret)
 				return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 366dcfc1f9bb..7c935c72d368 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -86,6 +86,15 @@  struct vmw_fpriv {
 	bool gb_aware; /* user-space is guest-backed aware */
 };
 
+/**
+ * struct vmw_buffer_object - TTM buffer object with vmwgfx additions
+ * @base: The TTM buffer object
+ * @res_list: List of resources using this buffer object as a backing MOB
+ * @pin_count: pin depth
+ * @dx_query_ctx: DX context if this buffer object is used as a DX query MOB
+ * @map: Kmap object for semi-persistent mappings
+ * @res_prios: Eviction priority counts for attached resources
+ */
 struct vmw_buffer_object {
 	struct ttm_buffer_object base;
 	struct list_head res_list;
@@ -94,6 +103,7 @@  struct vmw_buffer_object {
 	struct vmw_resource *dx_query_ctx;
 	/* Protected by reservation */
 	struct ttm_bo_kmap_obj map;
+	u32 res_prios[TTM_MAX_BO_PRIORITY];
 };
 
 /**
@@ -145,6 +155,7 @@  struct vmw_resource {
 	struct kref kref;
 	struct vmw_private *dev_priv;
 	int id;
+	u32 used_prio;
 	unsigned long backup_size;
 	bool res_dirty;
 	bool backup_dirty;
@@ -709,6 +720,19 @@  extern void vmw_query_move_notify(struct ttm_buffer_object *bo,
 extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob);
 extern void vmw_resource_evict_all(struct vmw_private *dev_priv);
 extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo);
+void vmw_resource_mob_attach(struct vmw_resource *res);
+void vmw_resource_mob_detach(struct vmw_resource *res);
+
+/**
+ * vmw_resource_mob_attached - Whether a resource currently has a mob attached
+ * @res: The resource
+ *
+ * Return: true if the resource has a mob attached, false otherwise.
+ */
+static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
+{
+	return !list_empty(&res->mob_head);
+}
 
 /**
  * vmw_user_resource_noref_release - release a user resource pointer looked up
@@ -787,6 +811,54 @@  static inline void vmw_user_bo_noref_release(void)
 	ttm_base_object_noref_release();
 }
 
+/**
+ * vmw_bo_adjust_prio - Adjust the buffer object eviction priority
+ * according to attached resources
+ * @vbo: The struct vmw_buffer_object
+ */
+static inline void vmw_bo_prio_adjust(struct vmw_buffer_object *vbo)
+{
+	int i = ARRAY_SIZE(vbo->res_prios);
+
+	while (i--) {
+		if (vbo->res_prios[i]) {
+			vbo->base.priority = i;
+			return;
+		}
+	}
+
+	vbo->base.priority = 3;
+}
+
+/**
+ * vmw_bo_prio_add - Notify a buffer object of a newly attached resource
+ * eviction priority
+ * @vbo: The struct vmw_buffer_object
+ * @prio: The resource priority
+ *
+ * After being notified, the code assigns the highest resource eviction priority
+ * to the backing buffer object (mob).
+ */
+static inline void vmw_bo_prio_add(struct vmw_buffer_object *vbo, int prio)
+{
+	if (vbo->res_prios[prio]++ == 0)
+		vmw_bo_prio_adjust(vbo);
+}
+
+/**
+ * vmw_bo_prio_del - Notify a buffer object of a resource with a certain
+ * priority being removed
+ * @vbo: The struct vmw_buffer_object
+ * @prio: The resource priority
+ *
+ * After being notified, the code assigns the highest resource eviction priority
+ * to the backing buffer object (mob).
+ */
+static inline void vmw_bo_prio_del(struct vmw_buffer_object *vbo, int prio)
+{
+	if (--vbo->res_prios[prio] == 0)
+		vmw_bo_prio_adjust(vbo);
+}
 
 /**
  * Misc Ioctl functionality - vmwgfx_ioctl.c
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 1d38a8b2f2ec..be7d4149a129 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -34,6 +34,37 @@ 
 
 #define VMW_RES_EVICT_ERR_COUNT 10
 
+/**
+ * vmw_resource_mob_attach - Mark a resource as attached to its backing mob
+ * @res: The resource
+ */
+void vmw_resource_mob_attach(struct vmw_resource *res)
+{
+	struct vmw_buffer_object *backup = res->backup;
+
+	lockdep_assert_held(&backup->base.resv->lock.base);
+	res->used_prio = (res->res_dirty) ? res->func->dirty_prio :
+		res->func->prio;
+	list_add_tail(&res->mob_head, &backup->res_list);
+	vmw_bo_prio_add(backup, res->used_prio);
+}
+
+/**
+ * vmw_resource_mob_detach - Mark a resource as detached from its backing mob
+ * @res: The resource
+ */
+void vmw_resource_mob_detach(struct vmw_resource *res)
+{
+	struct vmw_buffer_object *backup = res->backup;
+
+	lockdep_assert_held(&backup->base.resv->lock.base);
+	if (vmw_resource_mob_attached(res)) {
+		list_del_init(&res->mob_head);
+		vmw_bo_prio_del(backup, res->used_prio);
+	}
+}
+
+
 struct vmw_resource *vmw_resource_reference(struct vmw_resource *res)
 {
 	kref_get(&res->kref);
@@ -80,7 +111,7 @@  static void vmw_resource_release(struct kref *kref)
 		struct ttm_buffer_object *bo = &res->backup->base;
 
 		ttm_bo_reserve(bo, false, false, NULL);
-		if (!list_empty(&res->mob_head) &&
+		if (vmw_resource_mob_attached(res) &&
 		    res->func->unbind != NULL) {
 			struct ttm_validate_buffer val_buf;
 
@@ -89,7 +120,7 @@  static void vmw_resource_release(struct kref *kref)
 			res->func->unbind(res, false, &val_buf);
 		}
 		res->backup_dirty = false;
-		list_del_init(&res->mob_head);
+		vmw_resource_mob_detach(res);
 		ttm_bo_unreserve(bo);
 		vmw_bo_unreference(&res->backup);
 	}
@@ -179,6 +210,7 @@  int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
 	res->backup_offset = 0;
 	res->backup_dirty = false;
 	res->res_dirty = false;
+	res->used_prio = 3;
 	if (delay_id)
 		return 0;
 	else
@@ -355,14 +387,14 @@  static int vmw_resource_do_validate(struct vmw_resource *res,
 	}
 
 	if (func->bind &&
-	    ((func->needs_backup && list_empty(&res->mob_head) &&
+	    ((func->needs_backup && !vmw_resource_mob_attached(res) &&
 	      val_buf->bo != NULL) ||
 	     (!func->needs_backup && val_buf->bo != NULL))) {
 		ret = func->bind(res, val_buf);
 		if (unlikely(ret != 0))
 			goto out_bind_failed;
 		if (func->needs_backup)
-			list_add_tail(&res->mob_head, &res->backup->res_list);
+			vmw_resource_mob_attach(res);
 	}
 
 	return 0;
@@ -402,15 +434,13 @@  void vmw_resource_unreserve(struct vmw_resource *res,
 
 	if (switch_backup && new_backup != res->backup) {
 		if (res->backup) {
-			lockdep_assert_held(&res->backup->base.resv->lock.base);
-			list_del_init(&res->mob_head);
+			vmw_resource_mob_detach(res);
 			vmw_bo_unreference(&res->backup);
 		}
 
 		if (new_backup) {
 			res->backup = vmw_bo_reference(new_backup);
-			lockdep_assert_held(&new_backup->base.resv->lock.base);
-			list_add_tail(&res->mob_head, &new_backup->res_list);
+			vmw_resource_mob_attach(res);
 		} else {
 			res->backup = NULL;
 		}
@@ -469,7 +499,7 @@  vmw_resource_check_buffer(struct ww_acquire_ctx *ticket,
 	if (unlikely(ret != 0))
 		goto out_no_reserve;
 
-	if (res->func->needs_backup && list_empty(&res->mob_head))
+	if (res->func->needs_backup && !vmw_resource_mob_attached(res))
 		return 0;
 
 	backup_dirty = res->backup_dirty;
@@ -574,11 +604,11 @@  static int vmw_resource_do_evict(struct ww_acquire_ctx *ticket,
 		return ret;
 
 	if (unlikely(func->unbind != NULL &&
-		     (!func->needs_backup || !list_empty(&res->mob_head)))) {
+		     (!func->needs_backup || vmw_resource_mob_attached(res)))) {
 		ret = func->unbind(res, res->res_dirty, &val_buf);
 		if (unlikely(ret != 0))
 			goto out_no_unbind;
-		list_del_init(&res->mob_head);
+		vmw_resource_mob_detach(res);
 	}
 	ret = func->destroy(res);
 	res->backup_dirty = true;
@@ -660,7 +690,7 @@  int vmw_resource_validate(struct vmw_resource *res, bool intr)
 	if (unlikely(ret != 0))
 		goto out_no_validate;
 	else if (!res->func->needs_backup && res->backup) {
-		list_del_init(&res->mob_head);
+		WARN_ON_ONCE(vmw_resource_mob_attached(res));
 		vmw_bo_unreference(&res->backup);
 	}
 
@@ -699,7 +729,7 @@  void vmw_resource_unbind_list(struct vmw_buffer_object *vbo)
 		(void) res->func->unbind(res, res->res_dirty, &val_buf);
 		res->backup_dirty = true;
 		res->res_dirty = false;
-		list_del_init(&res->mob_head);
+		vmw_resource_mob_detach(res);
 	}
 
 	(void) ttm_bo_wait(&vbo->base, false, false);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
index 7e19eba0b0b8..984e588c62ca 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h
@@ -78,6 +78,8 @@  struct vmw_res_func {
 	const char *type_name;
 	struct ttm_placement *backup_placement;
 	bool may_evict;
+	u32 prio;
+	u32 dirty_prio;
 
 	int (*create) (struct vmw_resource *res);
 	int (*destroy) (struct vmw_resource *res);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index d310d21f0d54..e139fdfd1635 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -95,6 +95,8 @@  static const struct vmw_res_func vmw_gb_shader_func = {
 	.res_type = vmw_res_shader,
 	.needs_backup = true,
 	.may_evict = true,
+	.prio = 3,
+	.dirty_prio = 3,
 	.type_name = "guest backed shaders",
 	.backup_placement = &vmw_mob_placement,
 	.create = vmw_gb_shader_create,
@@ -106,7 +108,9 @@  static const struct vmw_res_func vmw_gb_shader_func = {
 static const struct vmw_res_func vmw_dx_shader_func = {
 	.res_type = vmw_res_shader,
 	.needs_backup = true,
-	.may_evict = false,
+	.may_evict = true,
+	.prio = 3,
+	.dirty_prio = 3,
 	.type_name = "dx shaders",
 	.backup_placement = &vmw_mob_placement,
 	.create = vmw_dx_shader_create,
@@ -423,7 +427,7 @@  static int vmw_dx_shader_create(struct vmw_resource *res)
 
 	WARN_ON_ONCE(!shader->committed);
 
-	if (!list_empty(&res->mob_head)) {
+	if (vmw_resource_mob_attached(res)) {
 		mutex_lock(&dev_priv->binding_mutex);
 		ret = vmw_dx_shader_unscrub(res);
 		mutex_unlock(&dev_priv->binding_mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 219471903bc1..c40d44f4d9af 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -112,6 +112,8 @@  static const struct vmw_res_func vmw_legacy_surface_func = {
 	.res_type = vmw_res_surface,
 	.needs_backup = false,
 	.may_evict = true,
+	.prio = 1,
+	.dirty_prio = 1,
 	.type_name = "legacy surfaces",
 	.backup_placement = &vmw_srf_placement,
 	.create = &vmw_legacy_srf_create,
@@ -124,6 +126,8 @@  static const struct vmw_res_func vmw_gb_surface_func = {
 	.res_type = vmw_res_surface,
 	.needs_backup = true,
 	.may_evict = true,
+	.prio = 1,
+	.dirty_prio = 2,
 	.type_name = "guest backed surfaces",
 	.backup_placement = &vmw_mob_placement,
 	.create = vmw_gb_surface_create,