summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_gpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_gpu.c')
-rw-r--r--kernel/gsp_phys_gpu.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/kernel/gsp_phys_gpu.c b/kernel/gsp_phys_gpu.c
index 88d13f2..22cdc33 100644
--- a/kernel/gsp_phys_gpu.c
+++ b/kernel/gsp_phys_gpu.c
@@ -49,6 +49,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
@@ -1001,3 +1002,129 @@ void gsp_phys_gpu_release(void)
gsp_phys_power_unlock();
}
+
+/*
+ * Backend session state (P0 skeleton, inert until a caller wires it). One
+ * physical GPU, one live claim, refcounted between the module-owned
+ * load-time claim and the guest-facing mdev owner. gsp_phys_session_lock is
+ * the outermost backend lock: it is held for state/refcount/owner changes
+ * only and dropped before gsp_phys_gpu_claim()/_release(), which take
+ * gsp_phys_rm_lock inside. The generation counter is bumped when the session
+ * leaves READY so a forward that captured the previous value can re-check it
+ * under the rm lock and refuse instead of racing the release.
+ */
+static DEFINE_MUTEX(gsp_phys_session_lock);
+
+static struct gsp_phys_backend_session {
+ enum gsp_phys_backend_state state;
+ u32 refcount;
+ u32 generation;
+ bool module_owned;
+} backend = {
+ .state = GSP_PHYS_BACKEND_OFF,
+};
+
+int gsp_phys_backend_state(void)
+{
+ return READ_ONCE(backend.state);
+}
+
+u32 gsp_phys_backend_generation(void)
+{
+ return READ_ONCE(backend.generation);
+}
+
+int gsp_phys_backend_start(void)
+{
+ bool was_claimed;
+ int ret;
+
+ mutex_lock(&gsp_phys_session_lock);
+ if (backend.state != GSP_PHYS_BACKEND_OFF) {
+ backend.refcount++;
+ pr_info("gsp-phys: backend start: session already up (state=%d, refcount=%u)\n",
+ backend.state, backend.refcount);
+ mutex_unlock(&gsp_phys_session_lock);
+ return 0;
+ }
+
+ /*
+ * A live claim can only pre-exist from the load-time module-owned
+ * path; join it without claiming again and keep the module as the
+ * owner so a later stop() drops only the reference and leaves the
+ * release to rmmod.
+ */
+ was_claimed = gsp_phys_gpu_claimed();
+ backend.refcount = 1;
+ backend.module_owned = was_claimed;
+ WRITE_ONCE(backend.state, GSP_PHYS_BACKEND_CLAIMING);
+ mutex_unlock(&gsp_phys_session_lock);
+
+ if (!was_claimed) {
+ pr_info("gsp-phys: backend start: claiming the physical GPU\n");
+ ret = gsp_phys_gpu_claim();
+ if (ret) {
+ mutex_lock(&gsp_phys_session_lock);
+ backend.refcount = 0;
+ backend.module_owned = false;
+ WRITE_ONCE(backend.state, GSP_PHYS_BACKEND_OFF);
+ mutex_unlock(&gsp_phys_session_lock);
+ pr_err("gsp-phys: backend start: claim failed: %d (backend OFF)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /*
+ * gsp_phys_gpu_claim() runs the stage-3d boot inline when the boot
+ * parameters are set, so READY here means the session is owned and
+ * live; gsp_phys_backend_rpc() additionally gates on init-done.
+ */
+ mutex_lock(&gsp_phys_session_lock);
+ WRITE_ONCE(backend.state, GSP_PHYS_BACKEND_READY);
+ pr_info("gsp-phys: backend start: READY (module-owned=%u)\n",
+ backend.module_owned);
+ mutex_unlock(&gsp_phys_session_lock);
+ return 0;
+}
+
+void gsp_phys_backend_stop(void)
+{
+ u32 generation;
+
+ mutex_lock(&gsp_phys_session_lock);
+ if (backend.state == GSP_PHYS_BACKEND_OFF) {
+ mutex_unlock(&gsp_phys_session_lock);
+ pr_info("gsp-phys: backend stop: already OFF\n");
+ return;
+ }
+ if (backend.refcount)
+ backend.refcount--;
+ if (backend.refcount) {
+ pr_info("gsp-phys: backend stop: refcount=%u, session stays up\n",
+ backend.refcount);
+ mutex_unlock(&gsp_phys_session_lock);
+ return;
+ }
+ if (backend.module_owned ||
+ backend.state != GSP_PHYS_BACKEND_READY) {
+ pr_info("gsp-phys: backend stop: state=%d owner=%s, no release\n",
+ backend.state,
+ backend.module_owned ? "module" : "mdev");
+ mutex_unlock(&gsp_phys_session_lock);
+ return;
+ }
+
+ WRITE_ONCE(backend.state, GSP_PHYS_BACKEND_STOPPING);
+ generation = ++backend.generation;
+ mutex_unlock(&gsp_phys_session_lock);
+ pr_info("gsp-phys: backend stop: STOPPING (generation=%u)\n", generation);
+
+ gsp_phys_gpu_release();
+
+ mutex_lock(&gsp_phys_session_lock);
+ backend.module_owned = false;
+ WRITE_ONCE(backend.state, GSP_PHYS_BACKEND_OFF);
+ mutex_unlock(&gsp_phys_session_lock);
+ pr_info("gsp-phys: backend stop: OFF\n");
+}