xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/i915/i915_globals.c (revision 9e5fbd4f7f25d0a357b482f4591196ee62d90ed5)
1*9e5fbd4fSriastradh /*	$NetBSD: i915_globals.c,v 1.3 2021/12/19 11:49:11 riastradh Exp $	*/
24e390cabSriastradh 
34e390cabSriastradh /*
44e390cabSriastradh  * SPDX-License-Identifier: MIT
54e390cabSriastradh  *
64e390cabSriastradh  * Copyright © 2019 Intel Corporation
74e390cabSriastradh  */
84e390cabSriastradh 
94e390cabSriastradh #include <sys/cdefs.h>
10*9e5fbd4fSriastradh __KERNEL_RCSID(0, "$NetBSD: i915_globals.c,v 1.3 2021/12/19 11:49:11 riastradh Exp $");
114e390cabSriastradh 
124e390cabSriastradh #include <linux/slab.h>
134e390cabSriastradh #include <linux/workqueue.h>
144e390cabSriastradh 
154e390cabSriastradh #include "i915_active.h"
164e390cabSriastradh #include "gem/i915_gem_context.h"
174e390cabSriastradh #include "gem/i915_gem_object.h"
184e390cabSriastradh #include "i915_globals.h"
194e390cabSriastradh #include "i915_request.h"
204e390cabSriastradh #include "i915_scheduler.h"
214e390cabSriastradh #include "i915_vma.h"
224e390cabSriastradh 
23*9e5fbd4fSriastradh #include <linux/nbsd-namespace.h>
24*9e5fbd4fSriastradh 
254e390cabSriastradh static LIST_HEAD(globals);
264e390cabSriastradh 
274e390cabSriastradh static atomic_t active;
284e390cabSriastradh static atomic_t epoch;
294e390cabSriastradh static struct park_work {
304e390cabSriastradh 	struct delayed_work work;
314e390cabSriastradh 	struct rcu_head rcu;
324e390cabSriastradh 	unsigned long flags;
334e390cabSriastradh #define PENDING 0
344e390cabSriastradh 	int epoch;
354e390cabSriastradh } park;
364e390cabSriastradh 
i915_globals_shrink(void)374e390cabSriastradh static void i915_globals_shrink(void)
384e390cabSriastradh {
394e390cabSriastradh 	struct i915_global *global;
404e390cabSriastradh 
414e390cabSriastradh 	/*
424e390cabSriastradh 	 * kmem_cache_shrink() discards empty slabs and reorders partially
434e390cabSriastradh 	 * filled slabs to prioritise allocating from the mostly full slabs,
444e390cabSriastradh 	 * with the aim of reducing fragmentation.
454e390cabSriastradh 	 */
464e390cabSriastradh 	list_for_each_entry(global, &globals, link)
474e390cabSriastradh 		global->shrink();
484e390cabSriastradh }
494e390cabSriastradh 
__i915_globals_grace(struct rcu_head * rcu)504e390cabSriastradh static void __i915_globals_grace(struct rcu_head *rcu)
514e390cabSriastradh {
524e390cabSriastradh 	/* Ratelimit parking as shrinking is quite slow */
534e390cabSriastradh 	schedule_delayed_work(&park.work, round_jiffies_up_relative(2 * HZ));
544e390cabSriastradh }
554e390cabSriastradh 
__i915_globals_queue_rcu(void)564e390cabSriastradh static void __i915_globals_queue_rcu(void)
574e390cabSriastradh {
584e390cabSriastradh 	park.epoch = atomic_inc_return(&epoch);
594e390cabSriastradh 	if (!atomic_read(&active)) {
604e390cabSriastradh 		init_rcu_head(&park.rcu);
614e390cabSriastradh 		call_rcu(&park.rcu, __i915_globals_grace);
624e390cabSriastradh 	}
634e390cabSriastradh }
644e390cabSriastradh 
__i915_globals_park(struct work_struct * work)654e390cabSriastradh static void __i915_globals_park(struct work_struct *work)
664e390cabSriastradh {
674e390cabSriastradh 	destroy_rcu_head(&park.rcu);
684e390cabSriastradh 
694e390cabSriastradh 	/* Confirm nothing woke up in the last grace period */
704e390cabSriastradh 	if (park.epoch != atomic_read(&epoch)) {
714e390cabSriastradh 		__i915_globals_queue_rcu();
724e390cabSriastradh 		return;
734e390cabSriastradh 	}
744e390cabSriastradh 
754e390cabSriastradh 	clear_bit(PENDING, &park.flags);
764e390cabSriastradh 	i915_globals_shrink();
774e390cabSriastradh }
784e390cabSriastradh 
i915_global_register(struct i915_global * global)794e390cabSriastradh void __init i915_global_register(struct i915_global *global)
804e390cabSriastradh {
814e390cabSriastradh 	GEM_BUG_ON(!global->shrink);
824e390cabSriastradh 	GEM_BUG_ON(!global->exit);
834e390cabSriastradh 
844e390cabSriastradh 	list_add_tail(&global->link, &globals);
854e390cabSriastradh }
864e390cabSriastradh 
__i915_globals_cleanup(void)874e390cabSriastradh static void __i915_globals_cleanup(void)
884e390cabSriastradh {
894e390cabSriastradh 	struct i915_global *global, *next;
904e390cabSriastradh 
914e390cabSriastradh 	list_for_each_entry_safe_reverse(global, next, &globals, link)
924e390cabSriastradh 		global->exit();
934e390cabSriastradh }
944e390cabSriastradh 
954e390cabSriastradh static __initconst int (* const initfn[])(void) = {
964e390cabSriastradh 	i915_global_active_init,
974e390cabSriastradh 	i915_global_buddy_init,
984e390cabSriastradh 	i915_global_context_init,
994e390cabSriastradh 	i915_global_gem_context_init,
1004e390cabSriastradh 	i915_global_objects_init,
1014e390cabSriastradh 	i915_global_request_init,
1024e390cabSriastradh 	i915_global_scheduler_init,
1034e390cabSriastradh 	i915_global_vma_init,
1044e390cabSriastradh };
1054e390cabSriastradh 
i915_globals_init(void)1064e390cabSriastradh int __init i915_globals_init(void)
1074e390cabSriastradh {
1084e390cabSriastradh 	int i;
1094e390cabSriastradh 
1104e390cabSriastradh 	for (i = 0; i < ARRAY_SIZE(initfn); i++) {
1114e390cabSriastradh 		int err;
1124e390cabSriastradh 
1134e390cabSriastradh 		err = initfn[i]();
1144e390cabSriastradh 		if (err) {
1154e390cabSriastradh 			__i915_globals_cleanup();
1164e390cabSriastradh 			return err;
1174e390cabSriastradh 		}
1184e390cabSriastradh 	}
1194e390cabSriastradh 
1204e390cabSriastradh 	INIT_DELAYED_WORK(&park.work, __i915_globals_park);
1214e390cabSriastradh 	return 0;
1224e390cabSriastradh }
1234e390cabSriastradh 
i915_globals_park(void)1244e390cabSriastradh void i915_globals_park(void)
1254e390cabSriastradh {
1264e390cabSriastradh 	/*
1274e390cabSriastradh 	 * Defer shrinking the global slab caches (and other work) until
1284e390cabSriastradh 	 * after a RCU grace period has completed with no activity. This
1294e390cabSriastradh 	 * is to try and reduce the latency impact on the consumers caused
1304e390cabSriastradh 	 * by us shrinking the caches the same time as they are trying to
1314e390cabSriastradh 	 * allocate, with the assumption being that if we idle long enough
1324e390cabSriastradh 	 * for an RCU grace period to elapse since the last use, it is likely
1334e390cabSriastradh 	 * to be longer until we need the caches again.
1344e390cabSriastradh 	 */
1354e390cabSriastradh 	if (!atomic_dec_and_test(&active))
1364e390cabSriastradh 		return;
1374e390cabSriastradh 
1384e390cabSriastradh 	/* Queue cleanup after the next RCU grace period has freed slabs */
1394e390cabSriastradh 	if (!test_and_set_bit(PENDING, &park.flags))
1404e390cabSriastradh 		__i915_globals_queue_rcu();
1414e390cabSriastradh }
1424e390cabSriastradh 
i915_globals_unpark(void)1434e390cabSriastradh void i915_globals_unpark(void)
1444e390cabSriastradh {
1454e390cabSriastradh 	atomic_inc(&epoch);
1464e390cabSriastradh 	atomic_inc(&active);
1474e390cabSriastradh }
1484e390cabSriastradh 
__i915_globals_flush(void)1494e390cabSriastradh static void __exit __i915_globals_flush(void)
1504e390cabSriastradh {
1514e390cabSriastradh 	atomic_inc(&active); /* skip shrinking */
1524e390cabSriastradh 
1534e390cabSriastradh 	rcu_barrier(); /* wait for the work to be queued */
1544e390cabSriastradh 	flush_delayed_work(&park.work);
1554e390cabSriastradh 
1564e390cabSriastradh 	atomic_dec(&active);
1574e390cabSriastradh }
1584e390cabSriastradh 
i915_globals_exit(void)1594e390cabSriastradh void __exit i915_globals_exit(void)
1604e390cabSriastradh {
1614e390cabSriastradh 	GEM_BUG_ON(atomic_read(&active));
1624e390cabSriastradh 
1634e390cabSriastradh 	__i915_globals_flush();
1644e390cabSriastradh 	__i915_globals_cleanup();
1654e390cabSriastradh 
1664e390cabSriastradh 	/* And ensure that our DESTROY_BY_RCU slabs are truly destroyed */
1674e390cabSriastradh 	rcu_barrier();
1684e390cabSriastradh }
169