diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 6da812d..146291c 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -26747,6 +26747,12 @@ static bool svc_ce_declared_userd(struct nv_vgpu_device *vgpu, return true; } +/* + * CONT.438: bounded witness for FB-sweep candidates skipped because another + * live channel already owns their page. + */ +static u32 svc_foreign_userd_skip_log; + static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch, u64 ring_pa, int ring_ap, u32 *put, u32 *get, int rrc) { @@ -27214,11 +27220,46 @@ ce_fb_scan: bool wtry = false, wused = false; u32 woff = (u32)(ch->gpfifo_va & (SEMA_PAGE_SIZE - 1)); + /* + * CONT.438 (patch A): a candidate on a 4K page that another + * live channel already owns is not this channel's USERD. The + * live X/GLX channel 0x1000013 re-adopted the RC watchdog + * channel 0x31415900's block at fb 0x8f0000 every pass (its + * own USERD is client-allocated, so the wire userdMem is + * zero); the foreign pair then never matched the client's + * progress. Snapshot the other channels' USERD pages once per + * sweep and refuse their pages as candidates. Failing closed + * here is deliberate: a foreign block must not become the + * write target for GP_GET. + */ + u64 foreign_userd_pages[SVC_MAX_CHANNELS]; + unsigned long chflags; + u32 foreign_userd_n = 0; + u32 oi; + + spin_lock_irqsave(&svc.chan_lock, chflags); + for (oi = 0; + oi < SVC_MAX_CHANNELS && + foreign_userd_n < SVC_MAX_CHANNELS; oi++) { + struct svc_channel *other = &svc.chan[oi]; + + if (!other->valid || other->vgpu != vgpu || + !other->userd_pa) + continue; + if (other->h_object == ch->h_object && + other->vgpu == ch->vgpu) + continue; + foreign_userd_pages[foreign_userd_n++] = + other->userd_pa & ~0xfffULL; + } + spin_unlock_irqrestore(&svc.chan_lock, chflags); + ch->fb_userd_scan_at = jiffies; ch->fb_userd_scan_n++; ch->userd_scans++; ring_sweep_ran = true; - lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x20000000ULL); + lim = min_t(u64, svc_fb_shadow_size(vgpu), + 0x20000000ULL); if (base && lim) { for (off = 0; off + 0xa0 <= lim; off += 0x200) { u32 hp, hg; @@ -27230,6 +27271,8 @@ ce_fb_scan: int rck = -1; u64 rkva = 0; u32 rklen = 0; + u64 page; + bool foreign = false; memcpy(&hp, base + off + SVC_USERD_GP_PUT, 4); memcpy(&hg, base + off + SVC_USERD_GP_GET, 4); @@ -27246,6 +27289,27 @@ ce_fb_scan: ch->gpfifo_entries <= 1024))) continue; gate_n++; + /* + * CONT.438: the page-ownership gate. A block + * on another live channel's USERD page cannot + * be this channel's control block. + */ + page = off & ~0xfffULL; + for (oi = 0; oi < foreign_userd_n; oi++) { + if (foreign_userd_pages[oi] == page) { + foreign = true; + break; + } + } + if (foreign) { + if (svc_foreign_userd_skip_log < 16) { + svc_foreign_userd_skip_log++; + pr_info("sema-chan: userdp h=0x%x skip fb 0x%llx (page owned by another live channel; put=%u get=%u)\n", + ch->h_object, off, hp, + hg); + } + continue; + } /* Validate: every claimed entry decodes to a * pushbuffer VA in the ring's window. */ for (k = 0; k < hp && k < 64; k++) { |
