summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
-rw-r--r--kernel/gsp_rm_emulation.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 764ef05..cd9cbf2 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -571,27 +571,39 @@ static int gsp_rm_send_flags(struct gsp_emu_context *ctx, u32 function,
u32 used, space, rxoff = 0;
u8 shdr[32];
- if (gsp_rm_read_buf(ctx, rm->stat_off, shdr,
- sizeof(shdr)))
+ /*
+ * r332 SWAP_RX cursor fix: the guest's consumption
+ * cursor for the STATUS queue lives in the COMMAND
+ * queue's RX header, not in the status queue's own
+ * rxHdrOff. Under MSGQ_FLAGS_SWAP_RX (both sides set
+ * it: flags=1 in both headers) the driver's
+ * msgqRxMarkConsumed writes its status readPtr to
+ * pOurRxHdr->readPtr, and the driver's pOurRxHdr is
+ * the COMMAND-queue buffer's RX header (msgq.c
+ * msgqRxLink swap branch: pReadOutgoing =
+ * &pOurRxHdr->readPtr with pOurRxHdr from
+ * msgqTxCreate's pBackingStore = pCommandQueue). The
+ * status queue's own +rxHdrOff is the mirror we
+ * publish: OUR command-queue read position
+ * (written below after every consumed command
+ * record). Reading that mirror here made the
+ * free-space math track our own writes: the ring was
+ * declared "full" with the guest mid-drain, replies
+ * were written into it anyway, unread records were
+ * overwritten, and the guest RM read a newer record
+ * ("Bad sequence number. Expected N got N+63") - the
+ * first-client cudaMalloc then fails with "device
+ * busy or unavailable" (the boot lottery) and every
+ * later RPC fails until a fresh boot.
+ */
+ if (gsp_rm_read_buf(ctx, rm->cmd_off, shdr, sizeof(shdr)))
break;
memcpy(&rxoff, shdr + 24, 4);
if (!rxoff || rxoff >= 0x1000)
break;
- if (gsp_rm_read_buf(ctx, rm->stat_off + rxoff,
- &peer_read, 4) ||
+ if (gsp_rm_read_buf(ctx, rm->cmd_off + rxoff, &peer_read, 4) ||
peer_read >= rm->stat_msgcount)
break; /* no usable cursor: blind write */
- /*
- * fail4: only a cursor the guest is actually BEHIND
- * (peer <= our writePtr) is a consumption cursor.
- * The observed value at stat+rxHdrOff under this
- * queue's flags tracks writePtr+1 (a mirror), and
- * gating on it silenced every wake-up event and
- * wedged the clients. A mirror (peer > write) falls
- * back to the historical blind write.
- */
- if (peer_read > rm->stat_write)
- break;
have_peer = true;
used = (rm->stat_write + rm->stat_msgcount -
peer_read) % rm->stat_msgcount;