diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_emulation.c | 41 | ||||
| -rw-r--r-- | kernel/gsp_emulation.h | 14 | ||||
| -rw-r--r-- | kernel/gsp_rm_emulation.c | 134 | ||||
| -rw-r--r-- | kernel/gsp_rm_emulation.h | 1 | ||||
| -rw-r--r-- | kernel/gsp_rm_tu104.h | 21 |
5 files changed, 188 insertions, 23 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c index c8f8041..94af0d2 100644 --- a/kernel/gsp_emulation.c +++ b/kernel/gsp_emulation.c @@ -179,6 +179,39 @@ static void gsp_emu_poll_boot(struct gsp_emu_context *ctx) u32 sec2_cpuctl = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_SEC2_CPUCTL); u32 engine = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_GSP_ENGINE); u32 mmu_inv = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_MMU_INVALIDATE); + u32 sw_vector; + + /* Software-interrupt trigger: the driver writes a vector to + * CPU_INTR_LEAF_TRIGGER to fire it (the osVerifyInterrupts sanity + * test uses the doorbell vector). Set the pending bits in the LEAF + * and TOP interrupt-tree registers and inject MSI-X so the guest's + * ISR runs - without this the sanity test times out and + * osVerifySystemEnvironment fails, bailing RmInitAdapter. */ + sw_vector = gsp_emu_shadow_read32(ctx, GSP_EMU_REG_CPU_INTR_LEAF_TRIGGER); + if (sw_vector) { + u32 leaf_idx = sw_vector / 32; + u32 leaf_bit = sw_vector % 32; + u32 subtree = sw_vector / 64; + u32 top_idx = subtree / 32; + u32 top_bit = subtree % 32; + u32 leaf_val = gsp_emu_shadow_read32(ctx, + GSP_EMU_REG_CPU_INTR_LEAF_BASE + leaf_idx * 4); + u32 top_val = gsp_emu_shadow_read32(ctx, + GSP_EMU_REG_CPU_INTR_TOP_BASE + top_idx * 4); + + gsp_emu_shadow_write32(ctx, + GSP_EMU_REG_CPU_INTR_LEAF_BASE + leaf_idx * 4, + leaf_val | (1U << leaf_bit)); + gsp_emu_shadow_write32(ctx, + GSP_EMU_REG_CPU_INTR_TOP_BASE + top_idx * 4, + top_val | (1U << top_bit)); + gsp_emu_shadow_write32(ctx, GSP_EMU_REG_CPU_INTR_LEAF_TRIGGER, 0); + + nv_vgpu_info(ctx->vgpu, "GSP-BOOT: SW interrupt vector %u -> LEAF[%u]|=0x%x TOP[%u]|=0x%x, MSI-X", + sw_vector, leaf_idx, 1U << leaf_bit, top_idx, + 1U << top_bit); + gsp_emu_inject_completion_interrupt(ctx, 0); + } /* TLB invalidate auto-complete: the driver sets TRIGGER then spins * polling for it to clear (kgmmuCheckPendingInvalidates). Report @@ -267,16 +300,18 @@ static void gsp_emu_poll_boot(struct gsp_emu_context *ctx) * driver reads a stale/garbage error code (0xff) and the unload * fails, killing the subsequent re-init. A SEC2 kick after a * completed boot is a GSP shutdown/reload: drop the boot state - * (GSP no longer active, queue dead). */ + * (GSP no longer active, queue dead). Clear boot state FIRST so + * WPR2 is already down when the driver sees CPUCTL=HALTED and + * checks kgspIsWpr2Up (avoids "Booter Unload: WPR2 is still up"). */ if (gsp_cpuctl & GSP_EMU_CPUCTL_STARTCPU) gsp_emu_shadow_write32(ctx, GSP_EMU_REG_GSP_CPUCTL, GSP_EMU_CPUCTL_HALTED); if (sec2_cpuctl & GSP_EMU_CPUCTL_STARTCPU) { + if (ctx->boot_stage == GSP_BOOT_STAGE_BOOTER_DONE) + gsp_emu_clear_boot_state(ctx, "Booter unload/reload kick"); gsp_emu_shadow_write32(ctx, GSP_EMU_REG_SEC2_MAILBOX0, 0); gsp_emu_shadow_write32(ctx, GSP_EMU_REG_SEC2_CPUCTL, GSP_EMU_CPUCTL_HALTED); - if (ctx->boot_stage == GSP_BOOT_STAGE_BOOTER_DONE) - gsp_emu_clear_boot_state(ctx, "Booter unload/reload kick"); } } diff --git a/kernel/gsp_emulation.h b/kernel/gsp_emulation.h index 929003e..6fa69b1 100644 --- a/kernel/gsp_emulation.h +++ b/kernel/gsp_emulation.h @@ -71,6 +71,20 @@ * returns NULL) so the health check always passes. */ #define GSP_EMU_REG_FALCON_DEBUGINFO 0x110094 +/* CPU interrupt tree (Turing, physical-GPU path): the driver accesses the + * VF window registers at virtualRegPhysOffset = NV_VIRTUAL_FUNCTION_FULL_PHYS_OFFSET + * (0xB80000) + offset. + * LEAF_TRIGGER 0xB80000+0x1640 - write a vector to fire its software interrupt + * LEAF[i] 0xB80000+0x1000+i*4 - per-32-vector pending bits + * TOP[i] 0xB81600+i*4 - per-32-subtree pending bits + * _osVerifyInterrupts (osVerifySystemEnvironment) fires a doorbell software + * interrupt and waits for its ISR; if we don't set the pending state and + * inject MSI-X, the ISR never runs and RmInitAdapter bails. */ +#define GSP_EMU_REG_FULL_PHYS_OFFSET 0xB80000 +#define GSP_EMU_REG_CPU_INTR_LEAF_TRIGGER (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1640) +#define GSP_EMU_REG_CPU_INTR_LEAF_BASE (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1000) +#define GSP_EMU_REG_CPU_INTR_TOP_BASE (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1600) + #define GSP_EMU_CPUCTL_STARTCPU 0x2 #define GSP_EMU_CPUCTL_HALTED 0x10 diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index 1075bee..24bd8fe 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -1159,6 +1159,47 @@ static void gsp_rm_handle_kgr_get_info(struct gsp_emu_context *ctx, TU104_MAX_SUBCONTEXT_COUNT); } +/* + * STATIC_KGR_GET_FLOORSPEEPING_MASKS (0x20800a26) + * + * Driver computes numGpcs from floorsweepingMasks.gpcMask; zero kills + * krcWatchdogInit ("numGpcs > 0" assert -> RmInitAdapter bails). Fill + * TU104's present-GPC/TPC masks: 6 GPCs (bits 0-5), 4 TPCs per GPC. + */ +static void gsp_rm_handle_kgr_get_floorsweeping_masks( + struct gsp_emu_context *ctx, + u32 sequence, + u32 *out_status, + u8 *out_params, + u32 *out_params_size) +{ + struct tu104_gr_floorsweeping_masks *m = + (struct tu104_gr_floorsweeping_masks *)out_params; /* engine 0 */ + u32 g; + + memset(out_params, 0, TU104_GR_INFO_MAX_ENGINES * + sizeof(struct tu104_gr_floorsweeping_masks)); + + m->gpcMask = (1U << TU104_NUM_GPC) - 1; /* bits 0-5 = 6 GPCs */ + m->physGpcMask = m->gpcMask; + m->physGfxGpcMask = m->gpcMask; + m->numGfxTpc = TU104_NUM_TPC; + for (g = 0; g < TU104_NUM_GPC; g++) { + m->tpcMask[g] = (1U << TU104_TPC_PER_GPC) - 1; /* 4 TPCs */ + m->tpcCount[g] = TU104_TPC_PER_GPC; + m->mmuPerGpc[g] = 1; + m->numPesPerGpc[g] = 1; + m->zcullMask[g] = (1U << TU104_TPC_PER_GPC) - 1; + } + + *out_params_size = TU104_GR_INFO_MAX_ENGINES * + sizeof(struct tu104_gr_floorsweeping_masks); + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: KGR_GET_FLOORSWEEPING_MASKS -> gpcMask=0x%x tpc/gpc=%u", + m->gpcMask, TU104_TPC_PER_GPC); +} + static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, const u8 *elem, u32 sequence) { @@ -1259,6 +1300,12 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); break; + case TU104_CTRL_STATIC_KGR_GET_FLOORSWEEPING_MASKS: + gsp_rm_handle_kgr_get_floorsweeping_masks(ctx, sequence, + &out_status, + reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); + break; + default: /* Unknown control command - return success with zeroed params. * Do NOT echo the request: pure queries pass uninitialized @@ -1305,6 +1352,62 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, } /* + * GSP_RM_FREE (function 10) - NVOS00_PARAMETERS echo with status=NV_OK. + * + * rpc_gsp_free: { hRoot, hObjectParent, hObjectOld, status }. Echo the + * request's params back with status=0 so the driver's free rpc_message is a + * complete well-formed record. (The poll match is function-only; the echo + * keeps the post-poll result struct self-consistent.) + */ +/* + sizeof(struct tu104_gr_floorsweeping_masks); + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: KGR_GET_FLOORSWEEPING_MASKS -> gpcMask=0x%x tpc/gpc=%u", + m->gpcMask, TU104_TPC_PER_GPC); +} + +/* + * GSP_RM_FREE (function 10) - NVOS00_PARAMETERS echo with status=NV_OK. + * + * rpc_gsp_free: { hRoot, hObjectParent, hObjectOld, status }. Echo the + * request's params back with status=0 so the driver's free rpc_message is a + * complete well-formed record. (The poll match is function-only; the echo + * keeps the post-poll result struct self-consistent.) + */ +static void gsp_rm_handle_free(struct gsp_emu_context *ctx, const u8 *elem, + u32 sequence) +{ + struct gsp_rm_emu *rm = ctx->rm_emu; + const struct gsprm_rpc_header *hdr = + (const struct gsprm_rpc_header *)(elem + GSPRM_ELEM_HDR_SIZE); + const u8 *req = elem + GSPRM_ELEM_HDR_SIZE + sizeof(*hdr); + u8 params[16]; /* NVOS00_PARAMETERS: hRoot, hObjectParent, hObjectOld, status */ + u32 hObjOld = 0; + + if (hdr->length >= sizeof(*hdr) + sizeof(params)) + memcpy(params, req, sizeof(params)); + else + memset(params, 0, sizeof(params)); + + memcpy(&hObjOld, params + 8, 4); + memset(params + 12, 0, 4); /* status = NV_OK */ + + nv_vgpu_info(ctx->vgpu, "GSPRM: FREE hObjOld=0x%x seq=%u cmd_read=%u stat_write=%u", + hObjOld, sequence, rm->cmd_read, rm->stat_write); + + /* Small delay before FREE/UNLOADING replies: mitigates an intermittent + * driver-side reply-matching race in the cleanup path. */ + udelay(2000); + + if (gsp_rm_send(ctx, GSPRM_RPC_FUNC_FREE, sequence, 0, + params, sizeof(params))) + nv_vgpu_err(ctx->vgpu, "GSPRM: FREE reply send failed"); + else + rm->rpcs_replied++; +} + +/* * Handle one command-queue record (first element). For async init RPCs we * just consume. Synchronous RPCs get a reply; per-function handlers are * implemented iteratively (unknown ones get a generic success reply). @@ -1341,36 +1444,27 @@ static void gsp_rm_handle_element(struct gsp_emu_context *ctx, const u8 *elem) gsp_rm_handle_rm_control(ctx, elem, sequence); return; + case GSPRM_RPC_FUNC_FREE: + gsp_rm_handle_free(ctx, elem, sequence); + return; + default: /* Synchronous RPC: echo function+sequence with success so the * driver's rpcRecvPoll completes. */ rm->unknown_rpcs++; - if (function == 10 || function == 47) { - /* FREE/UNLOADING: log hObject + queue positions for - * unload-cycle debugging. driver_rp = the peer's status - * read pointer (swap-rx): if it lags stat_write, the - * driver isn't draining our replies. */ - const u8 *p = elem + GSPRM_ELEM_HDR_SIZE + - sizeof(struct gsprm_rpc_header); - u32 hc = 0, ho = 0, driver_rp = 0; - - if (hdr->length >= sizeof(*hdr) + 12) - memcpy(&ho, p + 8, 4); /* hObjectOld */ - gsp_rm_read_buf(ctx, rm->cmd_off + 0x20, - &driver_rp, sizeof(driver_rp)); - nv_vgpu_info(ctx->vgpu, "GSPRM: RPC %s(%u) seq=%u hRoot=0x%x hObjOld=0x%x cmd_read=%u stat_write=%u drv_rp=%u stat_seq=%u", + if (function == 47) { + /* UNLOADING_GUEST_DRIVER: log for unload-cycle debugging */ + nv_vgpu_info(ctx->vgpu, "GSPRM: RPC %s(%u) seq=%u cmd_read=%u stat_write=%u stat_seq=%u", gsp_rm_rpc_name(function), function, sequence, - hc, ho, rm->cmd_read, rm->stat_write, - driver_rp, rm->stat_seq); + rm->cmd_read, rm->stat_write, rm->stat_seq); } else { nv_vgpu_info(ctx->vgpu, "GSPRM: RPC %s(%u) seq=%u len=%u -> generic SUCCESS reply (unknown #%llu)", gsp_rm_rpc_name(function), function, sequence, hdr->length, rm->unknown_rpcs); } - /* Small delay before fn-10/47 replies: mitigates (does not fully - * eliminate) an intermittent driver-side reply-matching race in - * the FREE/UNLOADING path. See Handoff-vGPU-IO.md. */ - if (function == 10 || function == 47) + /* Small delay before UNLOADING replies: mitigates an intermittent + * driver-side reply-matching race in the cleanup path. */ + if (function == 47) udelay(2000); if (gsp_rm_send(ctx, function, sequence, 0, NULL, 0)) nv_vgpu_err(ctx->vgpu, "GSPRM: reply send failed fn=%u", function); diff --git a/kernel/gsp_rm_emulation.h b/kernel/gsp_rm_emulation.h index b4e84ef..7329c0b 100644 --- a/kernel/gsp_rm_emulation.h +++ b/kernel/gsp_rm_emulation.h @@ -41,6 +41,7 @@ struct gsp_emu_context; #define GSPRM_RPC_FUNC_SET_REGISTRY 73 #define GSPRM_RPC_FUNC_CONTINUATION_RECORD 71 #define GSPRM_RPC_FUNC_GSP_RM_CONTROL 76 +#define GSPRM_RPC_FUNC_FREE 10 #define GSPRM_RPC_EVENT_GSP_INIT_DONE 0x1001 /* rpc_set_guest_system_info_v03_00: version fields the driver reads back diff --git a/kernel/gsp_rm_tu104.h b/kernel/gsp_rm_tu104.h index db05f68..ff2a4a7 100644 --- a/kernel/gsp_rm_tu104.h +++ b/kernel/gsp_rm_tu104.h @@ -728,6 +728,27 @@ struct tu104_gr_static_info { /* TU104 max subcontexts (NV_PGRAPH_PRI_FE_CHIP_DEF_INFO_MAX_VEID_COUNT_INIT) */ #define TU104_MAX_SUBCONTEXT_COUNT 64 +/* NV2080_CTRL_INTERNAL_STATIC_GR_FLOORSWEEPING_MASKS (ctrl2080internal.h) + * + STATIC_KGR_GET_FLOORSWEEPING_MASKS cmd = 0x20800a26. + * Driver computes numGpcs from floorsweepingMasks.gpcMask - zero kills + * krcWatchdogInit ("numGpcs > 0" assert -> RmInitAdapter bails). */ +#define TU104_CTRL_STATIC_KGR_GET_FLOORSWEEPING_MASKS 0x20800a26 +#define TU104_GR_MAX_GPC 12 +#define TU104_GR_MAX_TPC_PER_GPC_COUNT 10 + +struct tu104_gr_floorsweeping_masks { + u32 gpcMask; + u32 tpcMask[TU104_GR_MAX_GPC]; + u32 tpcCount[TU104_GR_MAX_GPC]; + u32 physGpcMask; + u32 mmuPerGpc[TU104_GR_MAX_GPC]; + u32 tpcToPesMap[TU104_GR_MAX_TPC_PER_GPC_COUNT]; + u32 numPesPerGpc[TU104_GR_MAX_GPC]; + u32 zcullMask[TU104_GR_MAX_GPC]; + u32 physGfxGpcMask; + u32 numGfxTpc; +}; + /* TU104 SM topology: 6 GPCs x 4 TPCs x 2 SMs = 48 SMs, 24 TPCs (RTX 2080 SUPER) */ #define TU104_NUM_GPC 6 #define TU104_TPC_PER_GPC 4 |
