diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index e336277..d476188 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -2152,6 +2152,7 @@ static void svc_counter_release_apply(struct nv_vgpu_device *vgpu, u32 h, return; svc.releases_applied++; svc.counter_rel_applied++; + svc.gr_rel_applied++; svc.post_hint_until = jiffies + 10 * HZ; if (svc.counter_rel_dbg < 32) { svc.counter_rel_dbg++; @@ -2182,7 +2183,14 @@ static void svc_counter_autoreg(struct svc_channel *ch, int n_gr) if (ch->gr_index >= n_gr) return; va = 0x20400fec0ULL + (u64)(n_gr - 1 - ch->gr_index) * 0x10ULL; - if (svc_pin_lookup_any(va, &pa, &ap) || ap != SVC_APERTURE_SYS) + /* + * Only the authoritative injected-pin table may register a counter + * slot: the self-discovered map can hold a stale translation for this + * VA (content-scanned page), and a write to that page never reaches + * the client. If no injected pin exists yet, leave counter_pa zero so + * a later pass (once the pin lands) registers it. + */ + if (svc_ipin_lookup(va, &pa, &ap) || ap != SVC_APERTURE_SYS) return; ch->counter_pa = pa & ~0x3ULL; pr_info("sema-chan: counter auto h=0x%x rank=%u pa=0x%llx (slot va=0x%llx)\n", @@ -2205,13 +2213,19 @@ static void svc_counter_learn(u32 h, u64 sem_va) if (!h || sem_va < 0x204000000ULL || sem_va >= 0x204100000ULL) return; - if (svc_pin_lookup_any(sem_va, &pa, &ap) || ap != SVC_APERTURE_SYS) + /* + * Authoritative injected pins only (see svc_counter_autoreg): a stale + * self-discovered entry would make every release land on a page the + * client never polls. Re-learn when the injected PA differs, so a pin + * that lands after an earlier stale registration still wins. + */ + if (svc_ipin_lookup(sem_va, &pa, &ap) || ap != SVC_APERTURE_SYS) return; spin_lock_irqsave(&svc.chan_lock, flags); for (i = 0; i < SVC_MAX_CHANNELS; i++) { if (svc.chan[i].valid && svc.chan[i].h_object == h) { - if (!svc.chan[i].counter_pa) { + if (svc.chan[i].counter_pa != (pa & ~0x3ULL)) { svc.chan[i].counter_pa = pa & ~0x3ULL; pr_info("sema-chan: counter learned h=0x%x pa=0x%llx (from release va=0x%llx)\n", h, pa & ~0x3ULL, sem_va); @@ -2636,19 +2650,24 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, cur += st.sem_payload; else cur = st.sem_payload; - if (!svc_sem_write(vgpu, sem_va, cur)) { + /* + * GR completion counters live in a + * client semaphore page whose generic + * translation can be a stale + * content-scanned page; writing there + * corrupts an unrelated page and never + * reaches the client. Those releases go + * through the injected-pin-backed slot + * (svc_counter_learn / + * svc_counter_release_apply) below. + */ + if (ch_eng == 0 && + sem_va >= 0x204000000ULL && + sem_va < 0x204100000ULL) { + /* handled by the exact-slot path */ + } else if (!svc_sem_write(vgpu, sem_va, cur)) { svc.releases_applied++; svc.post_hint_until = jiffies + 10 * HZ; - if (ch_eng == 0 && - sem_va >= 0x204000000ULL && - sem_va < 0x204100000ULL) { - svc.gr_rel_applied++; - if (svc.gr_rel_log < 48) { - svc.gr_rel_log++; - pr_info("sema-chan: gr release h=0x%x va=0x%llx pay=%u\n", - ch_h, sem_va, cur); - } - } } } |
