diff options
| -rw-r--r-- | linux-core/drm_bo.c | 180 | ||||
| -rw-r--r-- | linux-core/drm_fence.c | 4 | ||||
| -rw-r--r-- | linux-core/i915_fence.c | 3 | 
3 files changed, 109 insertions, 78 deletions
| diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index b8ee6c15..954b7a03 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -247,7 +247,46 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo)  	drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ);  } -static void drm_bo_delayed_delete(drm_device_t * dev) +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, +		       int no_wait) +{ + +	drm_fence_object_t *fence = bo->fence; +	int ret; + +	if (fence) { +		drm_device_t *dev = bo->dev; +		if (drm_fence_object_signaled(fence, bo->fence_type)) { +			drm_fence_usage_deref_unlocked(dev, fence); +			bo->fence = NULL; +			return 0; +		} +		if (no_wait) { +			return -EBUSY; +		} +		ret = +		    drm_fence_object_wait(dev, fence, lazy, ignore_signals, +					  bo->fence_type); +		if (ret) +			return ret; + +		drm_fence_usage_deref_unlocked(dev, fence); +		bo->fence = NULL; + +	} +	return 0; +} + +/* + * Call dev->struct_mutex locked. + */ + +static void drm_bo_delayed_delete(drm_device_t * dev, int remove_all)  {  	drm_buffer_manager_t *bm = &dev->bm; @@ -255,28 +294,23 @@ static void drm_bo_delayed_delete(drm_device_t * dev)  	struct list_head *list, *next;  	drm_fence_object_t *fence; -	mutex_lock(&dev->struct_mutex); -	if (!bm->initialized) -		goto out; - -	list = bm->ddestroy.next;  	list_for_each_safe(list, next, &bm->ddestroy) {  		entry = list_entry(list, drm_buffer_object_t, ddestroy); -		nentry = NULL; - -		/* -		 * Another process may claim access to this entry through the -		 * lru lists. In that case, just skip it. -		 */ - -		if (atomic_read(&entry->usage) != 0) +		atomic_inc(&entry->usage); +		if (atomic_read(&entry->usage) != 1) { +			atomic_dec(&entry->usage);  			continue; +		} -		/* -		 * Since we're the only users, No need to take the  -		 * bo->mutex to watch the fence. -		 */ +		nentry = NULL; +		if (next != &bm->ddestroy) { +			nentry = list_entry(next, drm_buffer_object_t, +					    ddestroy); +			atomic_inc(&nentry->usage); +		} +		mutex_unlock(&dev->struct_mutex); +		mutex_lock(&entry->mutex);  		fence = entry->fence;  		if (fence && drm_fence_object_signaled(fence,  						       entry->fence_type)) { @@ -284,29 +318,38 @@ static void drm_bo_delayed_delete(drm_device_t * dev)  			entry->fence = NULL;  		} -		if (!entry->fence) { - -			/* -			 * Protect the "next" entry against destruction in case -			 * drm_bo_destroy_locked temporarily releases the -			 * struct_mutex; -			 */ +		if (entry->fence && remove_all) { +			if (bm->nice_mode) { +				unsigned long _end = jiffies + 3 * DRM_HZ; +				int ret; +				do { +					ret = drm_bo_wait(entry, 0, 1, 0); +				} while (ret && !time_after_eq(jiffies, _end)); -			nentry = NULL; -			if (next != &bm->ddestroy) { -				nentry = list_entry(next, drm_buffer_object_t, -						    ddestroy); -				atomic_inc(&nentry->usage); +				if (entry->fence) { +					bm->nice_mode = 0; +					DRM_ERROR("Detected GPU lockup or " +						  "fence driver was taken down. " +						  "Evicting waiting buffers.\n"); +				} +			} +			if (entry->fence) { +				drm_fence_usage_deref_unlocked(dev, +							       entry->fence); +				entry->fence = NULL;  			} -			DRM_DEBUG("Destroying delayed buffer object\n"); +		} +		mutex_lock(&dev->struct_mutex); +		mutex_unlock(&entry->mutex); +		if (atomic_dec_and_test(&entry->usage) && (!entry->fence)) {  			list_del_init(&entry->ddestroy);  			drm_bo_destroy_locked(dev, entry); -			if (next != &bm->ddestroy) -				atomic_dec(&nentry->usage); +		} +		if (nentry) { +			atomic_dec(&nentry->usage);  		}  	} -      out: -	mutex_unlock(&dev->struct_mutex); +  }  static void drm_bo_delayed_workqueue(void *data) @@ -316,8 +359,12 @@ static void drm_bo_delayed_workqueue(void *data)  	DRM_DEBUG("Delayed delete Worker\n"); -	drm_bo_delayed_delete(dev);  	mutex_lock(&dev->struct_mutex); +	if (!bm->initialized) { +		mutex_unlock(&dev->struct_mutex); +		return; +	} +	drm_bo_delayed_delete(dev, 0);  	if (bm->initialized && !list_empty(&bm->ddestroy)) {  		schedule_delayed_work(&bm->wq,  				      ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); @@ -452,41 +499,6 @@ int drm_fence_buffer_objects(drm_file_t * priv,  EXPORT_SYMBOL(drm_fence_buffer_objects);  /* - * Call bo->mutex locked. - * Wait until the buffer is idle. - */ - -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, -		       int no_wait) -{ - -	drm_fence_object_t *fence = bo->fence; -	int ret; - -	if (fence) { -		drm_device_t *dev = bo->dev; -		if (drm_fence_object_signaled(fence, bo->fence_type)) { -			drm_fence_usage_deref_unlocked(dev, fence); -			bo->fence = NULL; -			return 0; -		} -		if (no_wait) { -			return -EBUSY; -		} -		ret = -		    drm_fence_object_wait(dev, fence, lazy, ignore_signals, -					  bo->fence_type); -		if (ret) -			return ret; - -		drm_fence_usage_deref_unlocked(dev, fence); -		bo->fence = NULL; - -	} -	return 0; -} - -/*   * bo->mutex locked    */ @@ -1385,8 +1397,6 @@ int drm_buffer_object_create(drm_file_t * priv,  	uint32_t new_flags;  	unsigned long num_pages; -	drm_bo_delayed_delete(dev); -  	if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) {  		DRM_ERROR("Invalid buffer object start.\n");  		return -EINVAL; @@ -1637,6 +1647,7 @@ static int drm_bo_force_list_clean(drm_device_t * dev,  		if (prev != list->prev || next != list->next) {  			mutex_unlock(&entry->mutex); +			drm_bo_usage_deref_locked(dev, entry);  			goto retry;  		}  		if (drm_bo_mm_node(entry, mem_type)) { @@ -1816,6 +1827,11 @@ static int drm_bo_init_mm(drm_device_t * dev,  	return 0;  } +/* + * This is called from lastclose, so we don't need to bother about + * any clients still running when we set the initialized flag to zero. + */ +  int drm_bo_driver_finish(drm_device_t * dev)  {  	drm_buffer_manager_t *bm = &dev->bm; @@ -1827,6 +1843,7 @@ int drm_bo_driver_finish(drm_device_t * dev)  	if (!bm->initialized)  		goto out; +	bm->initialized = 0;  	while (i--) {  		if (bm->has_type[i]) { @@ -1840,14 +1857,23 @@ int drm_bo_driver_finish(drm_device_t * dev)  		}  	}  	mutex_unlock(&dev->struct_mutex); -	drm_bo_delayed_delete(dev); -	mutex_lock(&dev->struct_mutex); -	bm->initialized = 0; -	mutex_unlock(&dev->struct_mutex);  	if (!cancel_delayed_work(&bm->wq)) {  		flush_scheduled_work();  	}  	mutex_lock(&dev->struct_mutex); +	drm_bo_delayed_delete(dev, 1); +	if (list_empty(&bm->ddestroy)) { +		DRM_DEBUG("Delayed destroy list was clean\n"); +	} +	if (list_empty(&bm->lru[0])) { +		DRM_DEBUG("Swap list was clean\n"); +	} +	if (list_empty(&bm->pinned[0])) { +		DRM_DEBUG("NO_MOVE list was clean\n"); +	} +	if (list_empty(&bm->unfenced)) { +		DRM_DEBUG("Unfenced list was clean\n"); +	}        out:  	mutex_unlock(&dev->struct_mutex);  	mutex_unlock(&dev->bm.init_mutex); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index aa382046..f656340e 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -311,7 +311,9 @@ int drm_fence_object_wait(drm_device_t * dev,  			ret = -EBUSY;  		if (ret) {  			if (ret == -EBUSY) { -				DRM_ERROR("Fence timout. GPU lockup.\n"); +				DRM_ERROR("Fence timeout. " +					  "GPU lockup or fence driver was " +					  "taken down.\n");  			}  			return ((ret == -EINTR) ? -EAGAIN : ret);  		} diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index fc8ab761..2182604c 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -124,6 +124,9 @@ int i915_fence_emit_sequence(drm_device_t * dev, uint32_t flags,  			     uint32_t * sequence, uint32_t * native_type)  {  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	if (!dev_priv) +		return -EINVAL; +  	i915_emit_irq(dev);  	*sequence = (uint32_t) dev_priv->counter;  	*native_type = DRM_FENCE_TYPE_EXE; | 
