summaryrefslogtreecommitdiffstats
path: root/kernel/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/main.c')
-rw-r--r--kernel/main.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/kernel/main.c b/kernel/main.c
index d821762..dd11d12 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -2752,6 +2752,10 @@ MODULE_PARM_DESC(sema_copy_dst2, "Second destination window for sema_copy_dst (d
* the release the client synchronizes on; the translation usually lands within
* a service pass.
*/
+module_param_named(gsp_phys_gr_peek, gsp_phys_gr_peek, uint, 0644);
+MODULE_PARM_DESC(gsp_phys_gr_peek,
+ "Peek the ring slots past GP_PUT at each GR launch decision (diagnostic, default 0)");
+
module_param_named(sema_ce_grace_ms, gsp_sema_ce_grace_ms, uint, 0644);
MODULE_PARM_DESC(sema_ce_grace_ms, "CE pending-entry grace window in ms (default 25000)");
@@ -2872,6 +2876,14 @@ MODULE_PARM_DESC(sema_wait_hold_ms, "bounded acquire-wait hold before fail-open,
module_param_named(sema_push_raw, gsp_sema_push_raw, uint, 0644);
MODULE_PARM_DESC(sema_push_raw, "r481 diagnostic: dump the decoded method stream of the first N large GR pushes (default 0 off)");
MODULE_PARM_DESC(sema_copy_dst_pin_guard, "hold device-dst copies without a pin-resolved translation (default 1)");
+/*
+ * r609: after a device-dst guard window expires WITHOUT a pin, skip the
+ * window for further first-write device-dst pages of the same channel for
+ * this long (ms) - the r606 held-chain serialization fix. 0 restores the
+ * per-page windows (pre-r609).
+ */
+module_param_named(sema_copy_dst_age_ms, gsp_sema_copy_dst_age_ms, uint, 0644);
+MODULE_PARM_DESC(sema_copy_dst_age_ms, "device-dst guard burst-ageing window after an un-pinned release, ms (r609, default 3000; 0 off)");
/*
* r384 (guest boot-corruption lottery): fill-destination guards. A large
@@ -3881,5 +3893,143 @@ static const struct kernel_param_ops nv_vgpu_rmpost_ops = {
module_param_cb(rmpost, &nv_vgpu_rmpost_ops, NULL, 0200);
MODULE_PARM_DESC(rmpost, "Post a GSP-RM event to the guest by event index (debug)");
+/*
+ * Debug: poke a channel's error notifier with an engine-exception shape and
+ * post its channel event (the relayed-fault delivery edge, manually):
+ * echo 0x5c000019 > .../parameters/grfaultpoke
+ * echo 0 > .../parameters/grfaultpoke (every valid channel)
+ * Experiment: a refused/degenerate GR launch ends its client's
+ * cudaDeviceSynchronize spin if a synthetic engine error completes the wait
+ * (r616; see gsp_sema_channel_fault_poke).
+ */
+struct nv_vgpu_faultpoke_req {
+ u32 h_object;
+ int rc;
+ struct completion done;
+};
+
+static int nv_vgpu_faultpoke_thread(void *arg)
+{
+ struct nv_vgpu_faultpoke_req *req = arg;
+ struct nv_vgpu_device *vgpu;
+
+ mutex_lock(&nv_vgpu_driver.lock);
+ list_for_each_entry(vgpu, &nv_vgpu_driver.devices, list) {
+ if (atomic_read(&vgpu->vfio_dev_open_count) <= 0)
+ continue;
+ req->rc = gsp_sema_channel_fault_poke(vgpu, req->h_object);
+ pr_info("vgsp: grfaultpoke h=0x%x -> %d\n",
+ req->h_object, req->rc);
+ }
+ mutex_unlock(&nv_vgpu_driver.lock);
+
+ complete(&req->done);
+ return 0;
+}
+
+static int nv_vgpu_faultpoke_set(const char *val, const struct kernel_param *kp)
+{
+ static struct nv_vgpu_faultpoke_req req;
+ struct task_struct *task;
+
+ memset(&req, 0, sizeof(req));
+ req.rc = -ENODEV;
+ if (kstrtou32(val, 0, &req.h_object))
+ return -EINVAL;
+
+ init_completion(&req.done);
+ task = kthread_run(nv_vgpu_faultpoke_thread, &req, "vgpu-faultpoke");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ wait_for_completion(&req.done);
+ return 0;
+}
+
+static const struct kernel_param_ops nv_vgpu_faultpoke_ops = {
+ .set = nv_vgpu_faultpoke_set,
+};
+
+module_param_cb(grfaultpoke, &nv_vgpu_faultpoke_ops, NULL, 0200);
+MODULE_PARM_DESC(grfaultpoke, "Write a channel error notifier + post its event (r616 experiment)");
+
+/*
+ * Debug r623: deliver a synthetic OS_ERROR_LOG (0x1006) engine-fault report
+ * to the guest's RM queue:
+ * echo 1 > .../parameters/oserrlog
+ * echo 0x1,0,0 > .../parameters/oserrlog (exceptType,runlistId,chid)
+ * Experiment: after a synth-fault, the next client sticks pre-submission; if
+ * the guest's fault handling completes only when the 0x1006 report arrives,
+ * this record is the missing recovery half.
+ */
+struct nv_vgpu_oserrlog_req {
+ u32 except_type, runlist_id, chid;
+ int rc;
+ struct completion done;
+};
+
+static int nv_vgpu_oserrlog_thread(void *arg)
+{
+ struct nv_vgpu_oserrlog_req *req = arg;
+ struct nv_vgpu_device *vgpu;
+
+ mutex_lock(&nv_vgpu_driver.lock);
+ list_for_each_entry(vgpu, &nv_vgpu_driver.devices, list) {
+ if (atomic_read(&vgpu->vfio_dev_open_count) <= 0)
+ continue;
+ req->rc = gsp_rm_send_os_error_log(vgpu, req->except_type,
+ req->runlist_id, req->chid,
+ "GR");
+ pr_info("vgsp: oserrlog except=0x%x rl=%u chid=%u -> %d\n",
+ req->except_type, req->runlist_id, req->chid, req->rc);
+ }
+ mutex_unlock(&nv_vgpu_driver.lock);
+
+ complete(&req->done);
+ return 0;
+}
+
+static int nv_vgpu_oserrlog_set(const char *val, const struct kernel_param *kp)
+{
+ static struct nv_vgpu_oserrlog_req req;
+ struct task_struct *task;
+ char buf[64];
+ char *c1, *c2;
+
+ memset(&req, 0, sizeof(req));
+ req.rc = -ENODEV;
+ strscpy(buf, val, sizeof(buf));
+ req.except_type = 1; /* generic engine exception, as the synth-fault */
+ {
+ c1 = strchr(buf, ',');
+ if (c1) {
+ *c1++ = '\0';
+ c2 = strchr(c1, ',');
+ if (c2) {
+ *c2++ = '\0';
+ if (kstrtou32(c2, 0, &req.chid))
+ return -EINVAL;
+ }
+ if (kstrtou32(c1, 0, &req.runlist_id))
+ return -EINVAL;
+ }
+ if (kstrtou32(buf, 0, &req.except_type))
+ return -EINVAL;
+ }
+
+ init_completion(&req.done);
+ task = kthread_run(nv_vgpu_oserrlog_thread, &req, "vgpu-oserrlog");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ wait_for_completion(&req.done);
+ return 0;
+}
+
+static const struct kernel_param_ops nv_vgpu_oserrlog_ops = {
+ .set = nv_vgpu_oserrlog_set,
+};
+
+module_param_cb(oserrlog, &nv_vgpu_oserrlog_ops, NULL, 0200);
+MODULE_PARM_DESC(oserrlog, "Send a synthetic OS_ERROR_LOG (0x1006) RM record to the guest (r623 experiment)");
+
module_init(nv_vgpu_init);
module_exit(nv_vgpu_exit);