Commit d9948a10 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Remove second level open-coded rcu work



We currently use a worker queued from an rcu callback to determine when
a how grace period has elapsed while we remained idle. We use this idle
delay to infer that we will be idle for a while and this is a suitable
point at which we can trim our global memory caches.

Since we wrote that, this mechanism now exists as rcu_work, and having
converted the idle shrinkers over to using that, we can remove our own
variant.

v2: Say goodbye to gt.epoch as well.
v3: Remove the misplaced and redundant comment before parking globals

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190228102035.5857-3-chris@chris-wilson.co.uk
parent 13f1bfd3
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -2655,8 +2655,7 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused)
	seq_printf(m, "Runtime power status: %s\n",
		   enableddisabled(!dev_priv->power_domains.wakeref));

	seq_printf(m, "GPU idle: %s (epoch %u)\n",
		   yesno(!dev_priv->gt.awake), dev_priv->gt.epoch);
	seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->gt.awake));
	seq_printf(m, "IRQs disabled: %s\n",
		   yesno(!intel_irqs_enabled(dev_priv)));
#ifdef CONFIG_PM
@@ -3092,8 +3091,7 @@ static int i915_engine_info(struct seq_file *m, void *unused)

	wakeref = intel_runtime_pm_get(dev_priv);

	seq_printf(m, "GT awake? %s (epoch %u)\n",
		   yesno(dev_priv->gt.awake), dev_priv->gt.epoch);
	seq_printf(m, "GT awake? %s\n", yesno(dev_priv->gt.awake));
	seq_printf(m, "Global active requests: %d\n",
		   dev_priv->gt.active_requests);
	seq_printf(m, "CS timestamp frequency: %u kHz\n",
+0 −6
Original line number Diff line number Diff line
@@ -2005,12 +2005,6 @@ struct drm_i915_private {
		 */
		intel_wakeref_t awake;

		/**
		 * The number of times we have woken up.
		 */
		unsigned int epoch;
#define I915_EPOCH_INVALID 0

		/**
		 * We leave the user IRQ off as much as possible,
		 * but this means that requests will finish and never
+4 −84
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
	spin_unlock(&dev_priv->mm.object_stat_lock);
}

static u32 __i915_gem_park(struct drm_i915_private *i915)
static void __i915_gem_park(struct drm_i915_private *i915)
{
	intel_wakeref_t wakeref;

@@ -112,9 +112,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
	GEM_BUG_ON(!list_empty(&i915->gt.active_rings));

	if (!i915->gt.awake)
		return I915_EPOCH_INVALID;

	GEM_BUG_ON(i915->gt.epoch == I915_EPOCH_INVALID);
		return;

	/*
	 * Be paranoid and flush a concurrent interrupt to make sure
@@ -143,7 +141,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)

	intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, wakeref);

	return i915->gt.epoch;
	i915_globals_park();
}

void i915_gem_park(struct drm_i915_private *i915)
@@ -185,9 +183,6 @@ void i915_gem_unpark(struct drm_i915_private *i915)
	i915->gt.awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
	GEM_BUG_ON(!i915->gt.awake);

	if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */
		i915->gt.epoch = 1;

	i915_globals_unpark();

	intel_enable_gt_powersave(i915);
@@ -2877,62 +2872,6 @@ i915_gem_retire_work_handler(struct work_struct *work)
				   round_jiffies_up_relative(HZ));
}

static void shrink_caches(struct drm_i915_private *i915)
{
	/*
	 * kmem_cache_shrink() discards empty slabs and reorders partially
	 * filled slabs to prioritise allocating from the mostly full slabs,
	 * with the aim of reducing fragmentation.
	 */
	i915_globals_park();
}

struct sleep_rcu_work {
	union {
		struct rcu_head rcu;
		struct work_struct work;
	};
	struct drm_i915_private *i915;
	unsigned int epoch;
};

static inline bool
same_epoch(struct drm_i915_private *i915, unsigned int epoch)
{
	/*
	 * There is a small chance that the epoch wrapped since we started
	 * sleeping. If we assume that epoch is at least a u32, then it will
	 * take at least 2^32 * 100ms for it to wrap, or about 326 years.
	 */
	return epoch == READ_ONCE(i915->gt.epoch);
}

static void __sleep_work(struct work_struct *work)
{
	struct sleep_rcu_work *s = container_of(work, typeof(*s), work);
	struct drm_i915_private *i915 = s->i915;
	unsigned int epoch = s->epoch;

	kfree(s);
	if (same_epoch(i915, epoch))
		shrink_caches(i915);
}

static void __sleep_rcu(struct rcu_head *rcu)
{
	struct sleep_rcu_work *s = container_of(rcu, typeof(*s), rcu);
	struct drm_i915_private *i915 = s->i915;

	destroy_rcu_head(&s->rcu);

	if (same_epoch(i915, s->epoch)) {
		INIT_WORK(&s->work, __sleep_work);
		queue_work(i915->wq, &s->work);
	} else {
		kfree(s);
	}
}

static inline bool
new_requests_since_last_retire(const struct drm_i915_private *i915)
{
@@ -2961,7 +2900,6 @@ i915_gem_idle_work_handler(struct work_struct *work)
{
	struct drm_i915_private *dev_priv =
		container_of(work, typeof(*dev_priv), gt.idle_work.work);
	unsigned int epoch = I915_EPOCH_INVALID;
	bool rearm_hangcheck;

	if (!READ_ONCE(dev_priv->gt.awake))
@@ -3016,7 +2954,7 @@ i915_gem_idle_work_handler(struct work_struct *work)
	if (new_requests_since_last_retire(dev_priv))
		goto out_unlock;

	epoch = __i915_gem_park(dev_priv);
	__i915_gem_park(dev_priv);

	assert_kernel_context_is_current(dev_priv);

@@ -3029,24 +2967,6 @@ out_rearm:
		GEM_BUG_ON(!dev_priv->gt.awake);
		i915_queue_hangcheck(dev_priv);
	}

	/*
	 * When we are idle, it is an opportune time to reap our caches.
	 * However, we have many objects that utilise RCU and the ordered
	 * i915->wq that this work is executing on. To try and flush any
	 * pending frees now we are idle, we first wait for an RCU grace
	 * period, and then queue a task (that will run last on the wq) to
	 * shrink and re-optimize the caches.
	 */
	if (same_epoch(dev_priv, epoch)) {
		struct sleep_rcu_work *s = kmalloc(sizeof(*s), GFP_KERNEL);
		if (s) {
			init_rcu_head(&s->rcu);
			s->i915 = dev_priv;
			s->epoch = epoch;
			call_rcu(&s->rcu, __sleep_rcu);
		}
	}
}

void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)