drm/vmwgfx: Resource evict fixes
Fix an error message that was incorrectly blaming device resource id
shortage.
Also make sure we correctly catch resource eviction errors, that
could otherwise lead to evictable resources temporarily not being on the
LRU list.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
Cc: stable@vger.kernel.org
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 0e67cf4..941e5ff 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -32,6 +32,8 @@
#include <drm/drmP.h>
#include "vmwgfx_resource_priv.h"
+#define VMW_RES_EVICT_ERR_COUNT 10
+
struct vmw_user_dma_buffer {
struct ttm_base_object base;
struct vmw_dma_buffer dma;
@@ -1091,8 +1093,9 @@
* to a backup buffer.
*
* @res: The resource to evict.
+ * @interruptible: Whether to wait interruptible.
*/
-int vmw_resource_do_evict(struct vmw_resource *res)
+int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible)
{
struct ttm_validate_buffer val_buf;
const struct vmw_res_func *func = res->func;
@@ -1102,7 +1105,8 @@
BUG_ON(!func->may_evict);
val_buf.bo = NULL;
- ret = vmw_resource_check_buffer(res, &ticket, true, &val_buf);
+ ret = vmw_resource_check_buffer(res, &ticket, interruptible,
+ &val_buf);
if (unlikely(ret != 0))
return ret;
@@ -1141,6 +1145,7 @@
struct vmw_private *dev_priv = res->dev_priv;
struct list_head *lru_list = &dev_priv->res_lru[res->func->res_type];
struct ttm_validate_buffer val_buf;
+ unsigned err_count = 0;
if (likely(!res->func->may_evict))
return 0;
@@ -1155,7 +1160,7 @@
write_lock(&dev_priv->resource_lock);
if (list_empty(lru_list) || !res->func->may_evict) {
- DRM_ERROR("Out of device device id entries "
+ DRM_ERROR("Out of device device resources "
"for %s.\n", res->func->type_name);
ret = -EBUSY;
write_unlock(&dev_priv->resource_lock);
@@ -1168,7 +1173,19 @@
list_del_init(&evict_res->lru_head);
write_unlock(&dev_priv->resource_lock);
- vmw_resource_do_evict(evict_res);
+
+ ret = vmw_resource_do_evict(evict_res, true);
+ if (unlikely(ret != 0)) {
+ write_lock(&dev_priv->resource_lock);
+ list_add_tail(&evict_res->lru_head, lru_list);
+ write_unlock(&dev_priv->resource_lock);
+ if (ret == -ERESTARTSYS ||
+ ++err_count > VMW_RES_EVICT_ERR_COUNT) {
+ vmw_resource_unreference(&evict_res);
+ goto out_no_validate;
+ }
+ }
+
vmw_resource_unreference(&evict_res);
} while (1);
@@ -1253,13 +1270,15 @@
* @type: The resource type to evict
*
* To avoid thrashing starvation or as part of the hibernation sequence,
- * evict all evictable resources of a specific type.
+ * try to evict all evictable resources of a specific type.
*/
static void vmw_resource_evict_type(struct vmw_private *dev_priv,
enum vmw_res_type type)
{
struct list_head *lru_list = &dev_priv->res_lru[type];
struct vmw_resource *evict_res;
+ unsigned err_count = 0;
+ int ret;
do {
write_lock(&dev_priv->resource_lock);
@@ -1272,7 +1291,18 @@
lru_head));
list_del_init(&evict_res->lru_head);
write_unlock(&dev_priv->resource_lock);
- vmw_resource_do_evict(evict_res);
+
+ ret = vmw_resource_do_evict(evict_res, false);
+ if (unlikely(ret != 0)) {
+ write_lock(&dev_priv->resource_lock);
+ list_add_tail(&evict_res->lru_head, lru_list);
+ write_unlock(&dev_priv->resource_lock);
+ if (++err_count > VMW_RES_EVICT_ERR_COUNT) {
+ vmw_resource_unreference(&evict_res);
+ return;
+ }
+ }
+
vmw_resource_unreference(&evict_res);
} while (1);