summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 21:59:42 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 21:59:42 -0400
commit954277863e8206d2ddf6058b8958a34eee22576b (patch)
tree9cbb8f9787cc44df1a9bbad1a4cc5b4fc9f48271 /kernel/gsp_phys_booter.c
parent684dbe2e5c01b7f27e6fe15242b318057454ac5a (diff)
downloadopen-iov-954277863e8206d2ddf6058b8958a34eee22576b.tar.gz
open-iov-954277863e8206d2ddf6058b8958a34eee22576b.zip
gsp-phys: backend session API skeleton (P0, inert)
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 247dcff..255d79e 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -4444,6 +4444,139 @@ static int gsp_phys_rm_probe(void __iomem *bar0)
}
/* ============================================================
+ * Backend session transport API (P0 skeleton, inert)
+ * ============================================================ */
+
+static struct gsp_phys_backend_static_config gsp_phys_backend_static;
+
+int gsp_phys_backend_rpc(u32 function, const void *req, u32 req_len,
+ void **reply, u32 *reply_len, u32 timeout_ms)
+{
+ struct gsp_phys_status_queue sq;
+ struct gsp_phys_rx_record rec;
+ void __iomem *bar0;
+ void *payload = NULL;
+ u32 generation;
+ int ret;
+
+ if (reply)
+ *reply = NULL;
+ if (reply_len)
+ *reply_len = 0;
+
+ /*
+ * Lock-free readiness check so a non-READY session is refused without
+ * taking the real-GSP lock or touching the device. The generation is
+ * captured before the lock and re-checked under it: a stop that bumps
+ * the generation between the two checks is seen below and the forward
+ * is refused instead of racing the release.
+ */
+ if (gsp_phys_backend_state() != GSP_PHYS_BACKEND_READY ||
+ !gsp_phys_gpu_claimed() || !boot_stage.rm_init_done ||
+ boot_stage.rm_unload_submitted) {
+ pr_info("gsp-phys-boot: backend rpc fn%u refused: not ready (state=%d claimed=%u rm_init_done=%u unload_submitted=%u)\n",
+ function, gsp_phys_backend_state(),
+ gsp_phys_gpu_claimed(), boot_stage.rm_init_done,
+ boot_stage.rm_unload_submitted);
+ return -EAGAIN;
+ }
+
+ generation = gsp_phys_backend_generation();
+ bar0 = gsp_phys_gpu_bar0();
+ if (!bar0) {
+ pr_info("gsp-phys-boot: backend rpc fn%u refused: no BAR0\n",
+ function);
+ return -ENODEV;
+ }
+
+ mutex_lock(&gsp_phys_rm_lock);
+ if (gsp_phys_backend_state() != GSP_PHYS_BACKEND_READY ||
+ gsp_phys_backend_generation() != generation ||
+ !boot_stage.rm_init_done || boot_stage.rm_unload_submitted) {
+ u32 gen_now = gsp_phys_backend_generation();
+
+ mutex_unlock(&gsp_phys_rm_lock);
+ pr_info("gsp-phys-boot: backend rpc fn%u refused: session changed while waiting for the GSP lock (generation %u -> %u)\n",
+ function, generation, gen_now);
+ return -EAGAIN;
+ }
+
+ ret = gsp_phys_queue_tx_submit(bar0, function, req, req_len);
+ if (ret) {
+ mutex_unlock(&gsp_phys_rm_lock);
+ pr_err("gsp-phys-boot: backend rpc fn%u submit refused: %d\n",
+ function, ret);
+ return ret;
+ }
+
+ gsp_phys_status_queue_init(&sq);
+ memset(&rec, 0, sizeof(rec));
+ ret = gsp_phys_status_wait(&sq, function, false, 0, timeout_ms, &rec);
+ if (ret) {
+ mutex_unlock(&gsp_phys_rm_lock);
+ pr_err("gsp-phys-boot: backend rpc fn%u no reply within %u ms (%d)\n",
+ function, timeout_ms, ret);
+ return ret;
+ }
+
+ pr_info("gsp-phys-boot: backend rpc fn%u reply: payload=%u B seqNum=%u rpc.seq=%u rpc_result=0x%x private=0x%x checksum=0x%08x\n",
+ function, rec.payload_len, rec.seq_num, rec.rpc_sequence,
+ rec.rpc_result, rec.rpc_result_private, rec.checksum);
+
+ if (rec.rpc_result != 0) {
+ pr_err("gsp-phys-boot: backend rpc fn%u server rpc_result=0x%x (not success)\n",
+ function, rec.rpc_result);
+ ret = -EIO;
+ goto out;
+ }
+
+ if (reply && rec.payload_len) {
+ payload = kmemdup(rec.buf + GSP_PHYS_MSG_ELEMENT_PAYLOAD_OFF,
+ rec.payload_len, GFP_KERNEL);
+ if (!payload) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ if (reply)
+ *reply = payload;
+ if (reply_len)
+ *reply_len = rec.payload_len;
+
+out:
+ gsp_phys_rx_record_free(&rec);
+ mutex_unlock(&gsp_phys_rm_lock);
+ return ret;
+}
+
+int gsp_phys_backend_static_snapshot(struct gsp_phys_backend_static_config *out)
+{
+ u32 generation;
+
+ if (!out)
+ return -EINVAL;
+
+ if (gsp_phys_backend_state() != GSP_PHYS_BACKEND_READY)
+ return -EAGAIN;
+
+ generation = gsp_phys_backend_generation();
+ mutex_lock(&gsp_phys_rm_lock);
+ if (gsp_phys_backend_state() != GSP_PHYS_BACKEND_READY ||
+ gsp_phys_backend_generation() != generation) {
+ mutex_unlock(&gsp_phys_rm_lock);
+ return -EAGAIN;
+ }
+ if (!gsp_phys_backend_static.valid) {
+ mutex_unlock(&gsp_phys_rm_lock);
+ pr_debug("gsp-phys-boot: backend static snapshot: cache not populated yet\n");
+ return -ENODATA;
+ }
+ *out = gsp_phys_backend_static;
+ mutex_unlock(&gsp_phys_rm_lock);
+ return 0;
+}
+
+/* ============================================================
* Host RM client ladder (R1): gsp-phys-rm-call
* ============================================================ */