diff --git a/README.md b/README.md index 0bbfc24..40bcef8 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,22 @@ sudo ./install.sh --mclk-ndiv=70 # → 1890 MHz Values below stock downclock the card, which is the way to stabilise a card that fails at stock. -Without the flag, patches `0009` and `0010` are not applied at all. The multiplier is compiled into the modules, so changing it means re-running `install.sh`. In a mixed 8GB+10GB system the same multiplier lands on every card. +Without the flag, patches `0008` and `0009` are not applied at all. The multiplier is compiled into the modules, so changing it means re-running `install.sh`. In a mixed 8GB+10GB system the same multiplier lands on every card. If a value turns out to be unstable - reinstall without `--mclk-ndiv` (or run `./remove.sh`) from a working state. +### IOMMU + +NVIDIA recommends `iommu=pt` (passthrough) for all GPUs. In this mode, DMA between the GPU and system memory bypasses IOMMU translation, avoiding extra latency and potential mapping errors. + +The installer does **not** touch the kernel command line by default. To have it add `iommu=pt` automatically: + +```bash +sudo ./install.sh --iommu +``` + +Or add `iommu=pt` to your kernel cmdline manually (via GRUB, systemd-boot, etc.). IOMMU must also be enabled in BIOS (VT-d on Intel, AMD-Vi / SVM on AMD). + ## What Gets Unlocked | Feature | Status | diff --git a/common/constants.yaml b/common/constants.yaml deleted file mode 100644 index 859c60a..0000000 --- a/common/constants.yaml +++ /dev/null @@ -1,88 +0,0 @@ -driver_versions: - - "610.43.03" - - "610.43.02" - -gpu: - vendor_id: "10de" - device_ids: - - "20c2" - - "2082" - -compute: - ss0: "0x88888888" - ss1: "0x00000008" - -pcie: - target_gen: 2 - link_speed_gen2: "0x2" - xve_link_control_status: "0x00088088" - xve_link_control_2: "0x000880a8" - pl_link_rate_addr: "0x0008c1c0" - pl_link_rate_value: "0x00240036" - vsec_hierarchy_addr: "0x00088610" - vsec_device_addr: "0x0008860c" - xp_fuse_override_base: "0x0008e110" - xp_fuse_override_val_base: "0x0008e120" - opt_gen23_addr: "0x0082057c" - opt_magic_a100: "0x00200000" - -mclk_overclock: - supported_device_ids: - - "20c2" - - "2082" - ndiv_min: 30 - ndiv_max: 80 - mhz_per_ndiv: 27 - stock_ndiv: - "10gb": 45 # 1215 MHz - "8gb_250w": 54 # 1458 MHz - "8gb_300w": 64 # 1728 MHz, VBIOS 92.00.6D.00.0A - # PLM addresses opened by patch 0001 (SEC2 Booter) to allow PLL access - plm: - fbpa_pll0: "0x009a3c7c" # value 0xffffffff - fbpa_pll1: "0x009a3c80" # value 0xffffffff - fbpa_pll2: "0x009a3c84" # value 0xffffffff - # Pre-GSP path (patch 0009, kernel_gsp_tu102.c) - pre_gsp: - fbpa0_pll_plm: "0x00903c7c" # PLM readback, bit4 = PLL access open - fbpa0_pll_coeff: "0x00903c98" # read stock NDIV from bits [15:8] - fbio_memclk_change_alert: "0x009a0590" # bit31 = MEMCLK_CHANGE_ALERT - hbm_self_refresh: "0x009a031c" # write 1 = enter, 0 = exit - fbpa_base: "0x00900000" - fbpa_stride: "0x00004000" - fbpa_count: 12 - fbpa_pll_cfg_offset: "0x3c90" # base + idx*stride + offset - fbpa_pll_coeff_offset: "0x3c98" # base + idx*stride + offset, NDIV bits [15:8] - ddll_control: "0x009a11dc" # bit6 = trigger DDLL calibration - ddll_cal_status0: "0x009a0674" - ddll_cal_status1: "0x009a0678" - # Post-GSP path (patch 0010, kernel_gsp.c) - post_gsp: - fbpa_multicast_pll_coeff: "0x0098bc98" # multicast COEFF write (all FBPAs at once) - pri_fence: "0x001211fc" # PRI write fence, write 0x0 to flush - fbpa0_pll_cfg: "0x00903c90" # poll bit5 for PLL lock - # COEFF register layout (shared by pre-GSP and post-GSP paths) - coeff_layout: - ndiv_shift: 8 - ndiv_mask: "0x0000ff00" - preserve_mask: "0xffff00ff" # MDIV/PDIV bits kept in read-modify-write - fallback_300w: "0x00010001" # MDIV=1, PDIV=1 (used when PRI read returns 0 or BAD) - pll_cfg_bits: - enable: "0x09" # bits 0,3 - lock: "0x20" # bit 5 - ddll_reset: "0x1000" # bit 12 - comment: "HBM2 memory clock via the FBPA PLL NDIV. The patches ship an XX placeholder that build.sh substitutes from --mclk-ndiv." - -profiles: - "8gb": - stock_mib: 8192 - unlocked_mib: 65536 - cfg1: "0x02779000" - lmr: "0x0000020B" - fb_bytes: "0x0000001000000000" - "10gb": - stock_mib: 10240 - unlocked_mib: 40960 - cfg1: "0x02669000" - lmr: "0x0000028A" - fb_bytes: "0x0000000A00000000" diff --git a/driver/build.sh b/driver/build.sh index dbcdfa6..49ad2ee 100755 --- a/driver/build.sh +++ b/driver/build.sh @@ -77,7 +77,7 @@ if [[ -n "${MCLK_NDIV}" ]]; then fi for p in "${patches[@]}"; do base="$(basename "${p}")" - if [[ ("${base}" == "0009-mclk-overclock.patch" || "${base}" == "0010-mclk-overclock-post-gsp.patch") && -z "${MCLK_NDIV}" ]]; then + if [[ ("${base}" == "0008-mclk-overclock.patch" || "${base}" == "0009-mclk-overclock-post-gsp.patch") && -z "${MCLK_NDIV}" ]]; then warn "Skipping ${base} (no --mclk-ndiv)" continue fi diff --git a/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch b/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch index bba89b7..1a25b1e 100644 --- a/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch +++ b/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch @@ -1,7 +1,6 @@ -diff -Naur a/src/nvidia/generated/g_kernel_gsp_nvoc.h b/src/nvidia/generated/g_kernel_gsp_nvoc.h ---- a/src/nvidia/generated/g_kernel_gsp_nvoc.h 2026-07-18 11:26:26.833302560 -0700 -+++ b/src/nvidia/generated/g_kernel_gsp_nvoc.h 2026-07-18 11:26:26.834341525 -0700 -@@ -544,6 +544,8 @@ +--- a/src/nvidia/generated/g_kernel_gsp_nvoc.h 2026-07-07 18:23:15.000000000 +0200 ++++ b/src/nvidia/generated/g_kernel_gsp_nvoc.h 2026-07-31 00:43:24.962804310 +0200 +@@ -544,6 +544,8 @@ struct KernelGsp { RM_RISCV_UCODE_DESC *pGspRmBootUcodeDesc; MEMORY_DESCRIPTOR *pGspUCodeRadix3Descriptor; MEMORY_DESCRIPTOR *pSignatureMemdesc; @@ -10,9 +9,8 @@ diff -Naur a/src/nvidia/generated/g_kernel_gsp_nvoc.h b/src/nvidia/generated/g_k GspSystemInfo *pSystemInfo; NvU32 regTableSize; PACKED_REGISTRY_TABLE *pRegTable; -diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c ---- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-18 11:26:26.827164897 -0700 -+++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-18 11:26:26.828254361 -0700 +--- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-07 18:23:15.000000000 +0200 ++++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:43:51.261744520 +0200 @@ -102,6 +102,23 @@ #include "crashcat/crashcat_report.h" @@ -37,7 +35,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ struct MIG_CI_UPDATE_CALLBACK_PARAMS { -@@ -4805,14 +4824,23 @@ +@@ -4805,14 +4822,23 @@ _kgspBootGspRm(OBJGPU *pGpu, KernelGsp * if (kgspIsWpr2Up_HAL(pGpu, pKernelGsp) && (!pGpu->getProperty(pGpu, PDB_PROP_GPU_PREINITIALIZED_WPR_REGION))) { @@ -64,7 +62,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ { // If the new FB layout requires a scrubber ucode to scrub additional space, prepare it now NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, _kgspPrepareScrubberImageIfNeeded(pGpu, pKernelGsp)); -@@ -4821,6 +4849,125 @@ +@@ -4821,6 +4847,130 @@ _kgspBootGspRm(OBJGPU *pGpu, KernelGsp * // Setup arguments for bootstrapping GSP NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kgspPrepareForBootstrap_HAL(pGpu, pKernelGsp, KGSP_BOOT_MODE_NORMAL)); @@ -87,6 +85,11 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ + { 0x009a3c7cU, 0xffffffffU, "FBPA_PLL0" }, + { 0x009a3c80U, 0xffffffffU, "FBPA_PLL1" }, + { 0x009a3c84U, 0xffffffffU, "FBPA_PLL2" }, ++ { 0x00088fe8U, 0xffffffffU, "XVE_PLM" }, ++ { 0x00088fecU, 0xffffffffU, "XVE_CYA_PLM" }, ++ { 0x0008872cU, 0x0000000aU, "XVE_FUSE_OVR" }, ++ { 0x0008841cU, 0x4034ad00U, "XVE_CYA_SPD" }, ++ { 0x000880a8U, 0x00000002U, "XVE_TARGET" }, + }; + + NvU32 wpr2Lo = GPU_REG_RD32(pGpu, 0x001fa824U); @@ -190,7 +193,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ // Release the API lock if relaxed locking for parallel init is enabled NvBool bRelaxedLocking = _kgspShouldRelaxGspInitLocking(pGpu); if (bRelaxedLocking) -@@ -5164,6 +5292,53 @@ +@@ -5164,6 +5314,53 @@ kgspInitRm_IMPL goto done; } @@ -244,7 +247,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ NV_ASSERT_OK_OR_GOTO(status, kgspInitGspTraceCrashBuffer(pGpu, pKernelGsp), done); // Set PDB properties as per data from GSP. -@@ -5662,6 +5834,84 @@ +@@ -5662,6 +5859,84 @@ _kgspFreeBootBinaryImage pKernelGsp->gspRmBootUcodeSize = 0; } @@ -329,7 +332,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ static NV_STATUS _kgspCreateSignatureMemdesc ( -@@ -5672,6 +5922,9 @@ +@@ -5672,6 +5947,9 @@ _kgspCreateSignatureMemdesc { NV_STATUS status = NV_OK; NvU8 *pSignatureVa = NULL; @@ -339,7 +342,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ NvU64 flags = MEMDESC_FLAGS_NONE; if (confComputeForceUnprotAlloc(pGpu)) -@@ -5682,7 +5935,7 @@ +@@ -5682,7 +5960,7 @@ _kgspCreateSignatureMemdesc // NOTE: align to 256 because that's the alignment needed for Booter DMA NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, memdescCreate(&pKernelGsp->pSignatureMemdesc, pGpu, @@ -348,7 +351,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ NV_TRUE, ADDR_SYSMEM, NV_MEMORY_CACHED, flags)); memdescTagAlloc(status, -@@ -5694,8 +5947,48 @@ +@@ -5694,8 +5972,48 @@ _kgspCreateSignatureMemdesc (pSignatureVa != NULL) ? NV_OK : NV_ERR_INSUFFICIENT_RESOURCES, fail_alloc); @@ -399,7 +402,7 @@ diff -Naur a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c b/src/nvidia/src/kernel/ memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); pSignatureVa = NULL; -@@ -5709,6 +6002,69 @@ +@@ -5709,6 +6027,69 @@ fail_create: memdescDestroy(pKernelGsp->pSignatureMemdesc); pKernelGsp->pSignatureMemdesc = NULL; diff --git a/driver/patches/0007-pcie-gen2.patch b/driver/patches/0007-pcie-gen2.patch index db73e34..6e5ba03 100644 --- a/driver/patches/0007-pcie-gen2.patch +++ b/driver/patches/0007-pcie-gen2.patch @@ -1,310 +1,73 @@ ---- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c -+++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c -@@ -4942,6 +4942,260 @@ +--- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:43:51.261744520 +0200 ++++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:44:47.811484740 +0200 +@@ -4951,6 +4951,70 @@ devId); } -+ ++ // PCIe Gen2: directed speed change via XP LTSSM ++ // PLM gates (XVE_PLM, XVE_CYA_PLM, XVE_FUSE_OVR, XVE_CYA_SPD, XVE_TARGET) ++ // are already opened by the main plmTable above. + { -+ #define PCIE_GEN2_LINK_CAP_ADDR 0x00088084U -+ #define PCIE_GEN2_LINK_CAP2_ADDR 0x000880a4U -+ #define PCIE_GEN2_LINK_CTRL_2_ADDR 0x000880a8U -+ #define PCIE_GEN2_LINK_CTRL_STATUS_ADDR 0x00088088U -+ #define PCIE_GEN2_PL_LINK_RATE_ADDR 0x0008c1c0U -+ #define PCIE_GEN2_LTSSM_ADDR 0x0008872cU -+ #define PCIE_GEN2_VSEC_DEVICE_ADDR 0x0008860cU -+ #define PCIE_GEN2_VSEC_HIERARCHY_ADDR 0x00088610U -+ #define PCIE_GEN2_XP3G_OVR_BASE 0x0008e110U -+ #define PCIE_GEN2_XP3G_VAL_BASE 0x0008e120U -+ #define PCIE_GEN2_XP3G_STATUS_BASE 0x0008e100U -+ #define PCIE_GEN2_OPT_GEN23_ADDR 0x0082057cU -+ #define PCIE_GEN2_OPT_GEN3_ADDR 0x00820580U -+ #define PCIE_GEN2_OPT_MAGIC_ADDR 0x00820520U -+ #define PCIE_LINK_SPEED_OF(stat) (((stat) >> 16) & 0xFU) -+ const NvU32 PCIE_GEN2_LINK_SPEED = 0x00000002U; -+ const NvU32 PCIE_GEN2_PL_LINK_RATE_VALUE = 0x00240036U; ++ NvU32 xpCfg0 = GPU_REG_RD32(pGpu, 0x0008C040U); ++ NvU32 xpLctrl2 = GPU_REG_RD32(pGpu, 0x0008C1C0U); ++ NvU32 xpCya0 = GPU_REG_RD32(pGpu, 0x0008C2C0U); + -+ NvU32 capBefore = GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CAP_ADDR); -+ NvU32 statBefore = GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CTRL_STATUS_ADDR); -+ NvU32 vsecDev = GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_DEVICE_ADDR); -+ NvU32 vsecHier = GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_HIERARCHY_ADDR); + NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe pre CAP=0x%08x CAP2=0x%08x LC2=0x%08x PL=0x%08x " -+ "STAT=0x%08x VSEC dev=0x%08x hier=0x%08x OPT=%08x/%08x/%08x " -+ "XP3G st0=0x%08x ovr0=0x%08x val0=0x%08x " -+ "st3=0x%08x ovr3=0x%08x val3=0x%08x speed=%u\n", -+ capBefore, -+ GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CAP2_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CTRL_2_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_PL_LINK_RATE_ADDR), -+ statBefore, -+ vsecDev, -+ vsecHier, -+ GPU_REG_RD32(pGpu, PCIE_GEN2_OPT_GEN23_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_OPT_GEN3_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_OPT_MAGIC_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_STATUS_BASE), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_OVR_BASE), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_VAL_BASE), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_STATUS_BASE + 0xCU), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_OVR_BASE + 0xCU), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_VAL_BASE + 0xCU), -+ PCIE_LINK_SPEED_OF(statBefore)); -+ -+ { -+ static const struct { NvU32 addr; NvU32 value; const char *name; } xp3gTable[] = { -+ { 0x0008e1b0U, 0xffffffffU, "XP3G_PLM" }, -+ { 0x0008e1b4U, 0xffffffffU, "XP3G_PLM4" }, -+ { 0x0008e1b8U, 0xffffffffU, "XP3G_PLM8" }, -+ { 0x0008e1bcU, 0xffffffffU, "XP3G_PLMC" }, -+ { 0x00088fe8U, 0xffffffffU, "XVE_D0" }, -+ { 0x00088fecU, 0xffffffffU, "XVE_D4" }, -+ { 0x00088ff0U, 0xffffffffU, "XVE_D8" }, -+ { 0x008200d0U, 0xffffffffU, "OPTB_D0" }, -+ { 0x008200d4U, 0xffffffffU, "OPTB_D4" }, -+ { 0x008200d8U, 0xffffffffU, "OPTB_D8" }, -+ { 0x008200dcU, 0xffffffffU, "OPTB_DC" }, -+ { 0x008200e0U, 0xffffffffU, "OPTB_E0" }, -+ { 0x008200e4U, 0xffffffffU, "OPTB_E4" }, -+ { 0x008200e8U, 0xffffffffU, "OPTB_E8" }, -+ { 0x008200ecU, 0xffffffffU, "OPTB_EC" }, -+ { 0x008200f0U, 0xffffffffU, "OPTB_F0" }, -+ { 0x008200f4U, 0xffffffffU, "OPTB_F4" }, -+ { 0x00823800U, 0xffffffffU, "FEAT_OVR_ECC_PLM" }, -+ { 0x0082057cU, 0x00000000U, "OPT_GEN23" }, -+ { 0x0008e120U, 0x00000000U, "XP3G_VAL0" }, -+ { 0x0008e110U, 0x00000001U, "XP3G_OVR0" }, -+ { 0x0008e12cU, 0x00200000U, "XP3G_VAL3" }, -+ { 0x0008e11cU, 0x00000004U, "XP3G_OVR3" }, -+ }; -+ NvU32 xi, xattempt; -+ NV_STATUS xpStatus; -+ const NvU32 xp3gCount = sizeof(xp3gTable) / sizeof(xp3gTable[0]); -+ #define PCIE_GEN2_PRIV_MISC_1_ADDR 0x0008841cU -+ #define PCIE_GEN2_PRIV_MISC_1_GEN2_EN ((1U << 11) | (1U << 13)) -+ #define PCIE_GEN2_PRIV_MISC_1_GEN2_VAL ((1U << 12) | (1U << 14)) -+ -+ for (xi = 0; xi < xp3gCount; xi++) -+ { -+ NvBool wrote = NV_FALSE; -+ for (xattempt = 0; xattempt < 2 && !wrote; xattempt++) -+ { -+ GPU_REG_WR32(pGpu, 0x001fa824U, wpr2Lo); -+ GPU_REG_WR32(pGpu, 0x001fa828U, wpr2Hi); ++ "SEC2_DEBUG: PCIe pre: CFG0=0x%08x LCTRL2=0x%08x CYA0=0x%08x\n", ++ xpCfg0, xpLctrl2, xpCya0); + -+ xpStatus = kgspSec2PostblTimingRefillPayload(pGpu, pKernelGsp, -+ xp3gTable[xi].addr, xp3gTable[xi].value); -+ if (xpStatus != NV_OK) -+ continue; -+ -+ xpStatus = kgspExecuteBooterLoad_HAL(pGpu, pKernelGsp, -+ memdescGetPhysAddr(pKernelGsp->pWprMetaDescriptor, AT_GPU, 0)); -+ -+ NvU32 tgtRd = GPU_REG_RD32(pGpu, xp3gTable[xi].addr); -+ NvU32 ovr0Rd = GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_OVR_BASE); -+ NvU32 val0Rd = GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_VAL_BASE); -+ NvU32 ovr3Rd = GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_OVR_BASE + 0xCU); -+ NvU32 val3Rd = GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_VAL_BASE + 0xCU); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe xp3g booter %s(0x%x)=0x%08x attempt=%u " -+ "status=0x%x rd=0x%08x OVR0=0x%08x VAL0=0x%08x " -+ "OVR3=0x%08x VAL3=0x%08x\n", -+ xp3gTable[xi].name, xp3gTable[xi].addr, -+ xp3gTable[xi].value, xattempt, xpStatus, -+ tgtRd, ovr0Rd, val0Rd, ovr3Rd, val3Rd); -+ if (tgtRd == xp3gTable[xi].value) -+ wrote = NV_TRUE; -+ } -+ if (!wrote) -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe xp3g booter FAILED to set %s\n", -+ xp3gTable[xi].name); -+ } ++ GPU_REG_WR32(pGpu, 0x0008C2C0U, xpCya0 & ~0x00802005U); ++ GPU_REG_WR32(pGpu, 0x0008C040U, (xpCfg0 & ~0xC0000U) | 0x80000U); ++ GPU_REG_WR32(pGpu, 0x0008C1C0U, (xpLctrl2 & ~0xF0000U) | 0x20000U); + ++ { ++ OBJCL *pCl = SYS_GET_CL(SYS_GET_INSTANCE()); ++ PORTDATA *pUpPort = &pGpu->gpuClData.upstreamPort; ++ if (pCl != NULL && pUpPort->addr.valid) + { -+ NvU32 capNow = GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CAP_ADDR); -+ NvU32 cap2Now = GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CAP2_ADDR); -+ NvU32 opt23Now = GPU_REG_RD32(pGpu, 0x0082057cU); -+ NvU32 plmXp = GPU_REG_RD32(pGpu, 0x0008e1b0U); ++ NvU32 lnkCtl2Off = pUpPort->PCIECapPtr + 0x30U; ++ NvU16 rpLnkCtl2 = clPcieReadWord(pCl, ++ pUpPort->addr.domain, pUpPort->addr.bus, ++ pUpPort->addr.device, pUpPort->addr.func, lnkCtl2Off); ++ NvU16 rpLnkCtl2New = (rpLnkCtl2 & ~0xFU) | 0x2U; ++ clPcieWriteWord(pCl, ++ pUpPort->addr.domain, pUpPort->addr.bus, ++ pUpPort->addr.device, pUpPort->addr.func, ++ lnkCtl2Off, rpLnkCtl2New); + NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe Cap oracle CAP=0x%08x CAP2=0x%08x " -+ "OPT_GEN23=0x%08x XP3G_PLM=0x%08x\n", -+ capNow, cap2Now, opt23Now, plmXp); ++ "SEC2_DEBUG: PCIe root port LnkCtl2 @ 0x%x: 0x%04x -> 0x%04x\n", ++ lnkCtl2Off, rpLnkCtl2, rpLnkCtl2New); + } ++ } + -+ { -+ NvU32 vsecDevNow = GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_DEVICE_ADDR); -+ NvU32 vsecDevWant = vsecDevNow | (1U << 0); -+ NvBool wrote = NV_FALSE; -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe VSEC_DEVICE pre=0x%08x want=0x%08x\n", -+ vsecDevNow, vsecDevWant); -+ for (xattempt = 0; xattempt < 2 && !wrote; xattempt++) -+ { -+ GPU_REG_WR32(pGpu, 0x001fa824U, wpr2Lo); -+ GPU_REG_WR32(pGpu, 0x001fa828U, wpr2Hi); -+ xpStatus = kgspSec2PostblTimingRefillPayload(pGpu, pKernelGsp, -+ PCIE_GEN2_VSEC_DEVICE_ADDR, vsecDevWant); -+ if (xpStatus != NV_OK) -+ continue; -+ xpStatus = kgspExecuteBooterLoad_HAL(pGpu, pKernelGsp, -+ memdescGetPhysAddr(pKernelGsp->pWprMetaDescriptor, AT_GPU, 0)); -+ NvU32 rd = GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_DEVICE_ADDR); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe VSEC_DEVICE booter attempt=%u " -+ "status=0x%x rd=0x%08x\n", -+ xattempt, xpStatus, rd); -+ if (rd == vsecDevWant) -+ wrote = NV_TRUE; -+ } -+ if (!wrote) -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe VSEC_DEVICE booter FAILED\n"); -+ } ++ { ++ NvU32 cfg0Now = GPU_REG_RD32(pGpu, 0x0008C040U); ++ NvU32 cfg0After; ++ NvU32 linkCtrlStat; ++ NvU32 i; ++ ++ GPU_REG_WR32(pGpu, 0x0008C040U, (cfg0Now & ~0xFU) | 0x1U); + ++ for (i = 0; i < 50; i++) + { -+ NvU32 misc1 = GPU_REG_RD32(pGpu, PCIE_GEN2_PRIV_MISC_1_ADDR); -+ NvU32 misc1Want = (misc1 | PCIE_GEN2_PRIV_MISC_1_GEN2_EN) -+ & ~PCIE_GEN2_PRIV_MISC_1_GEN2_VAL; -+ NvBool wrote = NV_FALSE; -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe PRIV_MISC_1 pre=0x%08x want=0x%08x\n", -+ misc1, misc1Want); -+ for (xattempt = 0; xattempt < 2 && !wrote; xattempt++) -+ { -+ GPU_REG_WR32(pGpu, 0x001fa824U, wpr2Lo); -+ GPU_REG_WR32(pGpu, 0x001fa828U, wpr2Hi); -+ xpStatus = kgspSec2PostblTimingRefillPayload(pGpu, pKernelGsp, -+ PCIE_GEN2_PRIV_MISC_1_ADDR, misc1Want); -+ if (xpStatus != NV_OK) -+ continue; -+ xpStatus = kgspExecuteBooterLoad_HAL(pGpu, pKernelGsp, -+ memdescGetPhysAddr(pKernelGsp->pWprMetaDescriptor, AT_GPU, 0)); -+ NvU32 rd = GPU_REG_RD32(pGpu, PCIE_GEN2_PRIV_MISC_1_ADDR); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe PRIV_MISC_1 booter attempt=%u " -+ "status=0x%x rd=0x%08x\n", -+ xattempt, xpStatus, rd); -+ if (rd == misc1Want) -+ wrote = NV_TRUE; -+ } -+ if (!wrote) -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe PRIV_MISC_1 booter FAILED\n"); ++ osDelay(10); ++ if ((GPU_REG_RD32(pGpu, 0x0008C040U) & 0x10U) == 0) ++ break; + } + -+ GPU_REG_WR32(pGpu, 0x001fa824U, wpr2Lo); -+ GPU_REG_WR32(pGpu, 0x001fa828U, wpr2Hi); -+ } -+ -+ { -+ NvU32 hier = GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_HIERARCHY_ADDR); -+ hier = (hier & ~(1U << 12)) | (1U << 0); -+ GPU_REG_WR32(pGpu, PCIE_GEN2_VSEC_HIERARCHY_ADDR, hier); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe vsec hierarchy=0x%08x device=0x%08x\n", -+ GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_HIERARCHY_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_DEVICE_ADDR)); -+ } ++ cfg0After = GPU_REG_RD32(pGpu, 0x0008C040U); ++ GPU_REG_WR32(pGpu, 0x0008C040U, cfg0After & ~0xFU); + -+ { -+ NvU32 lc2 = GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CTRL_2_ADDR); -+ NvU32 linkCfg; -+ NvU32 cya0; -+ lc2 = (lc2 & ~0x0000000FU) | PCIE_GEN2_LINK_SPEED; -+ lc2 = (lc2 & ~0x000F0000U) | 0x000F0000U; -+ GPU_REG_WR32(pGpu, PCIE_GEN2_LINK_CTRL_2_ADDR, lc2); -+ cya0 = GPU_REG_RD32(pGpu, 0x0008c2c0U); -+ cya0 = cya0 & ~(1U << 2); -+ GPU_REG_WR32(pGpu, 0x0008c2c0U, cya0); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe CYA_0 after clear DIS_G2: 0x%08x (bit2=%u)\n", -+ GPU_REG_RD32(pGpu, 0x0008c2c0U), -+ (GPU_REG_RD32(pGpu, 0x0008c2c0U) >> 2) & 1U); -+ linkCfg = GPU_REG_RD32(pGpu, 0x0008c040U); -+ linkCfg = (linkCfg & ~0x000C0000U) | (0x2U << 18); -+ GPU_REG_WR32(pGpu, 0x0008c040U, linkCfg); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe LINK_CONFIG_0 after MAX_RATE=2: 0x%08x\n", -+ GPU_REG_RD32(pGpu, 0x0008c040U)); -+ GPU_REG_WR32(pGpu, PCIE_GEN2_PL_LINK_RATE_ADDR, PCIE_GEN2_PL_LINK_RATE_VALUE); -+ GPU_REG_WR32(pGpu, 0x0008872cU, 0x00000006U); ++ linkCtrlStat = GPU_REG_RD32(pGpu, 0x00088088U); + NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe XVE_OVR@8872c=0x%08x; skip mid-boot retrain\n", -+ GPU_REG_RD32(pGpu, 0x0008872cU)); ++ "SEC2_DEBUG: PCIe retrain done (polls=%u): " ++ "LinkCtrlStat=0x%08x speed=%u width=x%u\n", ++ i, linkCtrlStat, ++ (linkCtrlStat >> 16) & 0xFU, ++ (linkCtrlStat >> 20) & 0x3FU); + } -+ -+ NvU32 statAfter = GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CTRL_STATUS_ADDR); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe retrain done CAP=0x%08x CAP2=0x%08x LC2=0x%08x " -+ "PL=0x%08x STAT=0x%08x hier=0x%08x dev=0x%08x OPT=%08x/%08x/%08x " -+ "XP3G ovr0=0x%08x val0=0x%08x ovr3=0x%08x val3=0x%08x " -+ "MISC1=0x%08x speed=%u\n", -+ GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CAP_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CAP2_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_LINK_CTRL_2_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_PL_LINK_RATE_ADDR), -+ statAfter, -+ GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_HIERARCHY_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_VSEC_DEVICE_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_OPT_GEN23_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_OPT_GEN3_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_OPT_MAGIC_ADDR), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_OVR_BASE), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_VAL_BASE), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_OVR_BASE + 0xCU), -+ GPU_REG_RD32(pGpu, PCIE_GEN2_XP3G_VAL_BASE + 0xCU), -+ GPU_REG_RD32(pGpu, 0x0008841cU), -+ PCIE_LINK_SPEED_OF(statAfter)); + } + plmStatus = kgspSec2PostblTimingRebuildStockSignature(pGpu, pKernelGsp); if (plmStatus != NV_OK) { ---- a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c -+++ b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c -@@ -611,6 +611,44 @@ - } - } - -+ -+ { -+ NvU32 lateDevId = pGpu->idInfo.PCIDeviceID >> 16; -+ if ((lateDevId == 0x20C2 || lateDevId == 0x2082) && status == NV_OK) -+ { -+ #define PCIE_GEN2_PRIV_MISC_1_ADDR_LATE 0x0008841cU -+ #define PCIE_GEN2_PRIV_MISC_1_GEN2_EN_LATE ((1U << 11) | (1U << 13)) -+ #define PCIE_GEN2_PRIV_MISC_1_GEN2_VAL_LATE ((1U << 12) | (1U << 14)) -+ NvU32 misc1Late = GPU_REG_RD32(pGpu, PCIE_GEN2_PRIV_MISC_1_ADDR_LATE); -+ NvU32 misc1WantLate = (misc1Late | PCIE_GEN2_PRIV_MISC_1_GEN2_EN_LATE) -+ & ~PCIE_GEN2_PRIV_MISC_1_GEN2_VAL_LATE; -+ GPU_REG_WR32(pGpu, PCIE_GEN2_PRIV_MISC_1_ADDR_LATE, misc1WantLate); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe PRIV_MISC_1 late pre=0x%08x post=0x%08x\n", -+ misc1Late, -+ GPU_REG_RD32(pGpu, PCIE_GEN2_PRIV_MISC_1_ADDR_LATE)); -+ { -+ NvU32 cyaLate = GPU_REG_RD32(pGpu, 0x0008c2c0U); -+ cyaLate = cyaLate & ~(1U << 2); -+ GPU_REG_WR32(pGpu, 0x0008c2c0U, cyaLate); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe CYA_0 late clear DIS_G2: 0x%08x (bit2=%u)\n", -+ GPU_REG_RD32(pGpu, 0x0008c2c0U), -+ (GPU_REG_RD32(pGpu, 0x0008c2c0U) >> 2) & 1U); -+ NvU32 linkCfgLate = GPU_REG_RD32(pGpu, 0x0008c040U); -+ linkCfgLate = (linkCfgLate & ~0x000C0000U) | (0x2U << 18); -+ GPU_REG_WR32(pGpu, 0x0008c040U, linkCfgLate); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe LINK_CONFIG_0 late MAX_RATE=2: 0x%08x\n", -+ GPU_REG_RD32(pGpu, 0x0008c040U)); -+ GPU_REG_WR32(pGpu, 0x0008872cU, 0x00000006U); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe XVE_OVR late=0x%08x\n", -+ GPU_REG_RD32(pGpu, 0x0008872cU)); -+ } -+ } -+ } -+ - if (status != NV_OK) - { - NV_PRINTF(LEVEL_ERROR, "failed to execute Booter Load (ucode for initial boot): 0x%x\n", status); diff --git a/driver/patches/0009-mclk-overclock.patch b/driver/patches/0008-mclk-overclock.patch similarity index 98% rename from driver/patches/0009-mclk-overclock.patch rename to driver/patches/0008-mclk-overclock.patch index 07ac0ed..9c52605 100644 --- a/driver/patches/0009-mclk-overclock.patch +++ b/driver/patches/0008-mclk-overclock.patch @@ -1,6 +1,6 @@ ---- a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c -+++ b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c -@@ -649,6 +649,144 @@ +--- a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c 2026-07-31 00:17:22.670241348 +0200 ++++ b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c 2026-07-31 00:18:28.686969052 +0200 +@@ -611,6 +611,144 @@ kgspBootstrap_TU102 } } diff --git a/driver/patches/0008-pcie-gen2-probe-retrain.patch b/driver/patches/0008-pcie-gen2-probe-retrain.patch deleted file mode 100644 index 4f2e90b..0000000 --- a/driver/patches/0008-pcie-gen2-probe-retrain.patch +++ /dev/null @@ -1,110 +0,0 @@ ---- a/kernel-open/nvidia/nv.c -+++ b/kernel-open/nvidia/nv.c -@@ -65,6 +65,10 @@ - - #include - #include -+#include -+#include -+#include -+#include - - #include /* HDA struct snd_card */ - -@@ -1360,6 +1364,87 @@ - #if defined(NV_UVM_ENABLE) - nv_uvm_resume_P2P(pUuid); - #endif -+} -+ -+static void -+nv_cmp170hx_retrain_gen2(nv_state_t *nv) -+{ -+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv); -+ struct pci_dev *gpu = nvl->pci_dev; -+ struct pci_dev *upstream; -+ void __iomem *bar0; -+ u16 gpu_ctl2, upstream_ctl2, upstream_ctl, link_status = 0; -+ u32 cya0, link_config; -+ int ret, attempt; -+ -+ if ((gpu == NULL) || -+ ((gpu->device != 0x20c2) && (gpu->device != 0x2082))) -+ return; -+ -+ upstream = pci_upstream_bridge(gpu); -+ if (upstream == NULL) -+ { -+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, -+ "CMP Gen2: no upstream PCIe bridge; skipping link retrain\n"); -+ return; -+ } -+ bar0 = ioremap(pci_resource_start(gpu, 0), 0x90000); -+ if (bar0 == NULL) -+ { -+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, -+ "CMP Gen2: cannot map BAR0; skipping link retrain\n"); -+ return; -+ } -+ cya0 = readl(bar0 + 0x8c2c0); -+ writel(cya0 & ~(1U << 2), bar0 + 0x8c2c0); -+ link_config = readl(bar0 + 0x8c040); -+ writel((link_config & ~0x000c0000U) | (2U << 18), bar0 + 0x8c040); -+ writel(0x00000006U, bar0 + 0x8872c); -+ (void)readl(bar0 + 0x8872c); -+ iounmap(bar0); -+ msleep(50); -+ ret = pcie_capability_read_word(gpu, PCI_EXP_LNKCTL2, &gpu_ctl2); -+ if (ret) -+ goto capability_error; -+ ret = pcie_capability_read_word(upstream, PCI_EXP_LNKCTL2, &upstream_ctl2); -+ if (ret) -+ goto capability_error; -+ gpu_ctl2 = (gpu_ctl2 & ~PCI_EXP_LNKCTL2_TLS) | PCI_EXP_LNKCTL2_TLS_5_0GT; -+ upstream_ctl2 = (upstream_ctl2 & ~PCI_EXP_LNKCTL2_TLS) | PCI_EXP_LNKCTL2_TLS_5_0GT; -+ ret = pcie_capability_write_word(gpu, PCI_EXP_LNKCTL2, gpu_ctl2); -+ if (ret) -+ goto capability_error; -+ ret = pcie_capability_write_word(upstream, PCI_EXP_LNKCTL2, upstream_ctl2); -+ if (ret) -+ goto capability_error; -+ ret = pcie_capability_read_word(upstream, PCI_EXP_LNKCTL, &upstream_ctl); -+ if (ret) -+ goto capability_error; -+ ret = pcie_capability_write_word(upstream, PCI_EXP_LNKCTL, -+ upstream_ctl | PCI_EXP_LNKCTL_RL); -+ if (ret) -+ goto capability_error; -+ -+ for (attempt = 0; attempt < 20; attempt++) -+ { -+ msleep(100); -+ ret = pcie_capability_read_word(gpu, PCI_EXP_LNKSTA, &link_status); -+ if (!ret && -+ ((link_status & PCI_EXP_LNKSTA_CLS) >= PCI_EXP_LNKSTA_CLS_5_0GB)) -+ { -+ NV_DEV_PRINTF(NV_DBG_INFO, nv, "CMP Gen2: PCIe link trained to Gen%u\n", -+ link_status & PCI_EXP_LNKSTA_CLS); -+ return; -+ } -+ } -+ -+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, -+ "CMP Gen2: PCIe retrain completed without Gen2 link (status=0x%04x, ret=%d)\n", -+ link_status, ret); -+ return; -+capability_error: -+ NV_DEV_PRINTF(NV_DBG_ERRORS, nv, -+ "CMP Gen2: PCIe capability access failed (%d); skipping link retrain\n", ret); - } - - /* -@@ -1530,6 +1624,8 @@ - nv->flags |= NV_FLAG_PERSISTENT_SW_STATE; - } - -+ nv_cmp170hx_retrain_gen2(nv); -+ - /* Generate and cache the UUID for future callers */ - (void)rm_get_gpu_uuid_raw(sp, nv); - diff --git a/driver/patches/0010-mclk-overclock-post-gsp.patch b/driver/patches/0009-mclk-overclock-post-gsp.patch similarity index 92% rename from driver/patches/0010-mclk-overclock-post-gsp.patch rename to driver/patches/0009-mclk-overclock-post-gsp.patch index 94e232a..194effa 100644 --- a/driver/patches/0010-mclk-overclock-post-gsp.patch +++ b/driver/patches/0009-mclk-overclock-post-gsp.patch @@ -1,6 +1,6 @@ ---- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c -+++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c -@@ -5620,6 +5620,56 @@ +--- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:47:41.953643183 +0200 ++++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:47:45.933556620 +0200 +@@ -5435,6 +5435,56 @@ NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, kgspStartLogPolling(pGpu, pKernelGsp), done); diff --git a/install.sh b/install.sh index 6949a82..3d4f4b0 100755 --- a/install.sh +++ b/install.sh @@ -9,35 +9,26 @@ mkdir -p "${LOG_DIR}" LOG_FILE="${LOG_DIR}/install_$(date +%Y%m%d_%H%M%S).log" PROFILE_OVERRIDE="" -CONFIGURE_IOMMU=1 -CONFIGURE_GEN2_SERVICE=1 +CONFIGURE_IOMMU=0 MCLK_NDIV="" for arg in "$@"; do case "${arg}" in --profile=8gb|--profile=8GB) PROFILE_OVERRIDE="8gb" ;; --profile=10gb|--profile=10GB) PROFILE_OVERRIDE="10gb" ;; - --no-iommu) CONFIGURE_IOMMU=0 ;; - --no-gen2-service) CONFIGURE_GEN2_SERVICE=0 ;; + --iommu) CONFIGURE_IOMMU=1 ;; --mclk-ndiv=*) MCLK_NDIV="${arg#*=}" ;; -h|--help) cat <<'EOF' -Usage: sudo ./install.sh [--profile=8gb|10gb] [--no-iommu] [--no-gen2-service] - [--mclk-ndiv=N] +Usage: sudo ./install.sh [--profile=8gb|10gb] [--iommu] [--mclk-ndiv=N] --profile=8gb Force 8GB metadata label (geometry is still chosen per PCI ID) --profile=10gb Force 10GB metadata label (geometry is still chosen per PCI ID) - --no-iommu Do not touch the kernel command line (leave IOMMU settings alone) - --no-gen2-service - Do not install the early-boot PCIe Gen2 retrain service + --iommu Add iommu=pt to the kernel command line (see README for details) --mclk-ndiv=N HBM memory clock: set PLL multiplier (30-80), N * 27 MHz. Works on any VBIOS, on both 0x20C2 and 0x2082. Stock is 64 on 8GB 300W, 54 on 8GB 250W, 45 on 10GB. Without this flag the overclock patches are not applied at all. -By default the installer appends intel_iommu=on / amd_iommu=on plus iommu=pt to -the kernel command line so the IOMMU runs in passthrough mode. This takes effect -on the next reboot. - Without --profile, each unlockable GPU is classified by PCI device ID: 10de:20c2 → 8gb / 64GB unlock 10de:2082 → 10gb / 40GB unlock @@ -306,33 +297,7 @@ CMPUNLOCKER_MCLK_NDIV="${MCLK_NDIV}" \ "${SCRIPT_DIR}/driver/build.sh" ok "Patched modules installed (profile ${CARD_PROFILE})" -step "Step 5b/6: Configuring PCIe Gen2" -cat > /etc/modprobe.d/cmp-pcie-gen2.conf <<'EOF' -options nvidia NVreg_RegistryDwords="RmForceEnableGen2=1;RMPcieLinkSpeed=0x1" -EOF -ok "Wrote /etc/modprobe.d/cmp-pcie-gen2.conf" - -for legacy_unit in cmpretrain.service cmp-gen2-retrain.service; do - systemctl disable --now "${legacy_unit}" 2>/dev/null || true - systemctl reset-failed "${legacy_unit}" 2>/dev/null || true -done -rm -f /etc/systemd/system/cmpretrain.service \ - /etc/systemd/system/cmp-gen2-retrain.service \ - /usr/local/sbin/retrain.sh \ - /usr/local/sbin/cmp-gen2-retrain.sh -systemctl daemon-reload -ok "Removed legacy PCIe retrain helpers" - -if (( CONFIGURE_GEN2_SERVICE == 1 )); then - chmod +x "${SCRIPT_DIR}/tools/hammer.sh" \ - "${SCRIPT_DIR}/tools/service.sh" - "${SCRIPT_DIR}/tools/service.sh" install - ok "Early-boot Gen2 retrain service armed (not started in this session)" -else - warn "--no-gen2-service given; early-boot PCIe retraining is not installed" -fi - -step "Step 5c/6: Configuring IOMMU (passthrough)" +step "Step 5b/6: Configuring IOMMU (passthrough)" IOMMU_STATUS="skipped" IOMMU_PARAMS="" @@ -473,7 +438,7 @@ configure_iommu_kernel_cmdline() { } if (( CONFIGURE_IOMMU == 0 )); then - warn "--no-iommu given; leaving kernel command line untouched" + info "IOMMU: not requested (use --iommu to configure passthrough)" else IOMMU_PARAMS="$(iommu_params_for_cpu)" if [[ -z "${IOMMU_PARAMS}" ]]; then @@ -532,10 +497,8 @@ echo -e " 5. Unlock logs: ${CYAN}sudo dmesg | grep SEC2_DEBUG${NC}" if [[ -n "${MCLK_NDIV}" ]]; then echo -e " Memory clock logs: ${CYAN}sudo dmesg | grep HBMPLL_OC${NC} (expect NDIV=${MCLK_NDIV})" fi -echo -e " 6. Verify IOMMU after reboot: ${CYAN}cat /proc/cmdline${NC} and ${CYAN}ls /sys/class/iommu${NC}" -if (( CONFIGURE_GEN2_SERVICE == 1 )); then - echo -e " 7. Verify negotiated Gen2: ${CYAN}sudo ./tools/service.sh verify${NC}" - echo -e " Recovery boot option: ${CYAN}systemd.mask=gen2.service${NC}" +if [[ -n "${IOMMU_PARAMS}" && "${IOMMU_STATUS}" != "skipped" ]]; then + echo -e " 6. Verify IOMMU after reboot: ${CYAN}cat /proc/cmdline${NC} and ${CYAN}ls /sys/class/iommu${NC}" fi echo "" echo "Log saved to: ${LOG_FILE}" diff --git a/systemd/gen2.service b/systemd/gen2.service deleted file mode 100644 index fae8005..0000000 --- a/systemd/gen2.service +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=CMP 170HX early-boot PCIe Gen2 retrain -DefaultDependencies=no -After=sysinit.target -Before=basic.target multi-user.target graphical.target -ConditionPathExists=/usr/local/sbin/gen2-hammer - -[Service] -Type=oneshot -ExecStart=/usr/local/sbin/gen2-hammer -TimeoutStartSec=45 -RemainAfterExit=no - -[Install] -WantedBy=sysinit.target diff --git a/tools/hammer.sh b/tools/hammer.sh deleted file mode 100755 index 2b914a1..0000000 --- a/tools/hammer.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash -# Early-boot PCIe Gen2 retrain loop for CMP 170HX (10de:20c2 / 10de:2082). -# -# The Gen2 capability the driver's probe-time patch exposes -# (driver/patches/0008-pcie-gen2-probe-retrain.patch) is only open for a -# short window during GSP bootstrap. If the driver's own one-shot retrain -# misses that window, this script keeps requesting Gen2 from the GPU's -# upstream bridge every ~50ms until it lands or the attempt budget runs out. -# Installed/removed via tools/service.sh; runs as -# systemd/gen2.service before basic.target. -set -uo pipefail - -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -readonly VENDOR_ID="10de" -readonly LOG_FILE="/var/log/gen2.log" -readonly TARGET_GEN="${CMP170HX_GEN2_TARGET:-2}" -readonly MAX_ITERATIONS="${CMP170HX_GEN2_MAX_ITERATIONS:-600}" -readonly RETRAIN_INTERVAL="${CMP170HX_GEN2_RETRAIN_INTERVAL:-0.05}" - -log() { - local line - line="[$(date -Is)] $*" - echo "${line}" - echo "${line}" >> "${LOG_FILE}" 2>/dev/null || true -} - -read_link_status() { - setpci -s "$1" CAP_EXP+12.w 2>/dev/null || true -} - -link_generation() { - local status - status="$(read_link_status "$1")" - if [[ "${status}" =~ ^[[:xdigit:]]{4}$ ]]; then - echo $((0x${status} & 0x0f)) - else - echo "?" - fi -} - -is_supported_gpu() { - local bdf="$1" - local vendor device - [[ -r "/sys/bus/pci/devices/${bdf}/vendor" ]] || return 1 - [[ -r "/sys/bus/pci/devices/${bdf}/device" ]] || return 1 - vendor="$(<"/sys/bus/pci/devices/${bdf}/vendor")" - device="$(<"/sys/bus/pci/devices/${bdf}/device")" - [[ "${vendor,,}" == "0x${VENDOR_ID}" ]] || return 1 - [[ "${device,,}" == "0x20c2" || "${device,,}" == "0x2082" ]] -} - -upstream_bridge() { - local bdf="$1" - local parent - parent="$(basename "$(dirname "$(readlink -f "/sys/bus/pci/devices/${bdf}")")")" - [[ "${parent}" != "${bdf}" ]] || return 1 - [[ -e "/sys/bus/pci/devices/${parent}" ]] || return 1 - echo "${parent}" -} - -is_pci_bridge() { - local bdf="$1" - local class - [[ -r "/sys/bus/pci/devices/${bdf}/class" ]] || return 1 - class="$(<"/sys/bus/pci/devices/${bdf}/class")" - [[ "${class,,}" == 0x0604* ]] -} - -retrain_one() { - local gpu="$1" - local bridge status generation cap2 iteration initial - - if ! is_supported_gpu "${gpu}"; then - log "${gpu}: vendor/device guard failed; refusing to touch the device" - return 1 - fi - bridge="$(upstream_bridge "${gpu}" || true)" - if [[ -z "${bridge}" ]] || ! is_pci_bridge "${bridge}"; then - log "${gpu}: no valid upstream PCI bridge found; skipping" - return 1 - fi - - initial="$(link_generation "${gpu}")" - if [[ "${initial}" =~ ^[0-9]+$ ]] && (( initial >= TARGET_GEN )); then - log "${gpu}: already Gen${initial}; no retrain needed" - return 0 - fi - - log "${gpu}: start via upstream ${bridge}; initial Gen${initial}; target Gen${TARGET_GEN}" - for ((iteration = 1; iteration <= MAX_ITERATIONS; iteration++)); do - if ! is_supported_gpu "${gpu}"; then - log "${gpu}: disappeared during retrain; stopping immediately" - return 1 - fi - - # Preserve all unrelated bits; the endpoint may clamp this to Gen1 - # until the driver's probe-time patch briefly exposes Gen2. - setpci -s "${bridge}" CAP_EXP+30.w=0002:000f 2>/dev/null || true - setpci -s "${gpu}" CAP_EXP+30.w=0002:000f 2>/dev/null || true - - # Retraining must be initiated by the upstream bridge. - setpci -s "${bridge}" CAP_EXP+10.w=0020:0020 2>/dev/null || true - - status="$(read_link_status "${gpu}")" - if [[ "${status}" =~ ^[[:xdigit:]]{4}$ ]]; then - generation=$((0x${status} & 0x0f)) - if (( generation >= TARGET_GEN )); then - cap2="$(setpci -s "${gpu}" CAP_EXP+2c.l 2>/dev/null || echo unreadable)" - log "${gpu}: SUCCESS Gen${generation} at iteration ${iteration}; LnkSta=0x${status}; LnkCap2=0x${cap2}" - return 0 - fi - fi - sleep "${RETRAIN_INTERVAL}" - done - - generation="$(link_generation "${gpu}")" - log "${gpu}: no Gen2 window caught after ${MAX_ITERATIONS} attempts; final Gen${generation}" - return 1 -} - -main() { - local rc=0 - local -a gpus=() - - if [[ "${EUID}" -ne 0 ]]; then - echo "gen2-hammer must run as root" >&2 - exit 1 - fi - if [[ "${TARGET_GEN}" != "2" ]]; then - echo "Only Gen2 is supported by this safety-constrained helper" >&2 - exit 1 - fi - if ! [[ "${MAX_ITERATIONS}" =~ ^[1-9][0-9]*$ ]]; then - echo "CMP170HX_GEN2_MAX_ITERATIONS must be a positive integer" >&2 - exit 1 - fi - command -v lspci >/dev/null || { echo "lspci is required" >&2; exit 1; } - command -v setpci >/dev/null || { echo "setpci is required" >&2; exit 1; } - - : > "${LOG_FILE}" - log "early retrain started (attempts=${MAX_ITERATIONS}, interval=${RETRAIN_INTERVAL}s)" - - mapfile -t gpus < <( - for id in 20c2 2082; do - lspci -D -d "${VENDOR_ID}:${id}" 2>/dev/null | awk '{print $1}' - done - ) - if [[ ${#gpus[@]} -eq 0 ]]; then - log "no supported CMP 170HX found; nothing touched" - return 0 - fi - - for gpu in "${gpus[@]}"; do - retrain_one "${gpu}" || rc=1 - done - log "early retrain finished (rc=${rc})" - return "${rc}" -} - -main "$@" diff --git a/tools/retrain.sh b/tools/retrain.sh deleted file mode 100755 index 020566b..0000000 --- a/tools/retrain.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash -set -euo pipefail - -SYS=/sys/bus/pci/devices/0000:0a:00.0 -for i in $(seq 1 120); do - if [[ -e $SYS/resource0 ]] && nvidia-smi -L &>/dev/null; then - break - fi - sleep 1 -done -if ! nvidia-smi -L &>/dev/null; then - exit 0 -fi - -mem="$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null | head -1 | tr -d ' ' || true)" -if [[ -z "${mem}" || "${mem}" == "[N/A]" ]]; then - exit 0 -fi - -cur="$(nvidia-smi --query-gpu=pcie.link.gen.current --format=csv,noheader 2>/dev/null | head -1 | tr -d ' ' || true)" -if [[ "${cur}" == "2" ]]; then - exit 0 -fi - -max="$(nvidia-smi --query-gpu=pcie.link.gen.max --format=csv,noheader 2>/dev/null | head -1 | tr -d ' ' || true)" -if [[ "${max}" != "2" && "${max}" != "3" && "${max}" != "4" ]]; then - exit 0 -fi - -python3 - <<'PY' -import os, mmap, struct, time, subprocess - -GPU, UP = "0a:00.0", "09:01.0" -PATH = "/sys/bus/pci/devices/0000:0a:00.0/resource0" - -def run(cmd): - return subprocess.check_output(cmd, text=True).strip() - -def bar0_open(): - fd = os.open(PATH, os.O_RDWR | os.O_SYNC) - m = mmap.mmap(fd, os.path.getsize(PATH), access=mmap.ACCESS_WRITE) - return fd, m - -def r(m, off): - return struct.unpack_from(">2)&1} " - f"MAX={(link>>18)&3} CAP={cap:08x} XVE={xve:08x} MISC1={misc1:08x}" -) -if bar0 == 0xFFFFFFFF or cya == 0xFFFFFFFF: - print("retrain: BAR0 dead; skip") - m.close(); os.close(fd) - raise SystemExit(0) -if ((cya >> 2) & 1) != 0: - print("retrain: DIS_G2 still set; skip") - m.close(); os.close(fd) - raise SystemExit(0) -if (cap & 0xF) < 2: - print(f"retrain: Cap Gen{cap & 0xF}; skip") - m.close(); os.close(fd) - raise SystemExit(0) -m.close(); os.close(fd) - -for bdf in (UP, GPU): - cur = int(run(["setpci", "-s", bdf, "CAP_EXP+30.w"]), 16) - subprocess.check_call(["setpci", "-s", bdf, f"CAP_EXP+30.w={(cur & ~0xF) | 0x2:04x}"]) - print(f"retrain: TLS {bdf} {cur:04x} -> {run(['setpci','-s',bdf,'CAP_EXP+30.w'])}") - -time.sleep(0.2) -fd, m = bar0_open() -if r(m, 0) == 0xFFFFFFFF: - print("retrain: BAR0 dead after TLS; skip") - m.close(); os.close(fd) - raise SystemExit(0) - -w(m, 0x8C2C0, r(m, 0x8C2C0) & ~(1 << 2)) -w(m, 0x8C040, (r(m, 0x8C040) & ~0xC0000) | (2 << 18)) -time.sleep(0.05) -cya = r(m, 0x8C2C0) -mx = (r(m, 0x8C040) >> 18) & 3 -alive = r(m, 0) != 0xFFFFFFFF -print(f"retrain: post CYA={cya:08x} DIS_G2={(cya>>2)&1} MAX={mx} bar0={r(m,0):08x}") -m.close(); os.close(fd) - -if not alive or ((cya >> 2) & 1) != 0 or mx != 2: - print("retrain: preconditions failed; skip") - raise SystemExit(0) - -cur = int(run(["setpci", "-s", UP, "CAP_EXP+10.w"]), 16) -subprocess.check_call(["setpci", "-s", UP, f"CAP_EXP+10.w={(cur | 0x20):04x}"]) -time.sleep(2.0) - -sta = int(run(["setpci", "-s", GPU, "CAP_EXP+12.w"]), 16) -print(f"retrain: speed_after={sta & 0xF}") -PY diff --git a/tools/service.sh b/tools/service.sh deleted file mode 100755 index c775ca1..0000000 --- a/tools/service.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash -# Install/remove/verify the early-boot PCIe Gen2 retrain service -# (systemd/gen2.service + tools/hammer.sh). -# Wired into install.sh (Step 5b/6), remove.sh, and verify.sh. -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" -SERVICE_NAME="gen2.service" -SERVICE_SOURCE="${PROJECT_DIR}/systemd/${SERVICE_NAME}" -SERVICE_TARGET="/etc/systemd/system/${SERVICE_NAME}" -HAMMER_SOURCE="${SCRIPT_DIR}/hammer.sh" -HAMMER_TARGET="/usr/local/sbin/gen2-hammer" -LOG_FILE="/var/log/gen2.log" - -info() { echo "==> $*"; } -ok() { echo "✓ $*"; } -warn() { echo "! $*" >&2; } -die() { echo "✗ $*" >&2; exit 1; } - -usage() { - cat </dev/null | awk '{print $1}' - done -} - -link_generation() { - local status - status="$(setpci -s "$1" CAP_EXP+12.w 2>/dev/null || true)" - if [[ "${status}" =~ ^[[:xdigit:]]{4}$ ]]; then - echo $((0x${status} & 0x0f)) - else - echo "?" - fi -} - -install_service() { - local module="/lib/modules/$(uname -r)/updates/cmpunlocker/nvidia.ko" - local -a gpus=() - - require_root - command -v install >/dev/null || die "install command not found" - command -v lspci >/dev/null || die "lspci not found (install pciutils)" - command -v setpci >/dev/null || die "setpci not found (install pciutils)" - [[ -f "${HAMMER_SOURCE}" ]] || die "Missing ${HAMMER_SOURCE}" - [[ -f "${SERVICE_SOURCE}" ]] || die "Missing ${SERVICE_SOURCE}" - - mapfile -t gpus < <(supported_gpus) - [[ ${#gpus[@]} -gt 0 ]] || die "No supported CMP 170HX found (10de:20c2 / 10de:2082)" - info "Detected: ${gpus[*]}" - - if [[ ! -f "${module}" ]]; then - die "Patched cmpunlocker module not found: ${module}" - fi - if ! grep -aFq 'CMP Gen2:' "${module}" 2>/dev/null; then - die "Installed module does not contain the Gen2 probe-retrain patch; refusing to arm a useless retrain service" - fi - ok "Installed NVIDIA module contains the Gen2 probe-retrain patch" - - install -m 0755 "${HAMMER_SOURCE}" "${HAMMER_TARGET}" - install -m 0644 "${SERVICE_SOURCE}" "${SERVICE_TARGET}" - systemctl daemon-reload - systemctl enable "${SERVICE_NAME}" >/dev/null - ok "Enabled ${SERVICE_NAME} for the next boot" - info "The service was not started now; the active desktop PCIe link was not touched." - info "Recovery boot option: systemd.mask=${SERVICE_NAME}" -} - -remove_service() { - require_root - systemctl disable --now "${SERVICE_NAME}" 2>/dev/null || true - rm -f "${SERVICE_TARGET}" "${HAMMER_TARGET}" - systemctl daemon-reload - systemctl reset-failed "${SERVICE_NAME}" 2>/dev/null || true - ok "Removed ${SERVICE_NAME}; cmpunlocker driver and memory unlock were left intact" - if [[ -f "${LOG_FILE}" ]]; then - info "Preserved diagnostic log: ${LOG_FILE}" - fi -} - -show_status() { - if [[ -f "${SERVICE_TARGET}" ]]; then - ok "Service file installed: ${SERVICE_TARGET}" - else - warn "Service file is not installed" - fi - systemctl is-enabled "${SERVICE_NAME}" 2>/dev/null || true - systemctl status "${SERVICE_NAME}" --no-pager 2>/dev/null || true -} - -verify_links() { - local gpu bridge status generation speed width max_speed result - local failures=0 - local -a gpus=() - - require_root - mapfile -t gpus < <(supported_gpus) - [[ ${#gpus[@]} -gt 0 ]] || die "No supported CMP 170HX found" - - printf '%-16s %-16s %-8s %-14s %-8s %s\n' "GPU" "Upstream" "LnkSta" "Current speed" "Width" "Result" - for gpu in "${gpus[@]}"; do - bridge="$(basename "$(dirname "$(readlink -f "/sys/bus/pci/devices/${gpu}")")")" - status="$(setpci -s "${gpu}" CAP_EXP+12.w 2>/dev/null || echo unreadable)" - generation="$(link_generation "${gpu}")" - speed="$(cat "/sys/bus/pci/devices/${gpu}/current_link_speed" 2>/dev/null || echo unknown)" - width="$(cat "/sys/bus/pci/devices/${gpu}/current_link_width" 2>/dev/null || echo unknown)" - max_speed="$(cat "/sys/bus/pci/devices/${gpu}/max_link_speed" 2>/dev/null || echo unknown)" - if [[ "${generation}" =~ ^[0-9]+$ ]] && (( generation >= 2 )); then - result="GEN2 OK" - else - result="GEN1" - failures=$((failures + 1)) - fi - printf '%-16s %-16s %-8s %-14s x%-7s %s\n' "${gpu}" "${bridge}" "0x${status}" "${speed}" "${width}" "${result}" - info "${gpu}: sysfs max=${max_speed}; negotiated generation is authoritative" - done - - if command -v nvidia-smi >/dev/null; then - echo - nvidia-smi --query-gpu=pci.bus_id,memory.total,pcie.link.gen.current,pcie.link.gen.max --format=csv 2>/dev/null || true - fi - - echo - if [[ -f "${LOG_FILE}" ]]; then - info "Last early-retrain log:" - tail -n 30 "${LOG_FILE}" - else - warn "No ${LOG_FILE}; the early service has not run yet" - fi - - if (( failures > 0 )); then - die "${failures} GPU(s) are still negotiated at Gen1" - fi - ok "All supported GPUs are negotiated at Gen2 or better" -} - -case "${1:-}" in - install) install_service ;; - remove) remove_service ;; - verify) verify_links ;; - status) show_status ;; - -h|--help|"") usage ;; - *) usage >&2; exit 1 ;; -esac diff --git a/verify.sh b/verify.sh index bcdac67..ea44a8c 100755 --- a/verify.sh +++ b/verify.sh @@ -202,12 +202,20 @@ fi echo "" ok "All ${#GPU_BDFS[@]} unlockable GPU(s) report unlocked memory" -if [[ -x "${SCRIPT_DIR}/tools/service.sh" ]]; then +pcie_info="$(nvidia-smi --query-gpu=pci.bus_id,pcie.link.gen.current --format=csv,noheader 2>/dev/null || true)" +if [[ -n "${pcie_info}" ]]; then echo "" - info "Checking negotiated PCIe generation" - if ! "${SCRIPT_DIR}/tools/service.sh" verify; then - warn "Memory unlock is healthy, but PCIe Gen2 is not active" - exit 1 - fi + info "PCIe link speed:" + while IFS=, read -r bus gen; do + bus="$(echo "${bus}" | tr -d '[:space:]')" + gen="$(echo "${gen}" | tr -d '[:space:]')" + if [[ "${gen}" == "2" ]]; then + ok "${bus}: Gen${gen}" + elif [[ "${gen}" == "1" ]]; then + warn "${bus}: Gen${gen} (Gen2 retrain may not have completed)" + else + info "${bus}: Gen${gen}" + fi + done <<< "${pcie_info}" fi exit 0 -- 2.51.2 From 982acf2c7cd69dcb67f013d4a044e69392d141ff Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 12:06:18 +0200 Subject: [PATCH 2/9] scrubbing the dogshit, day 2: now patches done right --- README.md | 70 +- benchmark/nvidia_bench | Bin 0 -> 1196568 bytes benchmark/nvidia_bench.cu | 1261 +++++++++++++++++ docs/ARCHITECTURE.md | 34 +- docs/DEBUGGING.md | 79 +- docs/INSTALLATION.md | 107 +- driver/build.sh | 145 +- driver/patches/0001-gsp-hooks.patch | 76 + .../patches/0001-sec2-postbl-plm-ss-cfg.patch | 474 ------- driver/patches/0002-booter-verify.patch | 87 -- driver/patches/0002-tu102-hook.patch | 20 + driver/patches/0003-late-pma.patch | 263 ---- .../patches/0003-osinit-late-pma-hook.patch | 19 + driver/patches/0004-bar0-pramin-clamp.patch | 20 - driver/patches/0004-memmgr-quirks.patch | 63 + driver/patches/0005-bar0-pramin-clamp.patch | 26 + .../patches/0005-ce-scrub-workarounds.patch | 38 - driver/patches/0006-persistent-sw-state.patch | 19 +- driver/patches/0007-pcie-gen2.patch | 73 - driver/patches/0008-mclk-overclock.patch | 147 -- .../0009-mclk-overclock-post-gsp.patch | 59 - driver/src/cmpunlock.c | 1016 +++++++++++++ driver/src/cmpunlock.h | 96 ++ driver/src/cmpunlock_config.h | 17 + install.sh | 13 +- remove.sh | 87 +- verify.sh | 221 --- 27 files changed, 2831 insertions(+), 1699 deletions(-) create mode 100755 benchmark/nvidia_bench create mode 100644 benchmark/nvidia_bench.cu create mode 100644 driver/patches/0001-gsp-hooks.patch delete mode 100644 driver/patches/0001-sec2-postbl-plm-ss-cfg.patch delete mode 100644 driver/patches/0002-booter-verify.patch create mode 100644 driver/patches/0002-tu102-hook.patch delete mode 100644 driver/patches/0003-late-pma.patch create mode 100644 driver/patches/0003-osinit-late-pma-hook.patch delete mode 100644 driver/patches/0004-bar0-pramin-clamp.patch create mode 100644 driver/patches/0004-memmgr-quirks.patch create mode 100644 driver/patches/0005-bar0-pramin-clamp.patch delete mode 100644 driver/patches/0005-ce-scrub-workarounds.patch delete mode 100644 driver/patches/0007-pcie-gen2.patch delete mode 100644 driver/patches/0008-mclk-overclock.patch delete mode 100644 driver/patches/0009-mclk-overclock-post-gsp.patch create mode 100644 driver/src/cmpunlock.c create mode 100644 driver/src/cmpunlock.h create mode 100644 driver/src/cmpunlock_config.h delete mode 100755 verify.sh diff --git a/README.md b/README.md index 40bcef8..627cbcb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # cmpunlocker -Unlock tool for the NVIDIA CMP 170HX (GA100) mining card. Restores full SM compute throughput and unlocked HBM2e memory geometry that are restricted in firmware/OTP configuration. - +Unlock tool for the NVIDIA CMP 170HX (GA100). Restores full SM compute, unlocked HBM2e memory geometry and PCIe Gen2 that are restricted in firmware/OTP configuration. **[Join our Discord community](https://discord.gg/CdHSakKSFv)** for support and discussions. @@ -22,40 +21,37 @@ Below are memory and performance results after applying the unlock: ## Requirements -- Linux (x86-64) +- Linux (x86-64 or aarch64) - Root access -- NVIDIA CMP 170HX +- NVIDIA CMP 170HX (8GB or 10GB) - **nvidia-open 610.43.0x already installed** (libs + firmware) - Kernel headers matching the running kernel (`linux-headers-$(uname -r)` / `kernel-devel`) - Secure Boot disabled (patched modules are unsigned) - Network access on first install (downloads matching stock `open-gpu-kernel-modules` sources) -- Python 3 (used at build time to select 8GB/10GB geometry) --- ## Install -To install cmpunlocker, run the following command: - ```bash sudo ./install.sh ``` -To force a certain memory profile, use the `--profile` option: +To force a certain memory profile: ```bash -sudo ./install.sh --profile=8gb # 8GB card → 64GB unlock -sudo ./install.sh --profile=10gb # 10GB card → 40GB unlock +sudo ./install.sh --profile=8gb # 8GB card -> 64GB unlock +sudo ./install.sh --profile=10gb # 10GB card -> 40GB unlock ``` Then perform a cold reboot (full power off, then boot). ### HBM Memory Clock -`--mclk-ndiv=N` sets the FBPA PLL multiplier; the resulting clock is `N × 27` MHz. Any VBIOS works, on both `0x20C2` (8GB) and `0x2082` (10GB) — the driver reads the stock NDIV out of the PLL and rewrites only that field, leaving MDIV/PDIV as the VBIOS programmed them. +`--mclk-ndiv=N` sets the FBPA PLL multiplier; the resulting clock is `N * 27` MHz. Any VBIOS works, on both `0x20C2` (8GB) and `0x2082` (10GB). ```bash -sudo ./install.sh --mclk-ndiv=70 # → 1890 MHz +sudo ./install.sh --mclk-ndiv=70 # 1890 MHz ``` | NDIV | Frequency | Notes | @@ -69,44 +65,64 @@ sudo ./install.sh --mclk-ndiv=70 # → 1890 MHz Values below stock downclock the card, which is the way to stabilise a card that fails at stock. -Without the flag, patches `0008` and `0009` are not applied at all. The multiplier is compiled into the modules, so changing it means re-running `install.sh`. In a mixed 8GB+10GB system the same multiplier lands on every card. +Without the flag the overclock is compiled out entirely. The multiplier is compiled into the modules, so changing it means re-running `install.sh`. In a mixed 8GB+10GB system the same multiplier lands on every card. If a value turns out to be unstable - reinstall without `--mclk-ndiv` (or run `./remove.sh`) from a working state. ### IOMMU -NVIDIA recommends `iommu=pt` (passthrough) for all GPUs. In this mode, DMA between the GPU and system memory bypasses IOMMU translation, avoiding extra latency and potential mapping errors. - -The installer does **not** touch the kernel command line by default. To have it add `iommu=pt` automatically: +NVIDIA recommends `iommu=pt` (passthrough) for all GPUs. The installer does **not** touch the kernel command line by default: ```bash sudo ./install.sh --iommu ``` -Or add `iommu=pt` to your kernel cmdline manually (via GRUB, systemd-boot, etc.). IOMMU must also be enabled in BIOS (VT-d on Intel, AMD-Vi / SVM on AMD). +Or add `iommu=pt` to your kernel cmdline manually. IOMMU must also be enabled in BIOS (VT-d on Intel, AMD-Vi / SVM on AMD). + +--- + +## Verify & Benchmark + +After install and cold reboot, run the built-in GPU benchmark: + +```bash +./benchmark/nvidia_bench +``` + +This measures memory bandwidth, tensor core throughput, PCIe speed, SM clock, and reports hardware features. An unlocked 8GB card should show ~64 GiB total memory and 56/70 SMs; a 10GB card should show ~40 GiB and 54/70 SMs. + +```bash +./benchmark/nvidia_bench 0 # test GPU 0 (default) +./benchmark/nvidia_bench --csv # machine-readable output +``` + +A pre-built x86-64 binary is included. On aarch64 (or to rebuild), install the CUDA toolkit and build from source: + +```bash +cd benchmark && nvcc -O3 -o nvidia_bench nvidia_bench.cu -lnvidia-ml -ldl \ + -gencode arch=compute_80,code=sm_80 && strip nvidia_bench +``` ## What Gets Unlocked | Feature | Status | |---|---| -| Full SM compute throughput (SS0/SS1) | Working ✓ | -| Memory geometry (64GB on 8GB cards, 40GB on 10GB cards) | Working ✓ | -| PCIe Gen 2 speeds | Working ✓ | -| HBM2 memory overclock/downclock | Working ✓ | -| Persistence across reboot (patched modules) | Working ✓ | +| Full SM compute throughput (SS0/SS1) | Working | +| Memory geometry (64GB on 8GB cards, 40GB on 10GB cards) | Working | +| PCIe Gen 2 speeds | Working | +| HBM2 memory overclock/downclock | Working | +| Persistence across reboot (patched modules) | Working | --- ## Uninstall -To uninstall cmpunlocker, run the following command: - ```bash -sudo ./uninstall.sh --yes +sudo ./remove.sh --yes ``` Then perform a cold reboot (full power off, then boot). -## Support & Community +## Community -Having issues? Need help? Join our [Discord community](https://discord.gg/CdHSakKSFv) to discuss with other users and get support. +Join our [Discord community](https://discord.gg/CdHSakKSFv) to discuss with other users. diff --git a/benchmark/nvidia_bench b/benchmark/nvidia_bench new file mode 100755 index 0000000000000000000000000000000000000000..c9924eda398dab047809382cd65e7a85f28d3c87 GIT binary patch literal 1196568 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

X&_%F8 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 W1Q{3@-az$(?}tVb2dPKmG5`P^PR$Ge literal 0 HcmV?d00001 diff --git a/benchmark/nvidia_bench.cu b/benchmark/nvidia_bench.cu new file mode 100644 index 0000000..5a02392 --- /dev/null +++ b/benchmark/nvidia_bench.cu @@ -0,0 +1,1261 @@ +/* + * nvidia_bench — GPU micro-benchmark: + * - memory latency (pointer chase, chain scaled to >= 16x L2, 128 B stride) + * - DRAM bandwidth (vectorized float4 read/write/copy/triad, cudaMemcpy D2D) + * - dense tensor-core throughput via WMMA: TF32 (FP32 inputs), BF16, INT8 + * (on Hopper/Blackwell datacenter parts WMMA can understate absolute + * peak — wgmma/tcgen05 paths are not used) + * - measured max SM boost clock + * - PCIe H2D/D2H bandwidth (pinned) + link config guess vs NVML readout + * - feature report: NVENC/NVDEC presence and engine counts (probed through + * the driver's libnvidia-encode/libnvcuvid rather than NVML's tables), + * MIG, ECC, NVLink, BAR1, copy engines, ... + * + * Minimum CUDA to build the source: 11.0 (WMMA TF32/BF16 and cuda_bf16.h; + * the CUDA-cores line needs 11.5+ headers and a R495+ driver — it is bound + * weakly and skipped when the driver lacks the symbol). The full build line + * below needs CUDA 12.8+ (compute_100/120 gencodes); CUDA 13.x cannot target + * Volta (sm_70) or older. NVML queries degrade gracefully on old drivers. + * + * Build: nvcc -O3 -o nvidia_bench nvidia_bench.cu -lnvidia-ml -ldl \ + -gencode arch=compute_75,code=sm_75 \ + -gencode arch=compute_80,code=sm_80 \ + -gencode arch=compute_86,code=sm_86 \ + -gencode arch=compute_89,code=sm_89 \ + -gencode arch=compute_90,code=sm_90 \ + -gencode arch=compute_100,code=sm_100 \ + -gencode arch=compute_120,code=sm_120 \ + -gencode arch=compute_120,code=compute_120 + * + * Run: ./nvidia_bench + ./nvidia_bench [gpu_id] [iterations] [--csv] + * iterations <= 0 (default) auto-sizes each timed run to ~1 s, which + * stays under the ~2 s display watchdog; compute tests keep a 100 ms + * floor. --csv prints one header line and one data line instead of the + * report. -h for usage help. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CUDART_VERSION) && CUDART_VERSION < 11000 +#error "nvidia_bench requires CUDA 11.0+ (WMMA TF32/BF16 fragments, cuda_bf16.h)" +#endif + +// nvmlDeviceGetNumGpuCores only exists in libnvidia-ml from driver R495; bind +// it weakly so older drivers skip the CUDA Cores line instead of dying with a +// dynamic-loader "undefined symbol" before any output. +#if defined(CUDART_VERSION) && CUDART_VERSION >= 11050 && defined(__GNUC__) +#pragma weak nvmlDeviceGetNumGpuCores +#define HAVE_NUM_GPU_CORES 1 +#endif + +#define CHECK_CUDA(call) do { \ + cudaError_t err = call; \ + if (err != cudaSuccess) { \ + fprintf(stderr, "CUDA Error at %s:%d - %s\n", __FILE__, __LINE__, cudaGetErrorString(err)); \ + if (err == cudaErrorLaunchTimeout) \ + fprintf(stderr, " The display watchdog killed a kernel. Re-run with a small explicit\n" \ + " iteration count, e.g. %s 20\n", "./nvidia_bench"); \ + exit(1); \ + } \ +} while(0) + +// --csv replaces the human-readable report with one header + one data line +static bool g_csv = false; +#define OUT(...) do { if (!g_csv) printf(__VA_ARGS__); } while (0) + +// ─── Vectorized float4 memory access kernels (128-bit / 16 bytes per thread) ─── + +// Read-Only: read float4 from global memory and reduce into scalar register +__global__ void bench_hbm_read(const float4 * __restrict__ A, float * __restrict__ dummy_out, size_t N_vec, int iters) { + size_t idx = blockIdx.x * blockDim.x + threadIdx.x; + size_t stride = blockDim.x * gridDim.x; + + float acc = 0.0f; + for (int iter = 0; iter < iters; iter++) { + for (size_t i = idx; i < N_vec; i += stride) { + float4 v = A[i]; + acc += v.x + v.y + v.z + v.w; + } + } + // A holds only positive values, so acc can never be -1.0f — but the compiler + // can't prove that, which keeps every thread's loads live + if (acc == -1.0f) dummy_out[0] = acc; +} + +// Write-Only: store float4 values to global memory +__global__ void bench_hbm_write(float4 * __restrict__ A, float4 val, size_t N_vec, int iters) { + size_t idx = blockIdx.x * blockDim.x + threadIdx.x; + size_t stride = blockDim.x * gridDim.x; + + for (int iter = 0; iter < iters; iter++) { + float4 v = val; + v.x += (float)iter; // distinct value each pass so passes can't be merged + for (size_t i = idx; i < N_vec; i += stride) { + A[i] = v; + } + } +} + +// Copy (D2D): dst[i] = src[i] (1 float4 read + 1 float4 write = 32 bytes traffic per element). +// Direction alternates each pass, so every store feeds the next pass's loads and +// no pass is a repeat of the previous one. +__global__ void bench_hbm_copy(float4 * __restrict__ A, float4 * __restrict__ B, size_t N_vec, int iters) { + size_t idx = blockIdx.x * blockDim.x + threadIdx.x; + size_t stride = blockDim.x * gridDim.x; + + for (int iter = 0; iter < iters; iter++) { + const float4 *src = (iter & 1) ? B : A; + float4 *dst = (iter & 1) ? A : B; + for (size_t i = idx; i < N_vec; i += stride) { + dst[i] = src[i]; + } + } +} + +// STREAM Triad: dst[i] = src[i] + alpha * B[i] (2 float4 reads + 1 float4 write = 48 bytes traffic per element). +// A and C swap roles each pass for the same reason as in bench_hbm_copy. +__global__ void bench_hbm_triad(float4 * __restrict__ A, const float4 * __restrict__ B, float4 * __restrict__ C, float alpha, size_t N_vec, int iters) { + size_t idx = blockIdx.x * blockDim.x + threadIdx.x; + size_t stride = blockDim.x * gridDim.x; + + for (int iter = 0; iter < iters; iter++) { + const float4 *src = (iter & 1) ? C : A; + float4 *dst = (iter & 1) ? A : C; + for (size_t i = idx; i < N_vec; i += stride) { + float4 a = src[i]; + float4 b = B[i]; + float4 c; + c.x = a.x + alpha * b.x; + c.y = a.y + alpha * b.y; + c.z = a.z + alpha * b.z; + c.w = a.w + alpha * b.w; + dst[i] = c; + } + } +} + +// ─── Memory latency kernel (Pointer Chasing / Stride) ─── +__global__ void bench_hbm_latency(const uint32_t * __restrict__ chain, uint32_t * __restrict__ out_idx, int steps) { + uint32_t idx = 0; + for (int i = 0; i < steps; i++) { + idx = chain[idx]; + } + out_idx[0] = idx; +} + +// Scatter the permutation into the padded chain: one slot per 128-byte cache line +// (stride 32 uint32_t), indices pre-scaled by 32 so the chase loop needs no math. +__global__ void build_chain(const uint32_t * __restrict__ perm, uint32_t * __restrict__ chain, size_t n_slots) { + size_t k = blockIdx.x * (size_t)blockDim.x + threadIdx.x; + size_t stride = (size_t)blockDim.x * gridDim.x; + for (; k < n_slots; k += stride) { + chain[k * 32] = perm[k] * 32u; + } +} + +// ─── Tensor core throughput kernels (WMMA) ─── +// Operands live in registers; each warp drives TC_ACC independent MMA +// accumulation chains so the tensor pipes stay saturated with no memory +// traffic. FLOPs are counted host-side as 2*M*N*K per mma_sync. +#define TC_ACC 4 + +__global__ void bench_tensor_tf32(float * __restrict__ dummy_out, int iters) { +#if __CUDA_ARCH__ >= 800 + using namespace nvcuda; + wmma::fragment a; + wmma::fragment b; + wmma::fragment c[TC_ACC]; + wmma::fill_fragment(a, 1.0f); + wmma::fill_fragment(b, 1.0f); + for (int k = 0; k < TC_ACC; k++) wmma::fill_fragment(c[k], 0.0f); + for (int i = 0; i < iters; i++) { +#pragma unroll + for (int k = 0; k < TC_ACC; k++) wmma::mma_sync(c[k], a, b, c[k]); + } + float sum = 0.0f; + for (int k = 0; k < TC_ACC; k++) + for (int e = 0; e < c[k].num_elements; e++) sum += c[k].x[e]; + // c accumulates only non-negative products, so sum can never be -1.0f — + // but the compiler can't prove that, which keeps the MMA chains live + if (sum == -1.0f) dummy_out[0] = sum; +#endif +} + +__global__ void bench_tensor_bf16(float * __restrict__ dummy_out, int iters) { +#if __CUDA_ARCH__ >= 800 + using namespace nvcuda; + wmma::fragment a; + wmma::fragment b; + wmma::fragment c[TC_ACC]; + wmma::fill_fragment(a, __float2bfloat16(1.0f)); + wmma::fill_fragment(b, __float2bfloat16(1.0f)); + for (int k = 0; k < TC_ACC; k++) wmma::fill_fragment(c[k], 0.0f); + for (int i = 0; i < iters; i++) { +#pragma unroll + for (int k = 0; k < TC_ACC; k++) wmma::mma_sync(c[k], a, b, c[k]); + } + float sum = 0.0f; + for (int k = 0; k < TC_ACC; k++) + for (int e = 0; e < c[k].num_elements; e++) sum += c[k].x[e]; + if (sum == -1.0f) dummy_out[0] = sum; +#endif +} + +__global__ void bench_tensor_int8(int * __restrict__ dummy_out, int iters) { +#if __CUDA_ARCH__ >= 720 + using namespace nvcuda; + wmma::fragment a; + wmma::fragment b; + wmma::fragment c[TC_ACC]; + wmma::fill_fragment(a, 1); + wmma::fill_fragment(b, 1); + for (int k = 0; k < TC_ACC; k++) wmma::fill_fragment(c[k], 0); + for (int i = 0; i < iters; i++) { +#pragma unroll + for (int k = 0; k < TC_ACC; k++) wmma::mma_sync(c[k], a, b, c[k]); + } + long long sum = 0; + for (int k = 0; k < TC_ACC; k++) + for (int e = 0; e < c[k].num_elements; e++) sum += c[k].x[e]; + if (sum == -1) dummy_out[0] = (int)sum; +#endif +} + +// ─── CUDA-core FMA throughput kernels ─── +// Each thread runs CC_CHAINS independent FMA dependency chains held in +// registers — enough ILP to saturate the pipes with no memory traffic. The +// multiplier/addend arrive as kernel arguments (not literals) and the +// recurrence x = x*b + c converges to a finite fixed point, so nothing folds +// at compile time and no value ever overflows. FLOPs are counted host-side as +// 2 per FMA (fp64/fp32) or 4 per packed half2 FMA. +#define CC_CHAINS 8 + +__global__ void bench_fp64_fma(double * __restrict__ out, double b, double c, int iters) { + double a[CC_CHAINS]; +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) a[k] = (double)(threadIdx.x + k); + for (int i = 0; i < iters; i++) { +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) a[k] = fma(a[k], b, c); + } + double sum = 0.0; +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) sum += a[k]; + // The chains converge to positive values, so sum can never be -1.0 — but + // the compiler can't prove it, which keeps every FMA live + if (sum == -1.0) out[0] = sum; +} + +__global__ void bench_fp32_fma(float * __restrict__ out, float b, float c, int iters) { + float a[CC_CHAINS]; +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) a[k] = (float)(threadIdx.x + k); + for (int i = 0; i < iters; i++) { +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) a[k] = fmaf(a[k], b, c); + } + float sum = 0.0f; +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) sum += a[k]; + if (sum == -1.0f) out[0] = sum; +} + +__global__ void bench_fp16_fma(__half * __restrict__ out, __half2 b, __half2 c, int iters) { +#if __CUDA_ARCH__ >= 530 + __half2 a[CC_CHAINS]; +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) + a[k] = __float2half2_rn((float)((threadIdx.x & 7) + k)); // stay well inside half range + for (int i = 0; i < iters; i++) { +#pragma unroll + for (int k = 0; k < CC_CHAINS; k++) a[k] = __hfma2(a[k], b, c); + } + __half2 s = a[0]; +#pragma unroll + for (int k = 1; k < CC_CHAINS; k++) s = __hadd2(s, a[k]); + float sf = __low2float(s) + __high2float(s); + if (sf == -1.0f) out[0] = __float2half(sf); +#endif +} + +// ─── SM clock measurement kernel ─── +// A single busy thread is the lightest load the boost governor sees, so it +// settles at the top clock bin; each segment derives the true SM frequency +// from clock64() cycles over %globaltimer nanoseconds (no NVML involved). +#define CLK_SEGMENTS 12 +__global__ void bench_clock(unsigned long long * __restrict__ out_cycles, unsigned long long * __restrict__ out_ns, int seg_ms) { + for (int s = 0; s < CLK_SEGMENTS; s++) { + unsigned long long t0, t1; + asm volatile("mov.u64 %0, %%globaltimer;" : "=l"(t0)); + unsigned long long c0 = clock64(); + unsigned long long tgt = t0 + (unsigned long long)seg_ms * 1000000ull; + do { asm volatile("mov.u64 %0, %%globaltimer;" : "=l"(t1)); } while (t1 < tgt); + out_cycles[s] = clock64() - c0; + out_ns[s] = t1 - t0; + } +} + +// ─── NVENC/NVDEC hardware probes ─── +// Engine counts come from the driver's own video stacks instead of NVML's +// device table (which drivers may get wrong): a real NVENC session open - +// it fails with NO_ENCODE_DEVICE on encoder-less parts like GA100/H100 - plus +// NV_ENC_CAPS_NUM_ENCODER_ENGINES, and cuvidGetDecoderCaps' nNumNVDECs. +// The structs below are minimal ABI mirrors of nvEncodeAPI.h / cuviddec.h +// (Video Codec SDK headers are not shipped with the CUDA toolkit). Both +// libraries come with the driver but may be absent in containers, so every +// failure path degrades to "unknown". Requires an R455+ (API 11.0) driver. + +typedef struct { unsigned int Data1; unsigned short Data2, Data3; unsigned char Data4[8]; } nvb_guid; + +typedef struct { + uint32_t version; + uint32_t capsToQuery; + uint32_t reserved[62]; +} nvb_enc_caps_param; + +typedef struct { + uint32_t version; + uint32_t deviceType; // NV_ENC_DEVICE_TYPE_CUDA = 1 + void *device; // CUcontext + void *reserved; + uint32_t apiVersion; + uint32_t reserved1[253]; + void *reserved2[64]; +} nvb_enc_session_params; + +// NV_ENCODE_API_FUNCTION_LIST: 318 pointer slots after version/reserved; +// we only type the three slots we call (8, 28, 30 — stable since API 7) +typedef struct { + uint32_t version; + uint32_t reserved; + void *fn_a[7]; + int (*getEncodeCaps)(void *, nvb_guid, nvb_enc_caps_param *, int *); + void *fn_b[19]; + int (*destroyEncoder)(void *); + void *fn_c[1]; + int (*openSessionEx)(nvb_enc_session_params *, void **); + void *fn_d[288]; +} nvb_enc_function_list; + +#define NVB_ENCAPI_VERSION (11u | (0u << 24)) +#define NVB_ENC_STRUCT_VER(v) (NVB_ENCAPI_VERSION | ((v) << 16) | (0x7u << 28)) +#define NVB_ENC_CAPS_NUM_ENCODER_ENGINES 49 + +// Returns 1 = present (engines set if the driver can count them, else -1), +// 0 = absent, -1 = could not tell. Needs a current CUDA context. +static int probe_nvenc(int *engines) { + *engines = -1; + void *lib = dlopen("libnvidia-encode.so.1", RTLD_LAZY | RTLD_LOCAL); + if (!lib) return -1; + typedef int (*create_fn)(nvb_enc_function_list *); + typedef int (*ctxget_fn)(void **); + create_fn create = (create_fn)dlsym(lib, "NvEncodeAPICreateInstance"); + // cudart loads libcuda with RTLD_LOCAL, so its symbols are invisible via + // RTLD_DEFAULT — open it explicitly (already resident, refcount bump only) + void *cuda_lib = dlopen("libcuda.so.1", RTLD_LAZY | RTLD_LOCAL); + ctxget_fn ctxget = cuda_lib ? (ctxget_fn)dlsym(cuda_lib, "cuCtxGetCurrent") : NULL; + void *ctx = NULL; + int rc = -1; + if (create && ctxget && ctxget(&ctx) == 0 && ctx) { + nvb_enc_function_list fl; + memset(&fl, 0, sizeof(fl)); + fl.version = NVB_ENC_STRUCT_VER(2); + if (create(&fl) == 0 && fl.openSessionEx && fl.destroyEncoder) { + nvb_enc_session_params sp; + memset(&sp, 0, sizeof(sp)); + sp.version = NVB_ENC_STRUCT_VER(1); + sp.deviceType = 1; + sp.device = ctx; + sp.apiVersion = NVB_ENCAPI_VERSION; + void *enc = NULL; + int st = fl.openSessionEx(&sp, &enc); + if (st == 0 && enc) { + rc = 1; + if (fl.getEncodeCaps) { + nvb_guid h264 = { 0x6bc82762, 0x4e63, 0x4ca4, + { 0xaa, 0x85, 0x1e, 0x50, 0xf3, 0x21, 0xf6, 0xbf } }; + nvb_enc_caps_param cp; + memset(&cp, 0, sizeof(cp)); + cp.version = NVB_ENC_STRUCT_VER(1); + cp.capsToQuery = NVB_ENC_CAPS_NUM_ENCODER_ENGINES; + int val = 0; + if (fl.getEncodeCaps(enc, h264, &cp, &val) == 0 && val > 0) + *engines = val; + } + fl.destroyEncoder(enc); + } else if (st == 1 || st == 2) { + // NO_ENCODE_DEVICE / UNSUPPORTED_DEVICE — device-absence codes; + // INVALID_ENCODERDEVICE (3) is a handle error, kept as unknown + rc = 0; + } + } + } + if (cuda_lib) dlclose(cuda_lib); + dlclose(lib); + return rc; +} + +// CUVIDDECODECAPS mirror; older drivers simply leave the newer OUT fields zero +typedef struct { + int eCodecType; // cudaVideoCodec_H264 = 4 + int eChromaFormat; // cudaVideoChromaFormat_420 = 1 + unsigned int nBitDepthMinus8; + unsigned int reserved1[3]; + unsigned char bIsSupported; + unsigned char nNumNVDECs; + unsigned short nOutputFormatMask; + unsigned int nMaxWidth, nMaxHeight, nMaxMBCount; + unsigned short nMinWidth, nMinHeight; + unsigned char bIsHistogramSupported, nCounterBitDepth; + unsigned short nMaxHistogramBins; + unsigned char bIsDecodeStatsSupported, reserved4[3]; + unsigned int reserved3[9]; +} nvb_dec_caps; + +static int probe_nvdec(int *engines) { + *engines = -1; + void *lib = dlopen("libnvcuvid.so.1", RTLD_LAZY | RTLD_LOCAL); + if (!lib) return -1; + typedef int (*caps_fn)(nvb_dec_caps *); + caps_fn get_caps = (caps_fn)dlsym(lib, "cuvidGetDecoderCaps"); + int rc = -1; + if (get_caps) { + // Try H264 first, and double-check with HEVC before declaring absence + static const int codecs[2] = { 4, 8 }; + for (int c = 0; c < 2 && rc <= 0; c++) { + nvb_dec_caps caps; + memset(&caps, 0, sizeof(caps)); + caps.eCodecType = codecs[c]; + caps.eChromaFormat = 1; + if (get_caps(&caps) != 0) break; + if (caps.nNumNVDECs > 0) { rc = 1; *engines = caps.nNumNVDECs; } + else rc = caps.bIsSupported ? 1 : 0; + } + } + dlclose(lib); + return rc; +} + +static const char *pci_ids_paths[] = { + "/usr/share/hwdata/pci.ids", + "/usr/share/misc/pci.ids", + "/usr/local/share/pci.ids", + NULL +}; + +// Lookup device name from pci.ids database (e.g. "GA100 [CMP 170HX]") +static bool lookup_pci_device_name(unsigned int dev_id, char *out, size_t out_sz) { + FILE *f = NULL; + for (int i = 0; pci_ids_paths[i]; i++) { + f = fopen(pci_ids_paths[i], "r"); + if (f) break; + } + if (!f) return false; + + char line[512]; + bool in_nvidia = false; + char target[8]; + snprintf(target, sizeof(target), "\t%04x", dev_id); + + while (fgets(line, sizeof(line), f)) { + if (line[0] == '#' || line[0] == '\n') continue; + if (!in_nvidia) { + if (strncmp(line, "10de", 4) == 0) in_nvidia = true; + continue; + } + if (line[0] != '\t') break; + if (line[0] == '\t' && line[1] == '\t') continue; + if (strncasecmp(line, target, 5) == 0) { + char *name = line + 5; + while (*name == ' ') name++; + size_t len = strlen(name); + while (len > 0 && (name[len-1] == '\n' || name[len-1] == '\r')) len--; + if (len >= out_sz) len = out_sz - 1; + memcpy(out, name, len); + out[len] = '\0'; + fclose(f); + return true; + } + } + fclose(f); + return false; +} + +// Timed iteration count: explicit user value, or sized from a calibration +// sample so the run lasts ~kTargetMs. +static const double kTargetMs = 1000.0; +static int auto_iters(int user_iters, double per_iter_ms) { + if (user_iters > 0) return user_iters; + if (per_iter_ms <= 0.0) return 5; + double it = kTargetMs / per_iter_ms; + if (it < 1.0) it = 1.0; + if (it > 100000000.0) it = 100000000.0; + return (int)it; +} + +// One compute (tensor / CUDA-core FMA) iteration is ~1000x cheaper than one +// 512 MiB bandwidth sweep, so an explicit user count sized for the bandwidth +// kernels would leave those tests a microsecond timed window dominated by +// launch overhead and event resolution; floor the window at ~100 ms regardless. +static int compute_iters(int user_iters, double per_iter_ms) { + int it = auto_iters(user_iters, per_iter_ms); + if (per_iter_ms > 0.0 && (double)it * per_iter_ms < 100.0) { + double min_it = 100.0 / per_iter_ms; + it = min_it > 100000000.0 ? 100000000 : (int)min_it; + } + return it; +} + +void print_bar() { + OUT("─────────────────────────────────────────────────────────────────────────────\n"); +} + +// Runs one benchmark end to end: warm-up, calibration sample, then a timed run +// sized to ~kTargetMs (or to the user's explicit count). launch(n) must enqueue +// exactly n iterations of the work. Returns the timed run's duration in seconds +// and stores the iteration count it used. short_work floors the timed window at +// 100 ms, for kernels whose single iteration is far below event resolution. +template +static double run_timed(LaunchFn launch, int sample_iters, int user_iters, bool short_work, + cudaEvent_t start, cudaEvent_t stop, int *out_iters) { + float ms = 0.0f; + launch(sample_iters); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaDeviceSynchronize()); + CHECK_CUDA(cudaEventRecord(start)); + launch(sample_iters); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaEventRecord(stop)); + CHECK_CUDA(cudaEventSynchronize(stop)); + CHECK_CUDA(cudaEventElapsedTime(&ms, start, stop)); + double per_iter_ms = (double)ms / sample_iters; + int n = short_work ? compute_iters(user_iters, per_iter_ms) : auto_iters(user_iters, per_iter_ms); + CHECK_CUDA(cudaEventRecord(start)); + launch(n); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaEventRecord(stop)); + CHECK_CUDA(cudaEventSynchronize(stop)); + CHECK_CUDA(cudaEventElapsedTime(&ms, start, stop)); + *out_iters = n; + return (double)ms / 1000.0; +} + +// ─── CSV assembly (--csv) ─── +static char g_csv_buf[4096]; +static size_t g_csv_len = 0; + +// Appends one comma-separated field; a NULL format emits an empty field +static void csv_field(const char *fmt, ...) { + if (g_csv_len > 0 && g_csv_len < sizeof(g_csv_buf) - 1) g_csv_buf[g_csv_len++] = ','; + g_csv_buf[g_csv_len] = '\0'; + if (!fmt) return; + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(g_csv_buf + g_csv_len, sizeof(g_csv_buf) - g_csv_len, fmt, ap); + va_end(ap); + if (n > 0) { + g_csv_len += (size_t)n; + if (g_csv_len >= sizeof(g_csv_buf)) g_csv_len = sizeof(g_csv_buf) - 1; + } +} + +// Numeric field, left empty when the value was not measured (<= 0) +static void csv_num(double v, int prec) { + if (v > 0.0) csv_field("%.*f", prec, v); + else csv_field(NULL); +} + +static void usage(const char *prog) { + printf("Usage: %s [gpu_id] [iterations] [--csv]\n" + " gpu_id CUDA device index (default 0)\n" + " iterations explicit per-test iteration count; <= 0 (default) auto-sizes\n" + " each timed run to ~%.1f s (compute tests keep a 100 ms floor)\n" + " --csv one CSV header line + one data line instead of the report\n" + " -h, --help this text\n", prog, kTargetMs / 1000.0); +} + +int main(int argc, char **argv) { + size_t size_mb = 512; + int device = 0; + int iters = 0; // <= 0: auto-size each timed run to ~kTargetMs + + int positional = 0; + for (int i = 1; i < argc; i++) { + const char *a = argv[i]; + if (strcmp(a, "--csv") == 0) { g_csv = true; continue; } + if (strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) { usage(argv[0]); return 0; } + char *end = NULL; + long v = strtol(a, &end, 10); + if (*a == '\0' || *end != '\0') { + fprintf(stderr, a[0] == '-' ? "Error: unknown option '%s'\n\n" : "Error: '%s' is not an integer\n\n", a); + usage(argv[0]); + return 1; + } + if (v > INT_MAX) v = INT_MAX; + if (v < INT_MIN) v = INT_MIN; + if (positional == 0) device = (int)v; + else if (positional == 1) iters = (int)v; + else { + fprintf(stderr, "Error: too many arguments\n\n"); + usage(argv[0]); + return 1; + } + positional++; + } + + int dev_count = 0; + CHECK_CUDA(cudaGetDeviceCount(&dev_count)); + if (device < 0 || device >= dev_count) { + fprintf(stderr, "Error: GPU %d not found (%d GPU(s) available)\n", device, dev_count); + return 1; + } + cudaDeviceProp prop; + CHECK_CUDA(cudaGetDeviceProperties(&prop, device)); + // The primary context itself needs a few hundred MiB; say so plainly rather + // than reporting a bare "out of memory" from the first allocation + cudaError_t set_err = cudaSetDevice(device); + if (set_err == cudaErrorMemoryAllocation || set_err == cudaErrorDevicesUnavailable) { + fprintf(stderr, "Error: cannot create a CUDA context on GPU %d (%s)\n" + " The GPU is busy or nearly out of memory — another process is probably using it.\n", + device, cudaGetErrorString(set_err)); + return 1; + } + CHECK_CUDA(set_err); + + int l2_bytes = 0; + if (cudaDeviceGetAttribute(&l2_bytes, cudaDevAttrL2CacheSize, device) != cudaSuccess) l2_bytes = 0; + + // INT8 tensor-core probe, done before any real allocations: TU116/TU117 + // report CC 7.5 but have no tensor cores — the s8 IMMA path faults and no + // device property distinguishes them. A fault kills the context, so probe + // while there is nothing to lose and recover with cudaDeviceReset(). The + // result gates the INT8 test and feeds the Features report. Below sm_72 + // the kernel body is compiled out and a launch would succeed vacuously, + // so gate on the arch first. + bool int8_hw = false; + if (prop.major > 7 || (prop.major == 7 && prop.minor >= 2)) { + int *d_probe = NULL; + if (cudaMalloc(&d_probe, sizeof(int)) == cudaSuccess) { + bench_tensor_int8<<<1, 32>>>(d_probe, 1); + int8_hw = cudaGetLastError() == cudaSuccess && cudaDeviceSynchronize() == cudaSuccess; + if (int8_hw) { + CHECK_CUDA(cudaFree(d_probe)); + } else { + cudaGetLastError(); // clear the sticky fault + cudaDeviceReset(); // recover the context; d_probe dies with it + CHECK_CUDA(cudaSetDevice(device)); + } + } + } + + // NVML is best-effort (identification and clock info only): resolve the handle + // by PCI bus id — NVML indices are PCI-ordered and ignore CUDA_VISIBLE_DEVICES, + // so reusing the CUDA ordinal can address a different physical GPU. + bool nvml_inited = (nvmlInit() == NVML_SUCCESS); + bool nvml_ok = nvml_inited; + nvmlDevice_t nvml_dev = NULL; + if (nvml_ok) { + char pci_bus[32]; + nvml_ok = cudaDeviceGetPCIBusId(pci_bus, sizeof(pci_bus), device) == cudaSuccess + && nvmlDeviceGetHandleByPciBusId_v2(pci_bus, &nvml_dev) == NVML_SUCCESS; + } + + unsigned int nvml_cur_mhz = 0, nvml_max_mhz = 0; + if (nvml_ok) { + if (nvmlDeviceGetClockInfo(nvml_dev, NVML_CLOCK_MEM, &nvml_cur_mhz) != NVML_SUCCESS) nvml_cur_mhz = 0; + if (nvmlDeviceGetMaxClockInfo(nvml_dev, NVML_CLOCK_MEM, &nvml_max_mhz) != NVML_SUCCESS) nvml_max_mhz = 0; + } + int cuda_max_khz = 0; + if (cudaDeviceGetAttribute(&cuda_max_khz, cudaDevAttrMemoryClockRate, device) != cudaSuccess) cuda_max_khz = 0; + unsigned int mem_rated_mhz = nvml_max_mhz; + if ((unsigned int)(cuda_max_khz / 1000) > mem_rated_mhz) mem_rated_mhz = (unsigned int)(cuda_max_khz / 1000); + + unsigned int dev_id = 0; + char pci_name[256] = {0}; + bool has_pci_name = false; + if (nvml_ok) { + nvmlPciInfo_t pci; + if (nvmlDeviceGetPciInfo(nvml_dev, &pci) == NVML_SUCCESS) { + dev_id = (pci.pciDeviceId >> 16) & 0xFFFF; + has_pci_name = lookup_pci_device_name(dev_id, pci_name, sizeof(pci_name)); + } + } + + // MIG state feeds both the header and the feature report. Under MIG the + // NVML handle (physical die) and the CUDA device (slice) describe + // different things, so die-wide counters must not be mixed with slice SMs. + int mig_state = -1; // -1 unknown, 0 unsupported, 1 supported/off, 2 enabled +#ifdef NVML_DEVICE_MIG_ENABLE + if (nvml_ok) { + unsigned int mig_cur = 0, mig_pend = 0; + nvmlReturn_t mr = nvmlDeviceGetMigMode(nvml_dev, &mig_cur, &mig_pend); + if (mr == NVML_SUCCESS) mig_state = (mig_cur == NVML_DEVICE_MIG_ENABLE) ? 2 : 1; + else if (mr == NVML_ERROR_NOT_SUPPORTED) mig_state = 0; + } +#endif + + // Measured SM boost clock — taken here so the header can report it. Runs on + // an idle GPU, so a shorter ramp-up launch precedes the measured one to let + // the boost governor settle. Everything is timed on-device (clock64 cycles + // over %globaltimer ns), so no CUDA events are needed yet. The same window + // doubles as the memory-clock sample: read at idle the memory clock can sit + // in a low power state, and substituting the rated maximum (as this used to + // do) would mask a deliberate underclock. + double sm_meas_mhz = 0.0; + unsigned int sm_rated_mhz = 0, mem_load_mhz = 0; + if (nvml_ok && nvmlDeviceGetMaxClockInfo(nvml_dev, NVML_CLOCK_SM, &sm_rated_mhz) != NVML_SUCCESS) + sm_rated_mhz = 0; + unsigned long long *d_clk = NULL; + if (cudaMalloc(&d_clk, 2 * CLK_SEGMENTS * sizeof(unsigned long long)) == cudaSuccess) { + for (int pass = 0; pass < 2; pass++) { + bench_clock<<<1, 1>>>(d_clk, d_clk + CLK_SEGMENTS, pass == 0 ? 10 : 25); + CHECK_CUDA(cudaGetLastError()); + while (cudaStreamQuery(0) == cudaErrorNotReady) { + unsigned int c = 0; + if (nvml_ok && nvmlDeviceGetClockInfo(nvml_dev, NVML_CLOCK_MEM, &c) == NVML_SUCCESS && c > mem_load_mhz) + mem_load_mhz = c; + usleep(5000); + } + cudaGetLastError(); // discard the cudaErrorNotReady left by polling + CHECK_CUDA(cudaDeviceSynchronize()); + } + unsigned long long h_clk[2 * CLK_SEGMENTS]; + CHECK_CUDA(cudaMemcpy(h_clk, d_clk, sizeof(h_clk), cudaMemcpyDeviceToHost)); + CHECK_CUDA(cudaFree(d_clk)); + // Max over segments, discarding implausible ones: a segment interrupted + // by compute preemption (display GPUs) can resume with a discontinuous + // cycle counter, and max-of-segments would else select that outlier + for (int s = 0; s < CLK_SEGMENTS; s++) { + if (h_clk[CLK_SEGMENTS + s] == 0) continue; + double mhz = (double)h_clk[s] * 1000.0 / (double)h_clk[CLK_SEGMENTS + s]; + if (mhz > 5000.0) continue; + if (sm_rated_mhz > 0 && mhz > 1.25 * sm_rated_mhz) continue; + if (mhz > sm_meas_mhz) sm_meas_mhz = mhz; + } + } + unsigned int mem_clock_mhz = mem_load_mhz; // operating clock, sampled under load + bool mem_under_load = mem_clock_mhz > 0; + if (!mem_under_load) // no NVML: fall back to the rated figure + mem_clock_mhz = nvml_cur_mhz > mem_rated_mhz ? nvml_cur_mhz : mem_rated_mhz; + + // Size the test arrays to what is actually free: three of them plus the + // pinned staging block and the latency chain have to coexist + size_t free_b = 0, total_b = 0; + CHECK_CUDA(cudaMemGetInfo(&free_b, &total_b)); + size_t max_per_array = free_b / 2 / 3; // leave half the card for everything else + if (size_mb * 1024 * 1024 > max_per_array) { + size_t new_mb = (max_per_array >> 20) & ~(size_t)15; // round down to 16 MiB + if (new_mb < 16) { + fprintf(stderr, "Error: only %.0f MiB free on GPU %d, need at least ~300 MiB\n", + free_b / 1048576.0, device); + return 1; + } + fprintf(stderr, "Note: test buffers reduced to %zu MiB each (%.0f MiB free on GPU %d)\n", + new_mb, free_b / 1048576.0, device); + size_mb = new_mb; + } + + unsigned int gpu_cores = 0; +#ifdef HAVE_NUM_GPU_CORES + // Skipped under MIG: the NVML count covers the whole die, not the slice + if (nvml_ok && mig_state != 2 && nvmlDeviceGetNumGpuCores != NULL) { + if (nvmlDeviceGetNumGpuCores(nvml_dev, &gpu_cores) != NVML_SUCCESS) gpu_cores = 0; + } +#endif + + print_bar(); + OUT(" NVIDIA Performance And Memory Benchmark\n"); + print_bar(); + if (has_pci_name) + OUT(" GPU: %s [%04X] (%s)\n", prop.name, dev_id, pci_name); + else if (dev_id) + OUT(" GPU: %s [%04X]\n", prop.name, dev_id); + else + OUT(" GPU: %s\n", prop.name); + OUT(" SMs: %d\n", prop.multiProcessorCount); + if (gpu_cores > 0) { + if (gpu_cores % (unsigned int)prop.multiProcessorCount == 0) + OUT(" CUDA Cores: %u (%u per SM)\n", gpu_cores, gpu_cores / (unsigned int)prop.multiProcessorCount); + else + OUT(" CUDA Cores: %u\n", gpu_cores); + } + OUT(" Memory Bus Width: %d-bit\n", prop.memoryBusWidth); + if (l2_bytes > 0) + OUT(" L2 Cache: %.0f MiB\n", l2_bytes / 1048576.0); + if (sm_meas_mhz > 0.0) { + if (sm_rated_mhz > 0) + OUT(" SM Clock: %.0f MHz (measured, max %u MHz)\n", sm_meas_mhz, sm_rated_mhz); + else + OUT(" SM Clock: %.0f MHz (measured)\n", sm_meas_mhz); + } + double theo_bw = 0.0; + if (mem_clock_mhz > 0) { + if (mem_under_load && mem_rated_mhz > 0 && mem_rated_mhz != mem_clock_mhz) + OUT(" Memory Clock: %u MHz (under load, rated %u MHz)\n", mem_clock_mhz, mem_rated_mhz); + else if (mem_under_load) + OUT(" Memory Clock: %u MHz (under load)\n", mem_clock_mhz); + else + OUT(" Memory Clock: %u MHz (rated)\n", mem_clock_mhz); + theo_bw = (double)mem_clock_mhz * 2 * prop.memoryBusWidth / 8 / 1000; + OUT(" Theoretical BW: %.2f GB/s\n", theo_bw); + } else { + OUT(" Memory Clock: unknown\n"); + } + // Under MIG the CUDA device is a slice, so report the slice's memory rather + // than the die-wide NVML figure that would contradict the SM count above + unsigned long long total_mem = (unsigned long long)prop.totalGlobalMem; + if (nvml_ok && mig_state != 2) { + nvmlMemory_t mem_info; + memset(&mem_info, 0, sizeof(mem_info)); + if (nvmlDeviceGetMemoryInfo(nvml_dev, &mem_info) == NVML_SUCCESS && mem_info.total > 0) + total_mem = mem_info.total; + } + OUT(" Total Memory: %.2f GiB (%llu MiB)%s\n", total_mem / (1024.0 * 1024.0 * 1024.0), + total_mem / (1024 * 1024), mig_state == 2 ? " [MIG slice]" : ""); + OUT(" Test Buffer Size: %zu MiB per array\n", size_mb); + if (iters > 0) + OUT(" Kernel Iterations: %d\n", iters); + else + OUT(" Kernel Iterations: auto (~%.1f s per test)\n", kTargetMs / 1000.0); + print_bar(); + + size_t total_bytes = size_mb * 1024 * 1024; + size_t N_vec = total_bytes / sizeof(float4); + total_bytes = N_vec * sizeof(float4); // Align to exact multiple of sizeof(float4) + + // Configure grid geometry to maximize HBM memory controller utilization + int threads = 256; + int blocks = prop.multiProcessorCount * 16; + if ((size_t)blocks * threads > N_vec) blocks = (int)((N_vec + threads - 1) / threads); + + // Device memory allocation + float4 *d_A, *d_B, *d_C; + float *d_dummy; + CHECK_CUDA(cudaMalloc(&d_A, total_bytes)); + CHECK_CUDA(cudaMalloc(&d_B, total_bytes)); + CHECK_CUDA(cudaMalloc(&d_C, total_bytes)); + CHECK_CUDA(cudaMalloc(&d_dummy, 16)); // 16 B so double/half2 sinks fit too + + // Initialize buffers + CHECK_CUDA(cudaMemset(d_A, 0x3F, total_bytes)); + CHECK_CUDA(cudaMemset(d_B, 0x40, total_bytes)); + CHECK_CUDA(cudaDeviceSynchronize()); + + cudaEvent_t start, stop; + CHECK_CUDA(cudaEventCreate(&start)); + CHECK_CUDA(cudaEventCreate(&stop)); + int n = 0; + double secs = 0.0; + + // ─── PCIe ─── + // Pinned-memory transfers on the copy engines + size_t pcie_bytes = 256ull * 1024 * 1024; + if (pcie_bytes > total_bytes) pcie_bytes = total_bytes; + void *h_pinned = NULL; + if (cudaMallocHost(&h_pinned, pcie_bytes) != cudaSuccess) { + cudaGetLastError(); + pcie_bytes = 64ull * 1024 * 1024; + CHECK_CUDA(cudaMallocHost(&h_pinned, pcie_bytes)); + } + memset(h_pinned, 0x3F, pcie_bytes); + + unsigned int link_gen = 0, link_width = 0; + + // The link state is sampled from inside the timed run: ASPM parks an idle + // link at Gen1, so an idle-time readout can be misleading + secs = run_timed([&](int it) { + for (int i = 0; i < it; i++) + CHECK_CUDA(cudaMemcpyAsync(d_A, h_pinned, pcie_bytes, cudaMemcpyHostToDevice, 0)); + if (nvml_ok && it > 2) { + nvmlDeviceGetCurrPcieLinkGeneration(nvml_dev, &link_gen); + nvmlDeviceGetCurrPcieLinkWidth(nvml_dev, &link_width); + } + }, 1, 0, false, start, stop, &n); + double h2d_gbs = (double)pcie_bytes * n / 1e9 / secs; + OUT(" PCIe H2D Bandwidth: %8.2f GB/s (pinned, %zu MiB blocks)\n", h2d_gbs, pcie_bytes >> 20); + fflush(stdout); + + secs = run_timed([&](int it) { + for (int i = 0; i < it; i++) + CHECK_CUDA(cudaMemcpyAsync(h_pinned, d_A, pcie_bytes, cudaMemcpyDeviceToHost, 0)); + }, 1, 0, false, start, stop, &n); + double d2h_gbs = (double)pcie_bytes * n / 1e9 / secs; + OUT(" PCIe D2H Bandwidth: %8.2f GB/s\n", d2h_gbs); + CHECK_CUDA(cudaFreeHost(h_pinned)); + + { + // Effective per-lane GB/s after encoding. Gen1-5 lose ~12% more to + // framing tokens/TLP headers; Gen6 FLIT mode has no framing tokens + // (~6% headers only). When NVML reports the trained link, validate the + // measured bandwidth against it; otherwise guess the config from + // bandwidth alone (equal-product configs like Gen4 x8 == Gen5 x4 are + // inherently ambiguous — ties resolve to the lowest generation). + static const double lane_gbs[7] = { 0.0, 0.25, 0.5, 0.985, 1.969, 3.938, 7.375 }; + static const double gen_eff[7] = { 0.0, 0.88, 0.88, 0.88, 0.88, 0.88, 0.94 }; + double pcie_meas = h2d_gbs > d2h_gbs ? h2d_gbs : d2h_gbs; + if (link_gen > 0 && link_width > 0) { + OUT(" PCIe Link (NVML): Gen%u x%u\n", link_gen, link_width); + if (link_gen <= 6) { + double expected = lane_gbs[link_gen] * link_width * gen_eff[link_gen]; + if (pcie_meas > expected * 1.3) + OUT(" PCIe BW vs link: %.1fx the Gen%u x%u ceiling — non-PCIe path (NVLink-C2C?)\n", + pcie_meas / expected, link_gen, link_width); + else + OUT(" PCIe BW vs link: %.0f%% of ~%.2f GB/s expected for Gen%u x%u\n", + pcie_meas / expected * 100.0, expected, link_gen, link_width); + } + } else { + static const int widths[5] = { 1, 2, 4, 8, 16 }; + int bg = 1, bw = 1; + double berr = 1e30; + for (int g = 1; g <= 6; g++) + for (int w = 0; w < 5; w++) { + double eff = lane_gbs[g] * widths[w] * gen_eff[g]; + double err = eff > pcie_meas ? eff - pcie_meas : pcie_meas - eff; + if (err < berr) { berr = err; bg = g; bw = widths[w]; } + } + if (pcie_meas > lane_gbs[6] * 16 * gen_eff[6] * 1.3) + OUT(" PCIe BW suggests: beyond Gen6 x16 — non-PCIe interconnect (NVLink-C2C?)\n"); + else + OUT(" PCIe BW suggests: ~Gen%d x%d (%.2f GB/s effective)\n", + bg, bw, lane_gbs[bg] * bw * gen_eff[bg]); + } + } + print_bar(); + + // ─── Features ─── + char enc_s[24] = "unknown", dec_s[24] = "unknown", mig_s[24] = "unknown", + ecc_s[24] = "unknown", nvl_s[24] = "unknown", disp_s[24] = "unknown", + plim_s[24] = "unknown", bar1_s[24] = "unknown"; + // NVENC/NVDEC ground truth (presence + engine count) via the driver's own + // video libraries; NVML's device-table claims are only a fallback + int enc_engines = -1, dec_engines = -1; + int enc_probe = probe_nvenc(&enc_engines); + int dec_probe = probe_nvdec(&dec_engines); + if (enc_probe == 1) { + if (enc_engines > 0) + snprintf(enc_s, sizeof(enc_s), "yes (%d engine%s)", enc_engines, enc_engines == 1 ? "" : "s"); + else + snprintf(enc_s, sizeof(enc_s), "yes"); + } else if (enc_probe == 0) { + snprintf(enc_s, sizeof(enc_s), "no"); + } + if (dec_probe == 1) { + if (dec_engines > 0) + snprintf(dec_s, sizeof(dec_s), "yes (%d engine%s)", dec_engines, dec_engines == 1 ? "" : "s"); + else + snprintf(dec_s, sizeof(dec_s), "yes"); + } else if (dec_probe == 0) { + snprintf(dec_s, sizeof(dec_s), "no"); + } + if (nvml_ok) { + // NOT_SUPPORTED means the feature is absent; any other error means we + // could not tell and the label stays "unknown". Under MIG the codec + // utilization/capacity queries are disabled regardless of the engines, + // so NOT_SUPPORTED proves nothing there. + nvmlReturn_t r; + unsigned int v = 0, v2 = 0; + if (enc_probe < 0) { + r = nvmlDeviceGetEncoderCapacity(nvml_dev, NVML_ENCODER_QUERY_H264, &v); + if (r == NVML_SUCCESS) + snprintf(enc_s, sizeof(enc_s), "%s", v > 0 ? "yes" : "no"); + else if (r == NVML_ERROR_NOT_SUPPORTED && mig_state != 2) + snprintf(enc_s, sizeof(enc_s), "no"); + } + if (dec_probe < 0) { + r = nvmlDeviceGetDecoderUtilization(nvml_dev, &v, &v2); + if (r == NVML_SUCCESS) + snprintf(dec_s, sizeof(dec_s), "yes"); + else if (r == NVML_ERROR_NOT_SUPPORTED && mig_state != 2) + snprintf(dec_s, sizeof(dec_s), "no"); + } + if (mig_state == 2) snprintf(mig_s, sizeof(mig_s), "enabled"); + else if (mig_state == 1) snprintf(mig_s, sizeof(mig_s), "supported, off"); + else if (mig_state == 0) snprintf(mig_s, sizeof(mig_s), "no"); + nvmlEnableState_t cur, pend; + r = nvmlDeviceGetEccMode(nvml_dev, &cur, &pend); + if (r == NVML_SUCCESS) + snprintf(ecc_s, sizeof(ecc_s), "%s", cur == NVML_FEATURE_ENABLED ? "enabled" : "disabled"); + else if (r == NVML_ERROR_NOT_SUPPORTED) + snprintf(ecc_s, sizeof(ecc_s), "no"); + int nvlinks = 0; + for (unsigned int l = 0; l < NVML_NVLINK_MAX_LINKS; l++) { + nvmlEnableState_t st; + if (nvmlDeviceGetNvLinkState(nvml_dev, l, &st) == NVML_SUCCESS && st == NVML_FEATURE_ENABLED) + nvlinks++; + } + if (nvlinks > 0) + snprintf(nvl_s, sizeof(nvl_s), "yes (%d links)", nvlinks); + else + snprintf(nvl_s, sizeof(nvl_s), "no"); + if (nvmlDeviceGetDisplayActive(nvml_dev, &cur) == NVML_SUCCESS) + snprintf(disp_s, sizeof(disp_s), "%s", cur == NVML_FEATURE_ENABLED ? "yes" : "no"); + unsigned int mw = 0; + if (nvmlDeviceGetPowerManagementLimit(nvml_dev, &mw) == NVML_SUCCESS) + snprintf(plim_s, sizeof(plim_s), "%u W", mw / 1000); + nvmlBAR1Memory_t bar1; + memset(&bar1, 0, sizeof(bar1)); + if (nvmlDeviceGetBAR1MemoryInfo(nvml_dev, &bar1) == NVML_SUCCESS) { + if (bar1.bar1Total >= 1024ull * 1024 * 1024) + snprintf(bar1_s, sizeof(bar1_s), "%.1f GiB", bar1.bar1Total / (1024.0 * 1024.0 * 1024.0)); + else + snprintf(bar1_s, sizeof(bar1_s), "%.0f MiB", bar1.bar1Total / (1024.0 * 1024.0)); + } + } + OUT(" Features:\n"); + // CC 8.0+ always has tensor cores; CC 7.0/7.2 (Volta/Xavier) always does; + // CC 7.5 splits into TU10x (yes) vs TU116/117 (no), decided by the startup + // INT8 probe; below CC 7.0 there are none. + OUT(" Tensor Cores: %-14s NVENC: %s\n", + (prop.major >= 8 || (prop.major == 7 && (prop.minor < 5 || int8_hw))) ? "yes" : "no", enc_s); + OUT(" ECC: %-14s NVDEC: %s\n", ecc_s, dec_s); + OUT(" MIG: %-14s NVLink: %s\n", mig_s, nvl_s); + OUT(" Copy Engines: %-14d Managed Memory: %s\n", + prop.asyncEngineCount, prop.managedMemory ? "yes" : "no"); + OUT(" Coop Launch: %-14s Compute Preempt: %s\n", + prop.cooperativeLaunch ? "yes" : "no", prop.computePreemptionSupported ? "yes" : "no"); + OUT(" Display Active: %-14s Power Limit: %s\n", disp_s, plim_s); + OUT(" BAR1 Size: %s\n", bar1_s); + print_bar(); + + // ─── Memory Latency (Pointer Chasing) ─── + // One chain slot per 128-byte cache line, chain sized >= 16x L2 (min 512 MiB): + // a random walk over a footprint comparable to L2 partially hits cache and + // reads low (e.g. a 128 MiB chain under-reports ~5% at 32 MiB L2, up to ~2x + // on 96+ MiB L2 parts). + size_t chain_bytes = (size_t)l2_bytes * 16; + if (chain_bytes < 512ull * 1024 * 1024) chain_bytes = 512ull * 1024 * 1024; + CHECK_CUDA(cudaMemGetInfo(&free_b, &total_b)); + while (chain_bytes > free_b / 2 && chain_bytes > 64ull * 1024 * 1024) chain_bytes /= 2; + if ((size_t)l2_bytes * 8 > chain_bytes) + fprintf(stderr, "Note: latency chain limited to %zu MiB (< 8x L2), latency may read low\n", + chain_bytes >> 20); + + size_t n_slots = chain_bytes / 128; + + uint32_t *h_perm = (uint32_t *)malloc(n_slots * sizeof(uint32_t)); + if (!h_perm) { fprintf(stderr, "Error: host allocation of %zu MiB failed\n", (n_slots * sizeof(uint32_t)) >> 20); return 1; } + for (size_t i = 0; i < n_slots; i++) h_perm[i] = (uint32_t)i; + // Sattolo shuffle — single cycle visiting all slots + for (size_t i = n_slots - 1; i > 0; i--) { + size_t j = (size_t)rand() % i; + uint32_t tmp = h_perm[i]; h_perm[i] = h_perm[j]; h_perm[j] = tmp; + } + + uint32_t *d_perm, *d_chain, *d_out; + CHECK_CUDA(cudaMalloc(&d_perm, n_slots * sizeof(uint32_t))); + CHECK_CUDA(cudaMalloc(&d_chain, chain_bytes)); + CHECK_CUDA(cudaMalloc(&d_out, sizeof(uint32_t))); + CHECK_CUDA(cudaMemcpy(d_perm, h_perm, n_slots * sizeof(uint32_t), cudaMemcpyHostToDevice)); + free(h_perm); + build_chain<<>>(d_perm, d_chain, n_slots); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaDeviceSynchronize()); + CHECK_CUDA(cudaFree(d_perm)); + + // Hand-rolled rather than run_timed: the walk needs an L2 flush between the + // calibration pass and the measured one, and it scales steps, not iterations + float time_ms = 0.0f, sample_ms = 0.0f; + CHECK_CUDA(cudaEventRecord(start)); + bench_hbm_latency<<<1, 1>>>(d_chain, d_out, 1000000); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaEventRecord(stop)); + CHECK_CUDA(cudaEventSynchronize(stop)); + CHECK_CUDA(cudaEventElapsedTime(&sample_ms, start, stop)); + int lat_steps = 1000000; + if (iters <= 0) { + double s = kTargetMs / ((double)sample_ms / 1000000.0); + if (s < 1000000.0) s = 1000000.0; + if (s > 50000000.0) s = 50000000.0; + lat_steps = (int)s; + } + // The warmup walked the same path the timed run will take; stream the test + // buffer through L2 to evict that footprint (keeps clocks/TLB warm only) + CHECK_CUDA(cudaMemset(d_A, 0x3F, total_bytes)); + CHECK_CUDA(cudaDeviceSynchronize()); + CHECK_CUDA(cudaEventRecord(start)); + bench_hbm_latency<<<1, 1>>>(d_chain, d_out, lat_steps); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaEventRecord(stop)); + CHECK_CUDA(cudaEventSynchronize(stop)); + CHECK_CUDA(cudaEventElapsedTime(&time_ms, start, stop)); + double latency_ns = (double)time_ms * 1e6 / lat_steps; + OUT(" Memory Latency: %6.1f ns (chain %zu MiB, 128 B stride)\n", latency_ns, chain_bytes >> 20); + fflush(stdout); + + CHECK_CUDA(cudaFree(d_chain)); + CHECK_CUDA(cudaFree(d_out)); + + // ─── Memory Bandwidth ─── + secs = run_timed([&](int it) { bench_hbm_read<<>>(d_A, d_dummy, N_vec, it); }, + 5, iters, false, start, stop, &n); + double read_gbs = (double)total_bytes * n / 1e9 / secs; + OUT(" Global Read Bandwidth: %8.2f GB/s\n", read_gbs); + fflush(stdout); + + float4 val = make_float4(1.0f, 2.0f, 3.0f, 4.0f); + secs = run_timed([&](int it) { bench_hbm_write<<>>(d_A, val, N_vec, it); }, + 5, iters, false, start, stop, &n); + double write_gbs = (double)total_bytes * n / 1e9 / secs; + OUT(" Global Write Bandwidth: %8.2f GB/s\n", write_gbs); + fflush(stdout); + + secs = run_timed([&](int it) { bench_hbm_copy<<>>(d_A, d_B, N_vec, it); }, + 5, iters, false, start, stop, &n); + double copy_gbs = (double)total_bytes * 2 * n / 1e9 / secs; + OUT(" Global Copy Bandwidth: %8.2f GB/s\n", copy_gbs); + fflush(stdout); + + secs = run_timed([&](int it) { bench_hbm_triad<<>>(d_A, d_B, d_C, 2.5f, N_vec, it); }, + 5, iters, false, start, stop, &n); + double triad_gbs = (double)total_bytes * 3 * n / 1e9 / secs; + OUT(" Global Triad Bandwidth: %8.2f GB/s\n", triad_gbs); + fflush(stdout); + + // Intra-device cudaMemcpy runs as an SM copy kernel, not on the DMA engines, + // hence the honest label + secs = run_timed([&](int it) { + for (int i = 0; i < it; i++) + CHECK_CUDA(cudaMemcpyAsync(d_B, d_A, total_bytes, cudaMemcpyDeviceToDevice, 0)); + }, 1, 0, false, start, stop, &n); + double d2d_gbs = (double)total_bytes * 2 * n / 1e9 / secs; + OUT(" cudaMemcpy D2D BW: %8.2f GB/s\n", d2d_gbs); + print_bar(); + + // ─── CUDA Core Throughput ─── + // 32 warps/SM with 8 in-flight FMA chains each is far past what the FMA + // pipes need; calibration samples use 10000 iters because a single + // iteration is far below event resolution + int cc_blocks = prop.multiProcessorCount * 4; + int cc_threads = 256; + double cc_threads_total = (double)cc_blocks * cc_threads; + const int cc_sample = 10000; + + secs = run_timed([&](int it) { bench_fp64_fma<<>>((double *)d_dummy, 0.5, 1.0, it); }, + cc_sample, iters, true, start, stop, &n); + double fp64_tflops = cc_threads_total * n * CC_CHAINS * 2.0 / 1e12 / secs; + OUT(" FP64 (CUDA cores): %8.2f TFLOPS\n", fp64_tflops); + fflush(stdout); + + secs = run_timed([&](int it) { bench_fp32_fma<<>>(d_dummy, 0.5f, 1.0f, it); }, + cc_sample, iters, true, start, stop, &n); + double fp32_tflops = cc_threads_total * n * CC_CHAINS * 2.0 / 1e12 / secs; + OUT(" FP32 (CUDA cores): %8.2f TFLOPS\n", fp32_tflops); + fflush(stdout); + + double fp16_tflops = 0.0; + if (prop.major > 5 || (prop.major == 5 && prop.minor >= 3)) { + __half2 hb = __float2half2_rn(0.5f), hc = __float2half2_rn(1.0f); + secs = run_timed([&](int it) { bench_fp16_fma<<>>((__half *)d_dummy, hb, hc, it); }, + cc_sample, iters, true, start, stop, &n); + // 4 FLOP per packed half2 FMA (2 lanes x multiply-add) + fp16_tflops = cc_threads_total * n * CC_CHAINS * 4.0 / 1e12 / secs; + OUT(" FP16 (CUDA cores): %8.2f TFLOPS\n", fp16_tflops); + } else { + OUT(" FP16 (CUDA cores): n/a (requires sm_53+)\n"); + } + fflush(stdout); + + // ─── Tensor Core Throughput ─── + int tc_blocks = prop.multiProcessorCount * 6; + int tc_threads = 256; + double tc_warps = (double)tc_blocks * tc_threads / 32.0; + const int tc_sample = 10000; + + double tf32_tflops = 0.0, bf16_tflops = 0.0, int8_tops = 0.0; + if (prop.major >= 8) { + secs = run_timed([&](int it) { bench_tensor_tf32<<>>(d_dummy, it); }, + tc_sample, iters, true, start, stop, &n); + tf32_tflops = tc_warps * n * TC_ACC * (2.0 * 16 * 16 * 8) / 1e12 / secs; + OUT(" FP32 Tensor (TF32): %8.2f TFLOPS\n", tf32_tflops); + } else { + OUT(" FP32 Tensor (TF32): n/a (requires sm_80+)\n"); + } + fflush(stdout); + + if (prop.major >= 8) { + secs = run_timed([&](int it) { bench_tensor_bf16<<>>(d_dummy, it); }, + tc_sample, iters, true, start, stop, &n); + bf16_tflops = tc_warps * n * TC_ACC * (2.0 * 16 * 16 * 16) / 1e12 / secs; + OUT(" BF16 Tensor: %8.2f TFLOPS\n", bf16_tflops); + } else { + OUT(" BF16 Tensor: n/a (requires sm_80+)\n"); + } + fflush(stdout); + + // INT8 hardware presence was probed at startup (int8_hw) + if (int8_hw) { + secs = run_timed([&](int it) { bench_tensor_int8<<>>((int *)d_dummy, it); }, + tc_sample, iters, true, start, stop, &n); + int8_tops = tc_warps * n * TC_ACC * (2.0 * 16 * 16 * 16) / 1e12 / secs; + OUT(" INT8 Tensor: %8.2f TOPS\n", int8_tops); + } else if (prop.major > 7 || (prop.major == 7 && prop.minor >= 2)) { + OUT(" INT8 Tensor: n/a (no tensor cores)\n"); + } else { + OUT(" INT8 Tensor: n/a (requires sm_72+)\n"); + } + print_bar(); + + if (g_csv) { + printf("gpu,sms,cuda_cores,bus_bits,l2_mib,sm_clock_mhz,sm_clock_rated_mhz," + "mem_clock_mhz,mem_clock_rated_mhz,theo_bw_gbs,total_mem_gib,buffer_mib," + "lat_ns,read_gbs,write_gbs,copy_gbs,triad_gbs,d2d_gbs,h2d_gbs,d2h_gbs," + "pcie_gen,pcie_width,fp64_tflops,fp32_tflops,fp16_tflops," + "tf32_tflops,bf16_tflops,int8_tops,nvenc_engines,nvdec_engines\n"); + csv_field("\"%s\"", has_pci_name ? pci_name : prop.name); + csv_field("%d", prop.multiProcessorCount); + csv_num((double)gpu_cores, 0); + csv_field("%d", prop.memoryBusWidth); + csv_num(l2_bytes / 1048576.0, 0); + csv_num(sm_meas_mhz, 0); + csv_num((double)sm_rated_mhz, 0); + csv_num((double)mem_clock_mhz, 0); + csv_num((double)mem_rated_mhz, 0); + csv_num(theo_bw, 2); + csv_num(total_mem / (1024.0 * 1024.0 * 1024.0), 2); + csv_field("%zu", size_mb); + csv_num(latency_ns, 1); + csv_num(read_gbs, 2); + csv_num(write_gbs, 2); + csv_num(copy_gbs, 2); + csv_num(triad_gbs, 2); + csv_num(d2d_gbs, 2); + csv_num(h2d_gbs, 2); + csv_num(d2h_gbs, 2); + csv_num((double)link_gen, 0); + csv_num((double)link_width, 0); + csv_num(fp64_tflops, 2); + csv_num(fp32_tflops, 2); + csv_num(fp16_tflops, 2); + csv_num(tf32_tflops, 2); + csv_num(bf16_tflops, 2); + csv_num(int8_tops, 2); + if (enc_probe < 0) csv_field(NULL); else csv_field("%d", enc_probe == 0 ? 0 : (enc_engines > 0 ? enc_engines : 1)); + if (dec_probe < 0) csv_field(NULL); else csv_field("%d", dec_probe == 0 ? 0 : (dec_engines > 0 ? dec_engines : 1)); + printf("%s\n", g_csv_buf); + } + + // Cleanup + CHECK_CUDA(cudaFree(d_dummy)); + CHECK_CUDA(cudaFree(d_A)); + CHECK_CUDA(cudaFree(d_B)); + CHECK_CUDA(cudaFree(d_C)); + CHECK_CUDA(cudaEventDestroy(start)); + CHECK_CUDA(cudaEventDestroy(stop)); + if (nvml_inited) nvmlShutdown(); + + return 0; +} diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 0bc8a06..f739151 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -31,6 +31,31 @@ Instead of modifying OTP (which is physically locked), cmpunlocker intercepts th --- +## Code Layout + +The unlock is a single source file that is dropped into the stock driver tree, plus a handful of one-line hooks that call into it: + +``` +driver/ + src/ + cmpunlock.c all unlock logic + cmpunlock.h the hook interface + cmpunlock_config.h build-time options (regenerated by build.sh) + patches/ + 0001-gsp-hooks.patch kernel_gsp.c 6 hooks + 0002-tu102-hook.patch kernel_gsp_tu102.c 1 hook + 0003-osinit-late-pma-hook.patch osinit.c 1 hook + 0004-memmgr-quirks.patch mem_mgr*, mem_scrub 3 conditionals + 0005-bar0-pramin-clamp.patch kern_bus_gm107.c 1 conditional + 0006-persistent-sw-state.patch nv.c 1 conditional +``` + +`build.sh` copies `driver/src/*` into `src/nvidia/{src,inc}/kernel/gpu/cmpunlock/`, appends one `SRCS +=` line to `src/nvidia/srcs.mk`, then applies the patches. + +Keeping the logic out of the patches means editing the unlock is ordinary C editing, and moving to a new nvidia-open release only requires re-checking the hook insertion points rather than re-merging large diffs. Every hook is a no-op on non-CMP GPUs, so the patched modules stay safe on mixed systems. + +--- + ## Technical Components ### SEC2 Booter & PLM @@ -44,8 +69,8 @@ cmpunlocker: Expected dmesg output: ``` -SEC2_DEBUG: PLMs opening to 0xffffffff -SEC2_DEBUG: Executing unlock sequence... +CMPUNLOCK: PLM[0] WPR_CFG(0x1fa7cc) attempt=0 status=0x0 reg=0xfffff0ff +CMPUNLOCK: PLMs: FEAT=0xffffffff FBPA=0xffffffff WPR=0xffffffff WPR_CFG=0xfffff0ff ``` Booter status codes like `0x31` or `0xffff` during early PLM passes are often harmless if the final boot succeeds. @@ -64,7 +89,7 @@ The GPU memory controller is configured by two registers: - **CFG1**: Memory configuration register (address mapping, bank layout) - **LMR**: LM (Local Memory) Request register (capacity/geometry selector) -cmpunlocker writes both during the unlock sequence. Detection of 8GB vs 10GB happens at install time via Python script (reads `nvidia-smi` output). +cmpunlocker writes both during the unlock sequence. 8GB vs 10GB is decided at runtime from the PCI device ID (`0x20C2` / `0x2082`), so one build works on either card and on mixed systems. --- @@ -78,8 +103,7 @@ SS0 and SS1 are Suspension State registers that control which SM clusters are ac Expected dmesg output: ``` -SEC2_DEBUG: SS0 = 0xffffffff -SEC2_DEBUG: SS1 = 0xffffffff +CMPUNLOCK: POST-WRITE SS0=0x88888888 SS1=0x00000008 CFG1=0x02779000 LMR=0x0000020b (devId=0x20c2) ``` --- diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index d10d0ff..513096d 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -1,40 +1,39 @@ -# Debugging - -Before you go asking in the Discord for help, here is a FAQ you should take a look at: - ---- - -## "nvidia-smi: command not found" - -- The installer likely didn't run or even failed. Re-run `sudo ./install.sh` and cold reboot. - ---- - -## nvidia-smi shows 8192 or 10240 MiB (not 65536 or 40960) - -- All the PLMs must show `0xffffffff`. Run `sudo dmesg | grep SEC2_DEBUG`to confirm. - -- If this still persists, refer to the Discord protocol at the end of the document. - ---- - -## PCIe still at Gen1 after install - -- Confirm IOMMU passthrough mode is enabled. Depending on your operating system, enabling IOMMU passthrough can vary. - -- If this still persists, refer to the Discord protocol at the end of the document. - ---- - -## Discord protocol - -If you have tried the above steps and are still having issues, please follow these steps to get help in the [Discord community](https://discord.gg/CdHSakKSFv): - -1. Open a ticket in the #issue-support channel. - -2. Provide the following information in your ticket: - - Your operating system and version - - Your GPU model and driver version - - The output of `sudo dmesg | grep SEC2_DEBUG` - - Latest install log (if applicable) - +# Debugging + +--- + +## Show debug logs + +`sudo dmesg | grep CMPUNLOCK` + +--- + +## "nvidia-smi: command not found" + +Re-run `sudo ./install.sh` and cold reboot. + +--- + +## nvidia-smi shows 8192 or 10240 MiB (not 65536 or 40960) + +Check that all PLMs show `0xffffffff`: + +```bash +sudo dmesg | grep CMPUNLOCK +``` + +If memory is still stock after a cold reboot, open a Discord ticket (see below). + +--- + +## Running the benchmark + +```bash +./benchmark/nvidia_bench # default: GPU 0, auto-sized iterations +./benchmark/nvidia_bench 1 # test GPU 1 +./benchmark/nvidia_bench 0 50 # GPU 0, 50 iterations per test +./benchmark/nvidia_bench --csv # machine-readable output +``` + +A pre-built x86-64 binary is included. On aarch64, see the README for the build command. + diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 9f85ae2..981b683 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -1,53 +1,54 @@ -# Installation - -Here are the steps to install cmpunlocker on your system. - ---- - -## Requirements - -- NVIDIA CMP 170HX (8GB or 10GB) -- Linux operating system (Ubuntu, Debian, Fedora, etc.) -- Kernel headers matching the running kernel (linux-headers-$(uname -r) / kernel-devel) -- Python 3 -- **nvidia-open 610.43.0x already installed** (libs + firmware) -- Root access to the system (sudo privileges) -- Secure Boot disabled -- Network access on first install (downloads matching stock open-gpu-kernel-modules sources) - -## Install - -To install cmpunlocker, run the following command: - -```bash -sudo ./install.sh -``` - -To force a certain memory profile, use the `--profile` option: - -```bash -sudo ./install.sh --profile=8gb # 8GB card → 64GB unlock -sudo ./install.sh --profile=10gb # 10GB card → 40GB unlock -``` - -To change the HBM memory clock, use `--mclk-ndiv` (multiplier × 27 MHz, any VBIOS, -both `0x20C2` and `0x2082`): - -```bash -sudo ./install.sh --mclk-ndiv=70 # → 1890 MHz -``` - -See the README for the full table -and the recovery path if a value turns out unstable. - -Then perform a cold reboot (full power off, then boot). - -## Uninstall - -To uninstall cmpunlocker, run the following command: - -```bash -sudo ./uninstall.sh --yes -``` - -Then perform a cold reboot (full power off, then boot). +# Installation + +## Requirements + +- NVIDIA CMP 170HX (8GB or 10GB) +- Linux (x86-64 or aarch64) +- Kernel headers matching the running kernel (linux-headers-$(uname -r) / kernel-devel) +- **nvidia-open 610.43.0x already installed** (libs + firmware) +- Root access (sudo privileges) +- Secure Boot disabled +- Network access on first install (downloads matching stock open-gpu-kernel-modules sources) + +## Install + +```bash +sudo ./install.sh +``` + +To force a certain memory profile: + +```bash +sudo ./install.sh --profile=8gb # 8GB card -> 64GB unlock +sudo ./install.sh --profile=10gb # 10GB card -> 40GB unlock +``` + +To set the HBM memory clock (multiplier x 27 MHz, any VBIOS, both card variants): + +```bash +sudo ./install.sh --mclk-ndiv=70 # 1890 MHz +``` + +See the README for the full NDIV table and the recovery path if a value turns out unstable. + +Then perform a cold reboot (full power off, then boot). + +## Verify + +After reboot, run the built-in benchmark: + +```bash +./benchmark/nvidia_bench +``` + +This measures memory bandwidth, tensor core throughput, PCIe speed and reports hardware features. An unlocked 8GB card should show ~64 GiB total memory; a 10GB card should show ~40 GiB. + +A pre-built x86-64 binary is included. On aarch64, see the README for the build command. + +## Uninstall + +```bash +sudo ./remove.sh --yes +``` + +Then perform a cold reboot (full power off, then boot). diff --git a/driver/build.sh b/driver/build.sh index 49ad2ee..8713f35 100755 --- a/driver/build.sh +++ b/driver/build.sh @@ -6,6 +6,7 @@ mapfile -t SUPPORTED_VERSIONS < <(grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' "${SCRIPT_D DEFAULT_VERSION="${SUPPORTED_VERSIONS[0]:-}" VERSION="${CMPUNLOCKER_DRIVER_VERSION:-${DEFAULT_VERSION}}" PATCH_DIR="${SCRIPT_DIR}/patches" +CMPSRC_DIR="${SCRIPT_DIR}/src" BUILD_ROOT="${CMPUNLOCKER_BUILD_DIR:-${SCRIPT_DIR}/.build}" SRC_NAME="open-gpu-kernel-modules-${VERSION}" SRC_DIR="${BUILD_ROOT}/${SRC_NAME}" @@ -39,8 +40,8 @@ version_supported() { [[ -n "${VERSION}" ]] || die "No driver version set (driver/VERSION empty and CMPUNLOCKER_DRIVER_VERSION unset)" version_supported "${VERSION}" || die "Unsupported driver version '${VERSION}' (supported: ${SUPPORTED_VERSIONS[*]})" [[ -d "${PATCH_DIR}" ]] || die "Missing patches directory: ${PATCH_DIR}" +[[ -d "${CMPSRC_DIR}" ]] || die "Missing sources directory: ${CMPSRC_DIR}" [[ -d "${KSRC}" ]] || die "Kernel headers not found at ${KSRC}. Install linux-headers-${KVER} (or kernel-devel)." -command -v python3 &>/dev/null || die "python3 is required to apply the card memory profile" info "Building against open-gpu-kernel-modules ${VERSION}" mkdir -p "${BUILD_ROOT}" @@ -64,119 +65,69 @@ if [[ ! -d "${SRC_DIR}" ]]; then fi ok "Sources ready: ${SRC_DIR}" -info "Applying unlock patches..." -cd "${SRC_DIR}" -shopt -s nullglob -patches=("${PATCH_DIR}"/*.patch) -[[ ${#patches[@]} -gt 0 ]] || die "No patches found in ${PATCH_DIR}" MCLK_NDIV="${CMPUNLOCKER_MCLK_NDIV:-}" if [[ -n "${MCLK_NDIV}" ]]; then if ! [[ "${MCLK_NDIV}" =~ ^[0-9]+$ ]] || [[ "${MCLK_NDIV}" -lt 30 || "${MCLK_NDIV}" -gt 80 ]]; then die "CMPUNLOCKER_MCLK_NDIV must be an integer between 30 and 80 (got: '${MCLK_NDIV}')" fi fi -for p in "${patches[@]}"; do - base="$(basename "${p}")" - if [[ ("${base}" == "0008-mclk-overclock.patch" || "${base}" == "0009-mclk-overclock-post-gsp.patch") && -z "${MCLK_NDIV}" ]]; then - warn "Skipping ${base} (no --mclk-ndiv)" - continue - fi - info " ${base}" - patch -p1 < "${p}" -done -ok "All patches applied" + +# +# The unlock itself lives in driver/src/cmpunlock.c and is dropped into the +# tree as a new source file. The patches below only add the hook calls that +# reach it, which is why they are a few lines each. +# +info "Installing cmpunlock sources..." +CMP_SRC_DST="${SRC_DIR}/src/nvidia/src/kernel/gpu/cmpunlock" +CMP_INC_DST="${SRC_DIR}/src/nvidia/inc/kernel/gpu/cmpunlock" +mkdir -p "${CMP_SRC_DST}" "${CMP_INC_DST}" +install -m 0644 "${CMPSRC_DIR}/cmpunlock.c" "${CMP_SRC_DST}/cmpunlock.c" +install -m 0644 "${CMPSRC_DIR}/cmpunlock.h" "${CMP_INC_DST}/cmpunlock.h" if [[ -n "${MCLK_NDIV}" ]]; then - TU102_C="${SRC_DIR}/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c" - MCLK_GSP_C="${SRC_DIR}/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c" - sed -i "s/static const NvU32 newNdiv = [^;]\\+;/static const NvU32 newNdiv = ${MCLK_NDIV};/" "${TU102_C}" "${MCLK_GSP_C}" - for f in "${TU102_C}" "${MCLK_GSP_C}"; do - grep -q "static const NvU32 newNdiv = ${MCLK_NDIV};" "${f}" \ - || die "NDIV placeholder not substituted in $(basename "${f}") — patch and build.sh are out of sync" - done + cat > "${CMP_INC_DST}/cmpunlock_config.h" <> "${SRC_DIR}/src/nvidia/srcs.mk" +ok "cmpunlock sources installed" -SKIP_GEOMETRY_REWRITE=0 +info "Applying hook patches..." +cd "${SRC_DIR}" +shopt -s nullglob +patches=("${PATCH_DIR}"/*.patch) +[[ ${#patches[@]} -gt 0 ]] || die "No patches found in ${PATCH_DIR}" +for p in "${patches[@]}"; do + info " $(basename "${p}")" + patch -p1 < "${p}" +done +ok "All patches applied" + +# +# The geometry is selected at runtime from the PCI device ID (see +# cmpUnlockPreBoot / cmpUnlockFixStaticInfo), so the profile is only a label +# recorded for the install summary. +# +PROFILE="${CMPUNLOCKER_CARD_PROFILE:-8gb}" case "${PROFILE}" in - 8gb|8GB) - PROFILE="8gb" - CFG1="0x02779000" - LMR="0x0000020B" - FB_BYTES="0x0000001000000000" - UNLOCK_LABEL="64GB" - ;; - 10gb|10GB) - PROFILE="10gb" - CFG1="0x02669000" - LMR="0x0000028A" - FB_BYTES="0x0000000A00000000" - UNLOCK_LABEL="40GB" - ;; - mixed|MIXED) - PROFILE="mixed" - CFG1="0x02779000" - LMR="0x0000020B" - FB_BYTES="0x0000001000000000" - UNLOCK_LABEL="mixed" - SKIP_GEOMETRY_REWRITE=1 - ;; + 8gb|8GB) PROFILE="8gb"; UNLOCK_LABEL="64GB" ;; + 10gb|10GB) PROFILE="10gb"; UNLOCK_LABEL="40GB" ;; + mixed|MIXED) PROFILE="mixed"; UNLOCK_LABEL="mixed" ;; *) die "Unknown CMPUNLOCKER_CARD_PROFILE='${PROFILE}' (use 8gb, 10gb, or mixed)" ;; esac - -info "Applying memory profile ${PROFILE} (${UNLOCK_LABEL} geometry)..." - -if [[ "${SKIP_GEOMETRY_REWRITE}" -eq 1 ]]; then - info "mixed profile: runtime device-id geometry (no build-time CFG1/LMR rewrite)" -else - python3 - "${GSP_C}" "${CFG1}" "${LMR}" "${FB_BYTES}" "${UNLOCK_LABEL}" <<'PY' -import pathlib, re, sys -path, cfg1, lmr, fb, label = sys.argv[1:6] -text = pathlib.Path(path).read_text() -if ( - "SEC2_POSTBL_TIMING_CMP_170HX_8GB_PCI_DEVICE_ID" in text - and "SEC2_POSTBL_TIMING_CMP_170HX_10GB_PCI_DEVICE_ID" in text - and "0x02779000U" in text - and "0x02669000U" in text - and "0x0000001000000000ULL" in text - and "0x0000000A00000000ULL" in text -): - print(f"runtime device-id geometry (profile metadata={label})") - raise SystemExit(0) - -text2, n1 = re.subn( - r"(NvU32 cfg1Value = )0x[0-9A-Fa-f]+(U;)", - rf"\g<1>{cfg1}\g<2>", - text, - count=1, -) -text2, n2 = re.subn( - r"(NvU32 lmrValue\s*=\s*)0x[0-9A-Fa-f]+(U;)", - rf"\g<1>{lmr}\g<2>", - text2, - count=1, -) -text2, n3 = re.subn( - r"(NvU64 targetFbBytes = )0x[0-9A-Fa-f]+ULL;\s*/\*[^*]*\*/", - rf"\g<1>{fb}ULL; /* {label} */", - text2, - count=1, -) -if n1 != 1 or n2 != 1 or n3 != 1: - raise SystemExit( - f"geometry rewrite failed (cfg1={n1} lmr={n2} fb={n3}); check kernel_gsp.c markers" - ) -pathlib.Path(path).write_text(text2) -print(f"cfg1={cfg1} lmr={lmr} fb={fb} ({label})") -PY -fi -ok "Memory profile ${PROFILE}: unlock_geometry=${UNLOCK_LABEL}" +ok "Memory profile ${PROFILE}: unlock_geometry=${UNLOCK_LABEL} (chosen per PCI ID at runtime)" mkdir -p "${INSTALL_MOD_DIR}" printf '%s\n' "${VERSION}" > "${INSTALL_MOD_DIR}/driver_version" printf '%s\n' "${PROFILE}" > "${INSTALL_MOD_DIR}/card_profile" diff --git a/driver/patches/0001-gsp-hooks.patch b/driver/patches/0001-gsp-hooks.patch new file mode 100644 index 0000000..f64a82b --- /dev/null +++ b/driver/patches/0001-gsp-hooks.patch @@ -0,0 +1,76 @@ +--- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c ++++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c +@@ -102,6 +102,8 @@ + + #include "crashcat/crashcat_report.h" + ++#include "gpu/cmpunlock/cmpunlock.h" ++ + + struct MIG_CI_UPDATE_CALLBACK_PARAMS + { +@@ -4801,9 +4803,10 @@ + NV_ASSERT_OR_RETURN(pbRetry != NULL, NV_ERR_INVALID_ARGUMENT); + *pbRetry = NV_FALSE; + +- // Fail early if WPR2 is up ++ // Fail early if WPR2 is up (cmpunlock recovers from this instead) + if (kgspIsWpr2Up_HAL(pGpu, pKernelGsp) && +- (!pGpu->getProperty(pGpu, PDB_PROP_GPU_PREINITIALIZED_WPR_REGION))) ++ (!pGpu->getProperty(pGpu, PDB_PROP_GPU_PREINITIALIZED_WPR_REGION)) && ++ !cmpUnlockIsTarget(pGpu)) + { + NV_PRINTF(LEVEL_ERROR, "unexpected WPR2 already up, cannot proceed with booting GSP\n"); + NV_PRINTF(LEVEL_ERROR, "(the GPU is likely in a bad state and may need to be reset)\n"); +@@ -4821,6 +4824,8 @@ + // Setup arguments for bootstrapping GSP + NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kgspPrepareForBootstrap_HAL(pGpu, pKernelGsp, KGSP_BOOT_MODE_NORMAL)); + ++ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, cmpUnlockPreBoot(pGpu, pKernelGsp, pGspFw)); ++ + // Release the API lock if relaxed locking for parallel init is enabled + NvBool bRelaxedLocking = _kgspShouldRelaxGspInitLocking(pGpu); + if (bRelaxedLocking) +@@ -5164,6 +5169,8 @@ + goto done; + } + ++ cmpUnlockFixStaticInfo(pGpu, pKernelGsp); ++ + NV_ASSERT_OK_OR_GOTO(status, kgspInitGspTraceCrashBuffer(pGpu, pKernelGsp), done); + + // Set PDB properties as per data from GSP. +@@ -5174,6 +5181,8 @@ + + NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, kgspStartLogPolling(pGpu, pKernelGsp), done); + ++ cmpUnlockMclkPostGsp(pGpu, pKernelGsp); ++ + done: + pKernelGsp->bInInit = NV_FALSE; + +@@ -5682,7 +5691,7 @@ + // NOTE: align to 256 because that's the alignment needed for Booter DMA + NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, + memdescCreate(&pKernelGsp->pSignatureMemdesc, pGpu, +- NV_ALIGN_UP(pGspFw->signatureSize, 256), 256, ++ cmpUnlockSignatureSize(pGpu, NV_ALIGN_UP(pGspFw->signatureSize, 256)), 256, + NV_TRUE, ADDR_SYSMEM, NV_MEMORY_CACHED, flags)); + + memdescTagAlloc(status, +@@ -5694,8 +5703,13 @@ + (pSignatureVa != NULL) ? NV_OK : NV_ERR_INSUFFICIENT_RESOURCES, + fail_alloc); + +- portMemCopy(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), +- pGspFw->pSignatureData, pGspFw->signatureSize); ++ if (!cmpUnlockFillSignature(pGpu, pKernelGsp, pSignatureVa, ++ memdescGetSize(pKernelGsp->pSignatureMemdesc), ++ pGspFw->pSignatureData, pGspFw->signatureSize)) ++ { ++ portMemCopy(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), ++ pGspFw->pSignatureData, pGspFw->signatureSize); ++ } + + memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); + pSignatureVa = NULL; diff --git a/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch b/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch deleted file mode 100644 index 1a25b1e..0000000 --- a/driver/patches/0001-sec2-postbl-plm-ss-cfg.patch +++ /dev/null @@ -1,474 +0,0 @@ ---- a/src/nvidia/generated/g_kernel_gsp_nvoc.h 2026-07-07 18:23:15.000000000 +0200 -+++ b/src/nvidia/generated/g_kernel_gsp_nvoc.h 2026-07-31 00:43:24.962804310 +0200 -@@ -544,6 +544,8 @@ struct KernelGsp { - RM_RISCV_UCODE_DESC *pGspRmBootUcodeDesc; - MEMORY_DESCRIPTOR *pGspUCodeRadix3Descriptor; - MEMORY_DESCRIPTOR *pSignatureMemdesc; -+ NvU8 *pStockSignatureData; -+ NvU64 stockSignatureSize; - GspSystemInfo *pSystemInfo; - NvU32 regTableSize; - PACKED_REGISTRY_TABLE *pRegTable; ---- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-07 18:23:15.000000000 +0200 -+++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:43:51.261744520 +0200 -@@ -102,6 +102,23 @@ - - #include "crashcat/crashcat_report.h" - -+#define SEC2_POSTBL_TIMING_CMP_170HX_8GB_PCI_DEVICE_ID 0x20C2 -+#define SEC2_POSTBL_TIMING_CMP_170HX_10GB_PCI_DEVICE_ID 0x2082 -+#define SEC2_POSTBL_TIMING_SIGNATURE_SIZE 0x0000f800ULL -+#define SEC2_POSTBL_TIMING_FILL_DWORD 0x000004a7U -+#define SEC2_POSTBL_TIMING_DMEM_PATH "/lib/firmware/nvidia/ga100/gsp/dmem.bin" -+ -+NV_STATUS kgspSec2PostblTimingRefillPayload(OBJGPU *pGpu, KernelGsp *pKernelGsp, -+ NvU32 writeAddr, NvU32 writeValue); -+NV_STATUS kgspSec2PostblTimingRebuildStockSignature(OBJGPU *pGpu, KernelGsp *pKernelGsp); -+ -+static NvBool -+_kgspSec2PostblTimingEnabled(OBJGPU *pGpu) -+{ -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ return (devId == SEC2_POSTBL_TIMING_CMP_170HX_8GB_PCI_DEVICE_ID || -+ devId == SEC2_POSTBL_TIMING_CMP_170HX_10GB_PCI_DEVICE_ID); -+} - - struct MIG_CI_UPDATE_CALLBACK_PARAMS - { -@@ -4805,14 +4822,23 @@ _kgspBootGspRm(OBJGPU *pGpu, KernelGsp * - if (kgspIsWpr2Up_HAL(pGpu, pKernelGsp) && - (!pGpu->getProperty(pGpu, PDB_PROP_GPU_PREINITIALIZED_WPR_REGION))) - { -- NV_PRINTF(LEVEL_ERROR, "unexpected WPR2 already up, cannot proceed with booting GSP\n"); -- NV_PRINTF(LEVEL_ERROR, "(the GPU is likely in a bad state and may need to be reset)\n"); -- return NV_ERR_INVALID_STATE; -+ NV_PRINTF(LEVEL_WARNING, -+ "WPR2 already up before GSP boot; continuing for recovery\n"); - } - - // Populate WPR meta structure (requires knowing FB size on dGPU, which depends on GFW_BOOT) - NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kgspPopulateWprMeta_HAL(pGpu, pKernelGsp, pGspFw)); - -+ if (_kgspSec2PostblTimingEnabled(pGpu)) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: WPR meta fbSize=0x%016llx wprEnd=0x%016llx " -+ "heapSize=0x%016llx\n", -+ pKernelGsp->pWprMeta->fbSize, -+ pKernelGsp->pWprMeta->gspFwWprEnd, -+ pKernelGsp->pWprMeta->gspFwHeapSize); -+ } -+ - { - // If the new FB layout requires a scrubber ucode to scrub additional space, prepare it now - NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, _kgspPrepareScrubberImageIfNeeded(pGpu, pKernelGsp)); -@@ -4821,6 +4847,130 @@ _kgspBootGspRm(OBJGPU *pGpu, KernelGsp * - // Setup arguments for bootstrapping GSP - NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kgspPrepareForBootstrap_HAL(pGpu, pKernelGsp, KGSP_BOOT_MODE_NORMAL)); - -+ if (_kgspSec2PostblTimingEnabled(pGpu)) -+ { -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ NvU32 plmIdx, attempt; -+ NV_STATUS plmStatus; -+ -+ static const struct { NvU32 addr; NvU32 value; const char *name; } plmTable[] = { -+ { 0x001fa7ccU, 0xfffff0ffU, "WPR_CFG" }, -+ { 0x009a0148U, 0xffffffffU, "FBPA" }, -+ { 0x001fa7c4U, 0xffffffffU, "WPR" }, -+ { 0x00823804U, 0xffffffffU, "FEAT" }, -+ { 0x00088ff4U, 0xffffffffU, "XVE" }, -+ { 0x00088ab4U, 0xffffffffU, "XVE_B" }, -+ { 0x00088ff8U, 0xffffffffU, "XVE_C" }, -+ { 0x00823b00U, 0xffffffffU, "FEAT2" }, -+ { 0x008200fcU, 0xffffffffU, "OPT_PLM" }, -+ { 0x009a3c7cU, 0xffffffffU, "FBPA_PLL0" }, -+ { 0x009a3c80U, 0xffffffffU, "FBPA_PLL1" }, -+ { 0x009a3c84U, 0xffffffffU, "FBPA_PLL2" }, -+ { 0x00088fe8U, 0xffffffffU, "XVE_PLM" }, -+ { 0x00088fecU, 0xffffffffU, "XVE_CYA_PLM" }, -+ { 0x0008872cU, 0x0000000aU, "XVE_FUSE_OVR" }, -+ { 0x0008841cU, 0x4034ad00U, "XVE_CYA_SPD" }, -+ { 0x000880a8U, 0x00000002U, "XVE_TARGET" }, -+ }; -+ -+ NvU32 wpr2Lo = GPU_REG_RD32(pGpu, 0x001fa824U); -+ NvU32 wpr2Hi = GPU_REG_RD32(pGpu, 0x001fa828U); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: saved WPR2 lo=0x%08x hi=0x%08x\n", -+ wpr2Lo, wpr2Hi); -+ -+ for (plmIdx = 0; plmIdx < NV_ARRAY_ELEMENTS(plmTable); plmIdx++) -+ { -+ NvBool opened = NV_FALSE; -+ for (attempt = 0; attempt < 2 && !opened; attempt++) -+ { -+ GPU_REG_WR32(pGpu, 0x001fa824U, wpr2Lo); -+ GPU_REG_WR32(pGpu, 0x001fa828U, wpr2Hi); -+ -+ plmStatus = kgspSec2PostblTimingRefillPayload(pGpu, pKernelGsp, -+ plmTable[plmIdx].addr, plmTable[plmIdx].value); -+ if (plmStatus != NV_OK) -+ continue; -+ -+ plmStatus = kgspExecuteBooterLoad_HAL(pGpu, pKernelGsp, -+ memdescGetPhysAddr(pKernelGsp->pWprMetaDescriptor, AT_GPU, 0)); -+ -+ NvU32 regVal = GPU_REG_RD32(pGpu, plmTable[plmIdx].addr); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PLM[%u] %s(0x%x) attempt=%u status=0x%x reg=0x%08x\n", -+ plmIdx, plmTable[plmIdx].name, -+ plmTable[plmIdx].addr, attempt, plmStatus, regVal); -+ -+ if (regVal == plmTable[plmIdx].value) -+ opened = NV_TRUE; -+ } -+ if (!opened) -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: FAILED to open %s after 2 attempts\n", -+ plmTable[plmIdx].name); -+ } -+ -+ GPU_REG_WR32(pGpu, 0x001fa824U, wpr2Lo); -+ GPU_REG_WR32(pGpu, 0x001fa828U, wpr2Hi); -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PLMs: FEAT=0x%08x FBPA=0x%08x WPR=0x%08x WPR_CFG=0x%08x\n", -+ GPU_REG_RD32(pGpu, 0x00823804U), -+ GPU_REG_RD32(pGpu, 0x009a0148U), -+ GPU_REG_RD32(pGpu, 0x001fa7c4U), -+ GPU_REG_RD32(pGpu, 0x001fa7ccU)); -+ -+ { -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ NvU32 cfg1Value; -+ NvU32 lmrValue; -+ -+ if (devId == SEC2_POSTBL_TIMING_CMP_170HX_8GB_PCI_DEVICE_ID) -+ { -+ cfg1Value = 0x02779000U; -+ lmrValue = 0x0000020BU; -+ } -+ else -+ { -+ cfg1Value = 0x02669000U; -+ lmrValue = 0x0000028AU; -+ } -+ -+ GPU_REG_WR32(pGpu, 0x0082381cU, 0x88888888U); -+ GPU_REG_WR32(pGpu, 0x00823820U, 0x00000008U); -+ GPU_REG_WR32(pGpu, 0x009a0204U, cfg1Value); -+ GPU_REG_WR32(pGpu, 0x00100ce0U, lmrValue); -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: POST-WRITE SS0=0x%08x SS1=0x%08x " -+ "CFG1=0x%08x LMR=0x%08x (devId=0x%x)\n", -+ GPU_REG_RD32(pGpu, 0x0082381cU), -+ GPU_REG_RD32(pGpu, 0x00823820U), -+ GPU_REG_RD32(pGpu, 0x009a0204U), -+ GPU_REG_RD32(pGpu, 0x00100ce0U), -+ devId); -+ } -+ -+ plmStatus = kgspSec2PostblTimingRebuildStockSignature(pGpu, pKernelGsp); -+ if (plmStatus != NV_OK) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: rebuild stock signature failed: 0x%x\n", plmStatus); -+ return plmStatus; -+ } -+ -+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kgspPopulateWprMeta_HAL(pGpu, pKernelGsp, pGspFw)); -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: WPR meta updated fbSize=0x%016llx wprStart=0x%016llx " -+ "wprEnd=0x%016llx heapOffset=0x%016llx heapSize=0x%016llx\n", -+ pKernelGsp->pWprMeta->fbSize, -+ pKernelGsp->pWprMeta->gspFwWprStart, -+ pKernelGsp->pWprMeta->gspFwWprEnd, -+ pKernelGsp->pWprMeta->gspFwHeapOffset, -+ pKernelGsp->pWprMeta->gspFwHeapSize); -+ } -+ - // Release the API lock if relaxed locking for parallel init is enabled - NvBool bRelaxedLocking = _kgspShouldRelaxGspInitLocking(pGpu); - if (bRelaxedLocking) -@@ -5164,6 +5314,53 @@ kgspInitRm_IMPL - goto done; - } - -+ { -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ if (devId == SEC2_POSTBL_TIMING_CMP_170HX_8GB_PCI_DEVICE_ID || -+ devId == SEC2_POSTBL_TIMING_CMP_170HX_10GB_PCI_DEVICE_ID) -+ { -+ GspStaticConfigInfo *pGSCI = &pKernelGsp->gspStaticInfo; -+ NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS *pFbRegionInfoParams = -+ &pGSCI->fbRegionInfoParams; -+ NvU64 targetFbBytes = (devId == SEC2_POSTBL_TIMING_CMP_170HX_8GB_PCI_DEVICE_ID) -+ ? 0x0000001000000000ULL -+ : 0x0000000A00000000ULL; -+ NvU64 stockFbBytes = 0x0000000200000000ULL; -+ NvU32 numRegions = pFbRegionInfoParams->numFBRegions; -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: static-info BEFORE: fb_length=0x%llx numRegions=%u\n", -+ pGSCI->fb_length, numRegions); -+ -+ pGSCI->fb_length = targetFbBytes; -+ -+ if (numRegions > 0 && -+ numRegions <= NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_MAX_ENTRIES) -+ { -+ NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO *pLastRegion = -+ &pFbRegionInfoParams->fbRegion[numRegions - 1]; -+ NvU64 highLimit = targetFbBytes - 1; -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: last region[%u] base=0x%llx limit=0x%llx reserved=0x%llx\n", -+ numRegions - 1, pLastRegion->base, pLastRegion->limit, pLastRegion->reserved); -+ -+ if (pLastRegion->limit < highLimit) -+ { -+ pLastRegion->limit = highLimit; -+ pLastRegion->reserved = pLastRegion->limit - pLastRegion->base + 1; -+ pLastRegion->supportCompressed = NV_TRUE; -+ pLastRegion->supportISO = NV_TRUE; -+ pLastRegion->performance = 20; -+ } -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: static-info AFTER: fb_length=0x%llx last_limit=0x%llx\n", -+ pGSCI->fb_length, pLastRegion->limit); -+ } -+ } -+ } -+ - NV_ASSERT_OK_OR_GOTO(status, kgspInitGspTraceCrashBuffer(pGpu, pKernelGsp), done); - - // Set PDB properties as per data from GSP. -@@ -5662,6 +5859,84 @@ _kgspFreeBootBinaryImage - pKernelGsp->gspRmBootUcodeSize = 0; - } - -+static void -+_kgspSec2PostblTimingPutU32(NvU8 *pBuffer, NvU32 offset, NvU32 value) -+{ -+ pBuffer[offset + 0] = (NvU8)(value >> 0); -+ pBuffer[offset + 1] = (NvU8)(value >> 8); -+ pBuffer[offset + 2] = (NvU8)(value >> 16); -+ pBuffer[offset + 3] = (NvU8)(value >> 24); -+} -+ -+static void -+_kgspSec2PostblTimingFillPayload(NvU8 *pSignatureVa, NvU64 signatureSize, -+ NvU32 writeAddr, NvU32 writeValue) -+{ -+ NvU64 i; -+ -+ for (i = 0; i + sizeof(NvU32) <= signatureSize; i += sizeof(NvU32)) -+ _kgspSec2PostblTimingPutU32(pSignatureVa, (NvU32)i, SEC2_POSTBL_TIMING_FILL_DWORD); -+ -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0x1100, 0x00000007U); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0x5b40, 0xc0deca7eU); -+ -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf754, writeValue); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf758, 0xc0deca7eU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf75c, 0x00000cbdU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf76c, writeAddr); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf774, 0x00001fbdU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf780, 0x00000000U); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf788, 0x000010aaU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf78c, 0x0000815aU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf790, 0x00008e18U); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf794, 0xc0deca7eU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf798, 0x0000815aU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf79c, 0x00000000U); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7a0, 0xc0deca7eU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7a4, 0x00001fbdU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7b0, 0x0000ffbcU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7b8, 0x0000582dU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7c4, 0xc0deca7eU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7c8, 0x00000cbdU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7d8, 0x00000003U); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7e0, 0x00001fbdU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7f4, 0x00000ccbU); -+ _kgspSec2PostblTimingPutU32(pSignatureVa, 0xf7f8, 0x00007f2fU); -+} -+ -+NV_STATUS -+kgspSec2PostblTimingRefillPayload(OBJGPU *pGpu, KernelGsp *pKernelGsp, -+ NvU32 writeAddr, NvU32 writeValue) -+{ -+ NvU8 *pSignatureVa; -+ -+ if (pKernelGsp->pSignatureMemdesc == NULL) -+ return NV_ERR_INVALID_STATE; -+ -+ pSignatureVa = memdescMapInternal(pGpu, pKernelGsp->pSignatureMemdesc, TRANSFER_FLAGS_NONE); -+ if (pSignatureVa == NULL) -+ return NV_ERR_INSUFFICIENT_RESOURCES; -+ -+ _kgspSec2PostblTimingFillPayload(pSignatureVa, -+ memdescGetSize(pKernelGsp->pSignatureMemdesc), writeAddr, writeValue); -+ -+ memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); -+ memdescFlushCpuCaches(pGpu, pKernelGsp->pSignatureMemdesc); -+ -+ if (pKernelGsp->pWprMeta != NULL) -+ { -+ pKernelGsp->pWprMeta->sysmemAddrOfSignature = -+ memdescGetPhysAddr(pKernelGsp->pSignatureMemdesc, AT_GPU, 0); -+ pKernelGsp->pWprMeta->sizeOfSignature = -+ memdescGetSize(pKernelGsp->pSignatureMemdesc); -+ } -+ -+ if (pKernelGsp->pWprMetaDescriptor != NULL) -+ memdescFlushCpuCaches(pGpu, pKernelGsp->pWprMetaDescriptor); -+ -+ return NV_OK; -+} -+ - static NV_STATUS - _kgspCreateSignatureMemdesc - ( -@@ -5672,6 +5947,9 @@ _kgspCreateSignatureMemdesc - { - NV_STATUS status = NV_OK; - NvU8 *pSignatureVa = NULL; -+ NvBool bPostbl = _kgspSec2PostblTimingEnabled(pGpu); -+ NvU64 sigSize = bPostbl ? SEC2_POSTBL_TIMING_SIGNATURE_SIZE -+ : NV_ALIGN_UP(pGspFw->signatureSize, 256); - NvU64 flags = MEMDESC_FLAGS_NONE; - - if (confComputeForceUnprotAlloc(pGpu)) -@@ -5682,7 +5960,7 @@ _kgspCreateSignatureMemdesc - // NOTE: align to 256 because that's the alignment needed for Booter DMA - NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, - memdescCreate(&pKernelGsp->pSignatureMemdesc, pGpu, -- NV_ALIGN_UP(pGspFw->signatureSize, 256), 256, -+ sigSize, 256, - NV_TRUE, ADDR_SYSMEM, NV_MEMORY_CACHED, flags)); - - memdescTagAlloc(status, -@@ -5694,8 +5972,48 @@ _kgspCreateSignatureMemdesc - (pSignatureVa != NULL) ? NV_OK : NV_ERR_INSUFFICIENT_RESOURCES, - fail_alloc); - -- portMemCopy(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), -- pGspFw->pSignatureData, pGspFw->signatureSize); -+ if (bPostbl) -+ { -+ NV_STATUS dmemStatus; -+ -+ if (pGspFw->pSignatureData != NULL && pGspFw->signatureSize > 0) -+ { -+ pKernelGsp->stockSignatureSize = pGspFw->signatureSize; -+ pKernelGsp->pStockSignatureData = portMemAllocNonPaged(pGspFw->signatureSize); -+ if (pKernelGsp->pStockSignatureData != NULL) -+ { -+ portMemCopy(pKernelGsp->pStockSignatureData, pGspFw->signatureSize, -+ pGspFw->pSignatureData, pGspFw->signatureSize); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: saved stock signature (%llu bytes)\n", -+ (unsigned long long)pGspFw->signatureSize); -+ } -+ } -+ -+ dmemStatus = os_open_and_read_file( -+ SEC2_POSTBL_TIMING_DMEM_PATH, pSignatureVa, sigSize); -+ if (dmemStatus == NV_OK) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: loaded %llu bytes from %s\n", -+ (unsigned long long)sigSize, SEC2_POSTBL_TIMING_DMEM_PATH); -+ } -+ else -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: %s not found (0x%x), using built-in payload\n", -+ SEC2_POSTBL_TIMING_DMEM_PATH, dmemStatus); -+ _kgspSec2PostblTimingFillPayload(pSignatureVa, -+ memdescGetSize(pKernelGsp->pSignatureMemdesc), -+ 0x009a0148U, 0xffffffffU); -+ } -+ memdescFlushCpuCaches(pGpu, pKernelGsp->pSignatureMemdesc); -+ } -+ else -+ { -+ portMemCopy(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), -+ pGspFw->pSignatureData, pGspFw->signatureSize); -+ } - - memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); - pSignatureVa = NULL; -@@ -5709,6 +6027,69 @@ fail_create: - memdescDestroy(pKernelGsp->pSignatureMemdesc); - pKernelGsp->pSignatureMemdesc = NULL; - -+ return status; -+} -+ -+NV_STATUS -+kgspSec2PostblTimingRebuildStockSignature(OBJGPU *pGpu, KernelGsp *pKernelGsp) -+{ -+ NV_STATUS status = NV_OK; -+ NvU8 *pSignatureVa = NULL; -+ NvU64 sigSize; -+ NvU64 flags = MEMDESC_FLAGS_NONE; -+ -+ if (pKernelGsp->pStockSignatureData == NULL || pKernelGsp->stockSignatureSize == 0) -+ return NV_ERR_INVALID_STATE; -+ -+ if (pKernelGsp->pSignatureMemdesc != NULL) -+ { -+ memdescFree(pKernelGsp->pSignatureMemdesc); -+ memdescDestroy(pKernelGsp->pSignatureMemdesc); -+ pKernelGsp->pSignatureMemdesc = NULL; -+ } -+ -+ sigSize = NV_ALIGN_UP(pKernelGsp->stockSignatureSize, 256); -+ flags |= MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY; -+ -+ NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, -+ memdescCreate(&pKernelGsp->pSignatureMemdesc, pGpu, -+ sigSize, 256, -+ NV_TRUE, ADDR_SYSMEM, NV_MEMORY_CACHED, flags)); -+ -+ memdescTagAlloc(status, -+ NV_FB_ALLOC_RM_INTERNAL_OWNER_UNNAMED_TAG_16, pKernelGsp->pSignatureMemdesc); -+ NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, status, rebuild_fail_create); -+ -+ pSignatureVa = memdescMapInternal(pGpu, pKernelGsp->pSignatureMemdesc, TRANSFER_FLAGS_NONE); -+ NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, -+ (pSignatureVa != NULL) ? NV_OK : NV_ERR_INSUFFICIENT_RESOURCES, -+ rebuild_fail_alloc); -+ -+ portMemCopy(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), -+ pKernelGsp->pStockSignatureData, pKernelGsp->stockSignatureSize); -+ -+ memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); -+ -+ if (pKernelGsp->pWprMeta != NULL) -+ { -+ pKernelGsp->pWprMeta->sysmemAddrOfSignature = -+ memdescGetPhysAddr(pKernelGsp->pSignatureMemdesc, AT_GPU, 0); -+ pKernelGsp->pWprMeta->sizeOfSignature = -+ memdescGetSize(pKernelGsp->pSignatureMemdesc); -+ } -+ -+ if (pKernelGsp->pWprMetaDescriptor != NULL) -+ memdescFlushCpuCaches(pGpu, pKernelGsp->pWprMetaDescriptor); -+ -+ return NV_OK; -+ -+rebuild_fail_alloc: -+ memdescFree(pKernelGsp->pSignatureMemdesc); -+ -+rebuild_fail_create: -+ memdescDestroy(pKernelGsp->pSignatureMemdesc); -+ pKernelGsp->pSignatureMemdesc = NULL; -+ - return status; - } - diff --git a/driver/patches/0002-booter-verify.patch b/driver/patches/0002-booter-verify.patch deleted file mode 100644 index 54a11f6..0000000 --- a/driver/patches/0002-booter-verify.patch +++ /dev/null @@ -1,87 +0,0 @@ -diff -Naur a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c ---- a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c 2026-07-18 11:26:26.848680684 -0700 -+++ b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c 2026-07-18 11:26:26.849806595 -0700 -@@ -57,6 +57,12 @@ - #include "g_all_dcl_pb.h" - #include "lib/protobuf/prb.h" - -+#define SEC2_DEBUG_PRI_FEATURE_OVERRIDE_PLM 0x00823804 -+#define SEC2_DEBUG_PRI_FEATURE_OVERRIDE_SM_SPEED 0x0082381c -+#define SEC2_DEBUG_PRI_FEATURE_OVERRIDE_SM_SPEED_1 0x00823820 -+#define SEC2_DEBUG_PRI_FBPA_CFG1 0x009a0204 -+#define SEC2_DEBUG_PRI_MMU_LMR 0x00100ce0 -+ - void - kgspConfigureFalcon_TU102 - ( -@@ -545,18 +551,35 @@ - // Execute FWSEC to setup FRTS if we have a FRTS region. - if (kgspGetFrtsSize_HAL(pGpu, pKernelGsp) > 0) - { -- NV_ASSERT_OR_RETURN(pKernelGsp->pPreparedFwsecCmd != NULL, NV_ERR_INVALID_STATE); -- -- NV_ASSERT_OK_OR_RETURN(kflcnReset_HAL(pGpu, pKernelFalcon)); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: FWSEC: pPreparedFwsecCmd=%p frtsSize=0x%x\n", -+ pKernelGsp->pPreparedFwsecCmd, -+ kgspGetFrtsSize_HAL(pGpu, pKernelGsp)); -+ -+ if (pKernelGsp->pPreparedFwsecCmd == NULL) -+ { -+ NV_PRINTF(LEVEL_ERROR, "SEC2_DEBUG: FWSEC cmd is NULL, aborting\n"); -+ return NV_ERR_INVALID_STATE; -+ } -+ -+ status = kflcnReset_HAL(pGpu, pKernelFalcon); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: kflcnReset for FWSEC: 0x%x\n", status); -+ if (status != NV_OK) return status; - - status = kgspExecuteFwsec_HAL(pGpu, pKernelGsp, pKernelGsp->pPreparedFwsecCmd); - portMemFree(pKernelGsp->pPreparedFwsecCmd); - pKernelGsp->pPreparedFwsecCmd = NULL; - -- NV_ASSERT_OK_OR_RETURN(status); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: FWSEC status=0x%x\n", status); -+ if (status != NV_OK) return status; - } - -- NV_ASSERT_OK_OR_RETURN(kflcnResetIntoRiscv_HAL(pGpu, pKernelFalcon)); -+ status = kflcnResetIntoRiscv_HAL(pGpu, pKernelFalcon); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: kflcnResetIntoRiscv: 0x%x\n", status); -+ if (status != NV_OK) return status; - - // Load init args into mailbox regs - kgspProgramLibosBootArgsAddr_HAL(pGpu, pKernelGsp); -@@ -565,6 +588,29 @@ - // Execute Booter Load - status = kgspExecuteBooterLoad_HAL(pGpu, pKernelGsp, - _kgspGetBooterLoadArgs(pKernelGsp, bootMode)); -+ -+ { -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ if (devId == 0x20C2 || devId == 0x2082) -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: normal BooterLoad status=0x%x\n", status); -+ } -+ -+ { -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ if ((devId == 0x20C2 || devId == 0x2082) && status == NV_OK) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: POST-BooterLoad verify PLM=0x%08x SS0=0x%08x SS1=0x%08x " -+ "CFG1=0x%08x LMR=0x%08x\n", -+ GPU_REG_RD32(pGpu, SEC2_DEBUG_PRI_FEATURE_OVERRIDE_PLM), -+ GPU_REG_RD32(pGpu, SEC2_DEBUG_PRI_FEATURE_OVERRIDE_SM_SPEED), -+ GPU_REG_RD32(pGpu, SEC2_DEBUG_PRI_FEATURE_OVERRIDE_SM_SPEED_1), -+ GPU_REG_RD32(pGpu, SEC2_DEBUG_PRI_FBPA_CFG1), -+ GPU_REG_RD32(pGpu, SEC2_DEBUG_PRI_MMU_LMR)); -+ } -+ } -+ - if (status != NV_OK) - { - NV_PRINTF(LEVEL_ERROR, "failed to execute Booter Load (ucode for initial boot): 0x%x\n", status); diff --git a/driver/patches/0002-tu102-hook.patch b/driver/patches/0002-tu102-hook.patch new file mode 100644 index 0000000..dca1887 --- /dev/null +++ b/driver/patches/0002-tu102-hook.patch @@ -0,0 +1,20 @@ +--- a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c ++++ b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c +@@ -57,6 +57,8 @@ + #include "g_all_dcl_pb.h" + #include "lib/protobuf/prb.h" + ++#include "gpu/cmpunlock/cmpunlock.h" ++ + void + kgspConfigureFalcon_TU102 + ( +@@ -571,6 +573,8 @@ + return status; + } + ++ cmpUnlockPostBooterLoad(pGpu, pKernelGsp); ++ + // Send init RPCs necessary for GSP-RM booting, before creating OBJGPU. + // Skips for suspend/resume as GSP saves/restores context + if (bootMode == KGSP_BOOT_MODE_NORMAL) diff --git a/driver/patches/0003-late-pma.patch b/driver/patches/0003-late-pma.patch deleted file mode 100644 index 218302b..0000000 --- a/driver/patches/0003-late-pma.patch +++ /dev/null @@ -1,263 +0,0 @@ -diff -Naur a/src/nvidia/arch/nvalloc/unix/src/osinit.c b/src/nvidia/arch/nvalloc/unix/src/osinit.c ---- a/src/nvidia/arch/nvalloc/unix/src/osinit.c 2026-07-18 11:26:26.875698119 -0700 -+++ b/src/nvidia/arch/nvalloc/unix/src/osinit.c 2026-07-18 11:26:26.876734803 -0700 -@@ -2195,6 +2195,18 @@ - goto shutdown; - } - -+ if (pGpu != NULL) -+ { -+ NvU32 devId = (pGpu->idInfo.PCIDeviceID) >> 16; -+ if (devId == 0x20C2 || devId == 0x2082) -+ { -+ NV_STATUS latePmaStatus = -+ memmgrSec2DebugLateExtendHighPmaRegion(pGpu, GPU_GET_MEMORY_MANAGER(pGpu)); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: late PMA extension status=0x%x\n", latePmaStatus); -+ } -+ } -+ - // - // Expanded GPU visibility in GPUMGR is no longer needed once the - // GPU is initialized. -diff -Naur a/src/nvidia/inc/kernel/gpu/mem_mgr/mem_mgr.h b/src/nvidia/inc/kernel/gpu/mem_mgr/mem_mgr.h ---- a/src/nvidia/inc/kernel/gpu/mem_mgr/mem_mgr.h 2026-07-18 11:26:26.869459809 -0700 -+++ b/src/nvidia/inc/kernel/gpu/mem_mgr/mem_mgr.h 2026-07-18 11:26:26.870506938 -0700 -@@ -1,3 +1,5 @@ - - #include "g_mem_mgr_nvoc.h" - -+NV_STATUS memmgrSec2DebugLateExtendHighPmaRegion(OBJGPU *pGpu, MemoryManager *pMemoryManager); -+ -diff -Naur a/src/nvidia/src/kernel/gpu/mem_mgr/mem_mgr.c b/src/nvidia/src/kernel/gpu/mem_mgr/mem_mgr.c ---- a/src/nvidia/src/kernel/gpu/mem_mgr/mem_mgr.c 2026-07-18 11:26:26.862962399 -0700 -+++ b/src/nvidia/src/kernel/gpu/mem_mgr/mem_mgr.c 2026-07-18 11:26:26.864088597 -0700 -@@ -1163,6 +1163,35 @@ - } - - NV_ASSERT_OK_OR_RETURN(kmemsysPostHeapCreate_HAL(pGpu, pKernelMemorySystem)); -+ -+ { -+ NvU32 devId2 = pGpu->idInfo.PCIDeviceID >> 16; -+ if (devId2 == 0x20C2 || devId2 == 0x2082) -+ { -+ NvU32 ri; -+ NvU64 regionBytes = 0, publicBytes = 0; -+ for (ri = 0; ri < pMemoryManager->Ram.numFBRegions; ri++) -+ { -+ NvU64 sz = pMemoryManager->Ram.fbRegion[ri].limit - -+ pMemoryManager->Ram.fbRegion[ri].base + 1; -+ regionBytes += sz; -+ if (!pMemoryManager->Ram.fbRegion[ri].bRsvdRegion && -+ !pMemoryManager->Ram.fbRegion[ri].bInternalHeap) -+ publicBytes += sz; -+ } -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_HEAP: fbAddrSpace=%lluMB mapRam=%lluMB " -+ "fbTotal=%lluMB fbUsable=0x%llx heapTotal=0x%llx " -+ "regionBytes=0x%llx publicBytes=0x%llx numRegions=%u\n", -+ pMemoryManager->Ram.fbAddrSpaceSizeMb, -+ pMemoryManager->Ram.mapRamSizeMb, -+ pMemoryManager->Ram.fbTotalMemSizeMb, -+ pMemoryManager->Ram.fbUsableMemSize, -+ pMemoryManager->pHeap->total, -+ regionBytes, publicBytes, -+ pMemoryManager->Ram.numFBRegions); -+ } -+ } - } - - return status; -@@ -3646,6 +3675,181 @@ - return status; - } - -+NV_STATUS -+memmgrSec2DebugLateExtendHighPmaRegion -+( -+ OBJGPU *pGpu, -+ MemoryManager *pMemoryManager -+) -+{ -+ Heap *pHeap; -+ PMA *pPma; -+ PMA_REGION_DESCRIPTOR pmaRegion = {0}; -+ PMA_REGION_DESCRIPTOR *pFirstPmaRegionDesc = NULL; -+ FB_REGION_DESCRIPTOR *pCandidate = NULL; -+ NvU32 numPmaRegions = 0; -+ NvU32 candidateIdx = MAX_FB_REGIONS; -+ NvU64 pmaFreeBefore = 0, pmaTotalBefore = 0; -+ NvU64 pmaFreeAfter = 0, pmaTotalAfter = 0; -+ NvU64 heapFree = 0, heapTotal = 0; -+ NvU32 devId; -+ NvU64 stockFbBytes; -+ NvU32 i; -+ NV_STATUS status; -+ -+ if (pGpu == NULL || pMemoryManager == NULL) -+ return NV_ERR_INVALID_ARGUMENT; -+ -+ devId = pGpu->idInfo.PCIDeviceID >> 16; -+ if (devId != 0x20C2 && devId != 0x2082) -+ return NV_OK; -+ -+ stockFbBytes = 0x200000000ULL; -+ -+ pHeap = pMemoryManager->pHeap; -+ if (pHeap == NULL || pHeap->pPmaObject == NULL || !memmgrIsPmaInitialized(pMemoryManager)) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: no PMA, skipped heap=%p init=%u\n", -+ pHeap, -+ pHeap ? memmgrIsPmaInitialized(pMemoryManager) : 0); -+ return NV_OK; -+ } -+ -+ pPma = pHeap->pPmaObject; -+ heapGetFree(pHeap, &heapFree); -+ heapGetSize(pHeap, &heapTotal); -+ pmaGetFreeMemory(pPma, &pmaFreeBefore); -+ pmaGetTotalMemory(pPma, &pmaTotalBefore); -+ -+ for (i = 0; i < pMemoryManager->Ram.numFBRegions; i++) -+ { -+ FB_REGION_DESCRIPTOR *pRegion = &pMemoryManager->Ram.fbRegion[i]; -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: region[%u] base=0x%llx limit=0x%llx " -+ "rsvd=%u rsvdSize=0x%llx intHeap=%u\n", -+ i, pRegion->base, pRegion->limit, -+ pRegion->bRsvdRegion, pRegion->rsvdSize, pRegion->bInternalHeap); -+ } -+ -+ status = pmaGetRegionInfo(pPma, &numPmaRegions, &pFirstPmaRegionDesc); -+ if (status != NV_OK) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: pmaGetRegionInfo failed 0x%x\n", status); -+ return status; -+ } -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: numFBRegions=%u numPmaRegions=%u " -+ "stockFb=0x%llx pma_total=0x%llx pma_free=0x%llx " -+ "heap_total=0x%llx heap_free=0x%llx\n", -+ pMemoryManager->Ram.numFBRegions, numPmaRegions, -+ stockFbBytes, pmaTotalBefore, pmaFreeBefore, -+ heapTotal, heapFree); -+ -+ for (i = 0; i < pMemoryManager->Ram.numFBRegions; i++) -+ { -+ FB_REGION_DESCRIPTOR *pRegion = &pMemoryManager->Ram.fbRegion[i]; -+ if (pRegion->bRsvdRegion && !pRegion->bInternalHeap && -+ pRegion->limit >= stockFbBytes && pRegion->base <= pRegion->limit && -+ (pCandidate == NULL || pRegion->limit > pCandidate->limit)) -+ { -+ pCandidate = pRegion; -+ candidateIdx = i; -+ } -+ } -+ -+ if (pCandidate == NULL) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: no high reserved region found " -+ "(looking for bRsvdRegion && limit>=0x%llx)\n", -+ stockFbBytes); -+ return NV_OK; -+ } -+ -+ pmaRegion.base = NV_MAX(pCandidate->base, stockFbBytes); -+ pmaRegion.limit = pCandidate->limit; -+ pmaRegion.performance = pCandidate->performance; -+ pmaRegion.bSupportCompressed = NV_TRUE; -+ pmaRegion.bSupportISO = pCandidate->bSupportISO; -+ pmaRegion.bProtected = pCandidate->bProtected; -+ -+ if (pmaRegion.base > pmaRegion.limit) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: empty range base=0x%llx > limit=0x%llx\n", -+ pmaRegion.base, pmaRegion.limit); -+ return NV_OK; -+ } -+ -+ if (pmaIsPmaManaged(pPma, pmaRegion.base, pmaRegion.limit)) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: already managed base=0x%llx limit=0x%llx\n", -+ pmaRegion.base, pmaRegion.limit); -+ return NV_OK; -+ } -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: registering candidate=%u base=0x%llx limit=0x%llx " -+ "cand_base=0x%llx cand_limit=0x%llx pma_region_id=%u\n", -+ candidateIdx, pmaRegion.base, pmaRegion.limit, -+ pCandidate->base, pCandidate->limit, numPmaRegions); -+ -+ if (pCandidate->base < stockFbBytes && -+ pMemoryManager->Ram.numFBRegions >= MAX_FB_REGIONS) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: no FB region slot for split, " -+ "numRegions=%u max=%u\n", -+ pMemoryManager->Ram.numFBRegions, MAX_FB_REGIONS); -+ return NV_ERR_INSUFFICIENT_RESOURCES; -+ } -+ -+ status = pmaRegisterRegion(pPma, numPmaRegions, NV_FALSE, &pmaRegion, 0, NULL); -+ -+ if (status == NV_OK) -+ { -+ if (pCandidate->base < stockFbBytes) -+ { -+ FB_REGION_DESCRIPTOR publicRegion = *pCandidate; -+ publicRegion.base = stockFbBytes; -+ publicRegion.limit = pCandidate->limit; -+ publicRegion.rsvdSize = 0; -+ publicRegion.bRsvdRegion = NV_FALSE; -+ publicRegion.bInternalHeap = NV_FALSE; -+ publicRegion.bSupportCompressed = NV_FALSE; -+ -+ pCandidate->limit = stockFbBytes - 1; -+ pCandidate->rsvdSize = NV_MIN(pCandidate->rsvdSize, -+ pCandidate->limit - pCandidate->base + 1); -+ -+ pMemoryManager->Ram.fbRegion[pMemoryManager->Ram.numFBRegions] = publicRegion; -+ pMemoryManager->Ram.numFBRegions++; -+ } -+ else -+ { -+ pCandidate->bRsvdRegion = NV_FALSE; -+ pCandidate->rsvdSize = 0; -+ pCandidate->bInternalHeap = NV_FALSE; -+ pCandidate->bSupportCompressed = NV_FALSE; -+ } -+ memmgrRegenerateFbRegionPriority(pGpu, pMemoryManager); -+ } -+ -+ pmaGetFreeMemory(pPma, &pmaFreeAfter); -+ pmaGetTotalMemory(pPma, &pmaTotalAfter); -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG_LATE_PMA: status=0x%x pma_total 0x%llx->0x%llx " -+ "pma_free 0x%llx->0x%llx\n", -+ status, pmaTotalBefore, pmaTotalAfter, pmaFreeBefore, pmaFreeAfter); -+ -+ return status; -+} -+ - - /*! - * @brief Retrieve the size of the client FB address space -@@ -4138,7 +4342,9 @@ - - if (!bFifoLite && !RMCFG_FEATURE_PLATFORM_GSP && bVirtualMode && - IS_SILICON(pGpu) && !pMemorySystemConfig->bDisableCompbitBacking && -- (pMemorySystemConfig->bUseRawModeComptaglineAllocation || pMemorySystemConfig->bOneToOneComptagLineAllocation)) -+ (pMemorySystemConfig->bUseRawModeComptaglineAllocation || pMemorySystemConfig->bOneToOneComptagLineAllocation) && -+ ((pGpu->idInfo.PCIDeviceID >> 16) != 0x20C2 && -+ (pGpu->idInfo.PCIDeviceID >> 16) != 0x2082)) - { - // Turn on virtual mode to enable compressed allocation access - ceUtilsParams.flags |= DRF_DEF(0050_CEUTILS, _FLAGS, _VIRTUAL_MODE, _TRUE); diff --git a/driver/patches/0003-osinit-late-pma-hook.patch b/driver/patches/0003-osinit-late-pma-hook.patch new file mode 100644 index 0000000..3c684b7 --- /dev/null +++ b/driver/patches/0003-osinit-late-pma-hook.patch @@ -0,0 +1,19 @@ +--- a/src/nvidia/arch/nvalloc/unix/src/osinit.c ++++ b/src/nvidia/arch/nvalloc/unix/src/osinit.c +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + #include "liblogdecode.h" + + #include +@@ -2195,6 +2196,8 @@ + goto shutdown; + } + ++ cmpUnlockLateExtendPma(pGpu); ++ + // + // Expanded GPU visibility in GPUMGR is no longer needed once the + // GPU is initialized. diff --git a/driver/patches/0004-bar0-pramin-clamp.patch b/driver/patches/0004-bar0-pramin-clamp.patch deleted file mode 100644 index fdcdbe7..0000000 --- a/driver/patches/0004-bar0-pramin-clamp.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Naur a/src/nvidia/src/kernel/gpu/bus/arch/maxwell/kern_bus_gm107.c b/src/nvidia/src/kernel/gpu/bus/arch/maxwell/kern_bus_gm107.c ---- a/src/nvidia/src/kernel/gpu/bus/arch/maxwell/kern_bus_gm107.c 2026-07-18 11:26:26.890781209 -0700 -+++ b/src/nvidia/src/kernel/gpu/bus/arch/maxwell/kern_bus_gm107.c 2026-07-18 11:26:26.891976131 -0700 -@@ -220,6 +220,16 @@ - else - { - offsetBar0 = (pMemoryManager->Ram.fbAddrSpaceSizeMb << 20) - DRF_SIZE(NV_PRAMIN); -+ -+ { -+ NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; -+ if ((devId == 0x20C2 || devId == 0x2082) && -+ pMemoryManager->Ram.fbAddrSpaceSizeMb > 0x2000) -+ { -+ NvU64 stockOffset = (0x2000ULL << 20) - DRF_SIZE(NV_PRAMIN); -+ offsetBar0 = stockOffset; -+ } -+ } - } - - // diff --git a/driver/patches/0004-memmgr-quirks.patch b/driver/patches/0004-memmgr-quirks.patch new file mode 100644 index 0000000..8c2c11a --- /dev/null +++ b/driver/patches/0004-memmgr-quirks.patch @@ -0,0 +1,63 @@ +--- a/src/nvidia/src/kernel/gpu/mem_mgr/mem_mgr.c ++++ b/src/nvidia/src/kernel/gpu/mem_mgr/mem_mgr.c +@@ -51,6 +51,7 @@ + #include "class/cl0005.h" // NV01_EVENT_KERNEL_CALLBACK_EX + #include "os/os.h" + #include "gpu/gsp/kernel_gsp.h" ++#include "gpu/cmpunlock/cmpunlock.h" + #include "gpu/conf_compute/conf_compute.h" + #include "gpu/mem_mgr/mem_mapper.h" + #include "platform/sli/sli.h" +@@ -4138,7 +4139,8 @@ + + if (!bFifoLite && !RMCFG_FEATURE_PLATFORM_GSP && bVirtualMode && + IS_SILICON(pGpu) && !pMemorySystemConfig->bDisableCompbitBacking && +- (pMemorySystemConfig->bUseRawModeComptaglineAllocation || pMemorySystemConfig->bOneToOneComptagLineAllocation)) ++ (pMemorySystemConfig->bUseRawModeComptaglineAllocation || pMemorySystemConfig->bOneToOneComptagLineAllocation) && ++ !cmpUnlockIsTarget(pGpu)) + { + // Turn on virtual mode to enable compressed allocation access + ceUtilsParams.flags |= DRF_DEF(0050_CEUTILS, _FLAGS, _VIRTUAL_MODE, _TRUE); +--- a/src/nvidia/src/kernel/gpu/mem_mgr/arch/turing/mem_mgr_tu102.c ++++ b/src/nvidia/src/kernel/gpu/mem_mgr/arch/turing/mem_mgr_tu102.c +@@ -33,6 +33,7 @@ + #include "published/turing/tu102/kind_macros.h" + #include "published/turing/tu102/dev_fb_addendum.h" + #include "nvRmReg.h" ++#include "gpu/cmpunlock/cmpunlock.h" + + /*! + * @brief Determine the kind of uncompressed PTE for a given allocation. +@@ -573,6 +574,13 @@ + if (pteKind == NULL) + return; + ++ // PLC compression is unreliable on the unlocked geometry ++ if (cmpUnlockIsTarget(ENG_GET_GPU(pMemoryManager))) ++ { ++ *pteKind = NV_MMU_PTE_KIND_GENERIC_MEMORY; ++ return; ++ } ++ + *pteKind = NV_MMU_PTE_KIND_GENERIC_MEMORY_COMPRESSIBLE_DISABLE_PLC; + } + +--- a/src/nvidia/src/kernel/gpu/mem_mgr/mem_scrub.c ++++ b/src/nvidia/src/kernel/gpu/mem_mgr/mem_scrub.c +@@ -64,6 +64,7 @@ + #include "class/clc9b5.h" // BLACKWELL_DMA_COPY_A + + #include "class/clcab5.h" // BLACKWELL_DMA_COPY_B ++#include "gpu/cmpunlock/cmpunlock.h" + + static NvU64 _scrubCheckProgress(OBJMEMSCRUB *pScrubber); + static NvU64 _searchScrubList(OBJMEMSCRUB *pScrubber, RmPhysAddr base, NvU64 size); +@@ -149,7 +150,7 @@ + NV_PRINTF(LEVEL_INFO, "Starting to init CeUtils for scrubber.\n"); + NV0050_ALLOCATION_PARAMETERS ceUtilsAllocParams = {0}; + +- if (memmgrUseVasForCeMemoryOps(pMemoryManager)) ++ if (memmgrUseVasForCeMemoryOps(pMemoryManager) && !cmpUnlockIsTarget(pGpu)) + { + ceUtilsAllocParams.flags = DRF_DEF(0050, _CEUTILS_FLAGS, _VIRTUAL_MODE, _TRUE); + } diff --git a/driver/patches/0005-bar0-pramin-clamp.patch b/driver/patches/0005-bar0-pramin-clamp.patch new file mode 100644 index 0000000..edb3f67 --- /dev/null +++ b/driver/patches/0005-bar0-pramin-clamp.patch @@ -0,0 +1,26 @@ +--- a/src/nvidia/src/kernel/gpu/bus/arch/maxwell/kern_bus_gm107.c ++++ b/src/nvidia/src/kernel/gpu/bus/arch/maxwell/kern_bus_gm107.c +@@ -50,6 +50,7 @@ + #include "published/maxwell/gm107/dev_mmu.h" + + #include "class/cl90f1.h" // FERMI_VASPACE_A ++#include "gpu/cmpunlock/cmpunlock.h" + + #define MAXWELL_BAR2_VBIOS_OFFSET (BUS_BAR2_RM_APERTURE_MB<<20) + +@@ -220,6 +221,15 @@ + else + { + offsetBar0 = (pMemoryManager->Ram.fbAddrSpaceSizeMb << 20) - DRF_SIZE(NV_PRAMIN); ++ ++ // ++ // The BAR0 window only decodes the stock 8GB, so keep PRAMIN where it ++ // would have landed before the unlock widened fbAddrSpaceSizeMb. ++ // ++ if (cmpUnlockIsTarget(pGpu) && pMemoryManager->Ram.fbAddrSpaceSizeMb > 0x2000) ++ { ++ offsetBar0 = (0x2000ULL << 20) - DRF_SIZE(NV_PRAMIN); ++ } + } + + // diff --git a/driver/patches/0005-ce-scrub-workarounds.patch b/driver/patches/0005-ce-scrub-workarounds.patch deleted file mode 100644 index 4103a83..0000000 --- a/driver/patches/0005-ce-scrub-workarounds.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff -Naur a/src/nvidia/src/kernel/gpu/mem_mgr/arch/turing/mem_mgr_tu102.c b/src/nvidia/src/kernel/gpu/mem_mgr/arch/turing/mem_mgr_tu102.c ---- a/src/nvidia/src/kernel/gpu/mem_mgr/arch/turing/mem_mgr_tu102.c 2026-07-18 11:26:26.913308290 -0700 -+++ b/src/nvidia/src/kernel/gpu/mem_mgr/arch/turing/mem_mgr_tu102.c 2026-07-18 11:26:26.914385381 -0700 -@@ -570,9 +570,20 @@ - NvU32 *pteKind - ) - { -+ OBJGPU *pGpu; -+ - if (pteKind == NULL) - return; - -+ pGpu = ENG_GET_GPU(pMemoryManager); -+ if (pGpu != NULL && -+ ((pGpu->idInfo.PCIDeviceID >> 16) == 0x20C2 || -+ (pGpu->idInfo.PCIDeviceID >> 16) == 0x2082)) -+ { -+ *pteKind = NV_MMU_PTE_KIND_GENERIC_MEMORY; -+ return; -+ } -+ - *pteKind = NV_MMU_PTE_KIND_GENERIC_MEMORY_COMPRESSIBLE_DISABLE_PLC; - } - -diff -Naur a/src/nvidia/src/kernel/gpu/mem_mgr/mem_scrub.c b/src/nvidia/src/kernel/gpu/mem_mgr/mem_scrub.c ---- a/src/nvidia/src/kernel/gpu/mem_mgr/mem_scrub.c 2026-07-18 11:26:26.905387408 -0700 -+++ b/src/nvidia/src/kernel/gpu/mem_mgr/mem_scrub.c 2026-07-18 11:26:26.906485666 -0700 -@@ -149,7 +149,9 @@ - NV_PRINTF(LEVEL_INFO, "Starting to init CeUtils for scrubber.\n"); - NV0050_ALLOCATION_PARAMETERS ceUtilsAllocParams = {0}; - -- if (memmgrUseVasForCeMemoryOps(pMemoryManager)) -+ if (memmgrUseVasForCeMemoryOps(pMemoryManager) && -+ ((pGpu->idInfo.PCIDeviceID >> 16) != 0x20C2 && -+ (pGpu->idInfo.PCIDeviceID >> 16) != 0x2082)) - { - ceUtilsAllocParams.flags = DRF_DEF(0050, _CEUTILS_FLAGS, _VIRTUAL_MODE, _TRUE); - } diff --git a/driver/patches/0006-persistent-sw-state.patch b/driver/patches/0006-persistent-sw-state.patch index bb6a85d..d4626cd 100644 --- a/driver/patches/0006-persistent-sw-state.patch +++ b/driver/patches/0006-persistent-sw-state.patch @@ -1,15 +1,16 @@ -diff -Naur a/kernel-open/nvidia/nv.c b/kernel-open/nvidia/nv.c ---- a/kernel-open/nvidia/nv.c 2026-07-18 11:26:26.928006389 -0700 -+++ b/kernel-open/nvidia/nv.c 2026-07-18 11:26:26.930357872 -0700 -@@ -1521,6 +1521,15 @@ +--- a/kernel-open/nvidia/nv.c ++++ b/kernel-open/nvidia/nv.c +@@ -1521,6 +1521,17 @@ goto failed_release_irq; } -+ if (nv->pci_info.device_id == 0x20C2) -+ { -+ nv->flags |= NV_FLAG_PERSISTENT_SW_STATE; -+ } -+ else if (nv->pci_info.device_id == 0x2082) ++ /* ++ * CMP 170HX: the unlock is applied once during GSP bootstrap, so the ++ * software state has to survive teardown rather than being rebuilt. ++ * Device IDs match CMPUNLOCK_DEVID_* in cmpunlock.h; they are repeated ++ * here because kernel-open sources cannot include RM headers. ++ */ ++ if (nv->pci_info.device_id == 0x20C2 || nv->pci_info.device_id == 0x2082) + { + nv->flags |= NV_FLAG_PERSISTENT_SW_STATE; + } diff --git a/driver/patches/0007-pcie-gen2.patch b/driver/patches/0007-pcie-gen2.patch deleted file mode 100644 index 6e5ba03..0000000 --- a/driver/patches/0007-pcie-gen2.patch +++ /dev/null @@ -1,73 +0,0 @@ ---- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:43:51.261744520 +0200 -+++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:44:47.811484740 +0200 -@@ -4951,6 +4951,70 @@ - devId); - } - -+ // PCIe Gen2: directed speed change via XP LTSSM -+ // PLM gates (XVE_PLM, XVE_CYA_PLM, XVE_FUSE_OVR, XVE_CYA_SPD, XVE_TARGET) -+ // are already opened by the main plmTable above. -+ { -+ NvU32 xpCfg0 = GPU_REG_RD32(pGpu, 0x0008C040U); -+ NvU32 xpLctrl2 = GPU_REG_RD32(pGpu, 0x0008C1C0U); -+ NvU32 xpCya0 = GPU_REG_RD32(pGpu, 0x0008C2C0U); -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe pre: CFG0=0x%08x LCTRL2=0x%08x CYA0=0x%08x\n", -+ xpCfg0, xpLctrl2, xpCya0); -+ -+ GPU_REG_WR32(pGpu, 0x0008C2C0U, xpCya0 & ~0x00802005U); -+ GPU_REG_WR32(pGpu, 0x0008C040U, (xpCfg0 & ~0xC0000U) | 0x80000U); -+ GPU_REG_WR32(pGpu, 0x0008C1C0U, (xpLctrl2 & ~0xF0000U) | 0x20000U); -+ -+ { -+ OBJCL *pCl = SYS_GET_CL(SYS_GET_INSTANCE()); -+ PORTDATA *pUpPort = &pGpu->gpuClData.upstreamPort; -+ if (pCl != NULL && pUpPort->addr.valid) -+ { -+ NvU32 lnkCtl2Off = pUpPort->PCIECapPtr + 0x30U; -+ NvU16 rpLnkCtl2 = clPcieReadWord(pCl, -+ pUpPort->addr.domain, pUpPort->addr.bus, -+ pUpPort->addr.device, pUpPort->addr.func, lnkCtl2Off); -+ NvU16 rpLnkCtl2New = (rpLnkCtl2 & ~0xFU) | 0x2U; -+ clPcieWriteWord(pCl, -+ pUpPort->addr.domain, pUpPort->addr.bus, -+ pUpPort->addr.device, pUpPort->addr.func, -+ lnkCtl2Off, rpLnkCtl2New); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe root port LnkCtl2 @ 0x%x: 0x%04x -> 0x%04x\n", -+ lnkCtl2Off, rpLnkCtl2, rpLnkCtl2New); -+ } -+ } -+ -+ { -+ NvU32 cfg0Now = GPU_REG_RD32(pGpu, 0x0008C040U); -+ NvU32 cfg0After; -+ NvU32 linkCtrlStat; -+ NvU32 i; -+ -+ GPU_REG_WR32(pGpu, 0x0008C040U, (cfg0Now & ~0xFU) | 0x1U); -+ -+ for (i = 0; i < 50; i++) -+ { -+ osDelay(10); -+ if ((GPU_REG_RD32(pGpu, 0x0008C040U) & 0x10U) == 0) -+ break; -+ } -+ -+ cfg0After = GPU_REG_RD32(pGpu, 0x0008C040U); -+ GPU_REG_WR32(pGpu, 0x0008C040U, cfg0After & ~0xFU); -+ -+ linkCtrlStat = GPU_REG_RD32(pGpu, 0x00088088U); -+ NV_PRINTF(LEVEL_ERROR, -+ "SEC2_DEBUG: PCIe retrain done (polls=%u): " -+ "LinkCtrlStat=0x%08x speed=%u width=x%u\n", -+ i, linkCtrlStat, -+ (linkCtrlStat >> 16) & 0xFU, -+ (linkCtrlStat >> 20) & 0x3FU); -+ } -+ } -+ - plmStatus = kgspSec2PostblTimingRebuildStockSignature(pGpu, pKernelGsp); - if (plmStatus != NV_OK) - { diff --git a/driver/patches/0008-mclk-overclock.patch b/driver/patches/0008-mclk-overclock.patch deleted file mode 100644 index 9c52605..0000000 --- a/driver/patches/0008-mclk-overclock.patch +++ /dev/null @@ -1,147 +0,0 @@ ---- a/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c 2026-07-31 00:17:22.670241348 +0200 -+++ b/src/nvidia/src/kernel/gpu/gsp/arch/turing/kernel_gsp_tu102.c 2026-07-31 00:18:28.686969052 +0200 -@@ -611,6 +611,144 @@ kgspBootstrap_TU102 - } - } - -+ // HBM PLL NDIV overclock (post-BooterLoad, pre-GSP window where PLMs are open) -+ if (status == NV_OK) -+ { -+ // -+ // Device IDs mirror SEC2_POSTBL_TIMING_CMP_170HX_{8,10}GB_PCI_DEVICE_ID -+ // in kernel_gsp.c. The sequence is VBIOS-agnostic: the stock NDIV is -+ // read out of the PLL rather than assumed, and every COEFF write is a -+ // read-modify-write that keeps the MDIV/PDIV the VBIOS programmed. -+ // -+ NvU32 ocDevId = pGpu->idInfo.PCIDeviceID >> 16; -+ if (ocDevId == 0x20C2 || ocDevId == 0x2082) -+ { -+ NvU32 fbpaIdx; -+ NvU32 pollIdx; -+ NvU32 fbpaCount = 0; -+ NvU32 failCount = 0; -+ NvU32 plm0; -+ NvU32 fbio0; -+ NvU32 curNdiv; -+ NvU32 base, cfgAddr, coeffAddr; -+ NvU32 origCfg, origCoeff, newCoeff, lockCfg; -+ NvU32 ddll0, calSt0, calSt1; -+ // XX is rewritten by driver/build.sh from --mclk-ndiv, and is left -+ // deliberately uncompilable so an unsubstituted tree cannot build. -+ static const NvU32 newNdiv = XX; -+ -+ plm0 = GPU_REG_RD32(pGpu, 0x00903C7CU); -+ curNdiv = (GPU_REG_RD32(pGpu, 0x00903C98U) >> 8) & 0xFFU; -+ if ((plm0 & 0x10U) == 0) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: aborted, PLM=0x%08x (bit4 closed)\n", plm0); -+ } -+ else -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: start NDIV %u->%u (%u->%u MHz) " -+ "devid=0x%04x vbios=%s PLM=0x%08x\n", -+ curNdiv, newNdiv, 27 * curNdiv, 27 * newNdiv, -+ ocDevId, pKernelGsp->vbiosVersionStr, plm0); -+ -+ // 1. Assert MEMCLK_CHANGE_ALERT (FBIO broadcast bit 31) -+ fbio0 = GPU_REG_RD32(pGpu, 0x009A0590U); -+ GPU_REG_WR32(pGpu, 0x009A0590U, fbio0 | 0x80000000U); -+ -+ // 2. Enter HBM self-refresh -+ GPU_REG_WR32(pGpu, 0x009A031CU, 0x00000001U); -+ osDelay(5); -+ -+ // 3. PLL cycle on each active FBPA -+ for (fbpaIdx = 0; fbpaIdx < 12; fbpaIdx++) -+ { -+ base = 0x900000U + fbpaIdx * 0x4000U; -+ cfgAddr = base + 0x3C90U; -+ coeffAddr = base + 0x3C98U; -+ -+ origCfg = GPU_REG_RD32(pGpu, cfgAddr); -+ origCoeff = GPU_REG_RD32(pGpu, coeffAddr); -+ -+ if (origCfg == 0 || origCoeff == 0 || -+ (origCfg & 0xFFF00000U) == 0xBAD00000U) -+ continue; -+ -+ fbpaCount++; -+ -+ GPU_REG_WR32(pGpu, cfgAddr, origCfg & ~0x09U); -+ osDelay(2); -+ -+ newCoeff = (origCoeff & ~0xFF00U) | ((newNdiv & 0xFFU) << 8); -+ GPU_REG_WR32(pGpu, coeffAddr, newCoeff); -+ -+ GPU_REG_WR32(pGpu, cfgAddr, (origCfg | 0x09U) & ~0x20U); -+ -+ lockCfg = 0; -+ for (pollIdx = 0; pollIdx < 200; pollIdx++) -+ { -+ osDelay(1); -+ lockCfg = GPU_REG_RD32(pGpu, cfgAddr); -+ if (lockCfg & 0x20U) -+ break; -+ } -+ -+ if (!(lockCfg & 0x20U)) -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: FBPA%u PLL lock timeout\n", fbpaIdx); -+ failCount++; -+ continue; -+ } -+ -+ GPU_REG_WR32(pGpu, cfgAddr, lockCfg & ~0x1000U); -+ } -+ -+ // 4. Exit self-refresh -+ GPU_REG_WR32(pGpu, 0x009A031CU, 0x00000000U); -+ osDelay(10); -+ -+ // 5. DDLL calibration -+ ddll0 = GPU_REG_RD32(pGpu, 0x009A11DCU); -+ GPU_REG_WR32(pGpu, 0x009A11DCU, ddll0 | 0x40U); -+ osDelay(10); -+ calSt0 = 0; -+ calSt1 = 0; -+ for (pollIdx = 0; pollIdx < 100; pollIdx++) -+ { -+ osDelay(1); -+ calSt0 = GPU_REG_RD32(pGpu, 0x009A0674U); -+ calSt1 = GPU_REG_RD32(pGpu, 0x009A0678U); -+ } -+ GPU_REG_WR32(pGpu, 0x009A11DCU, ddll0 & ~0x40U); -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: DDLL cal status 0x%08x 0x%08x\n", -+ calSt0, calSt1); -+ -+ // 6. Clear MEMCLK_CHANGE_ALERT -+ GPU_REG_WR32(pGpu, 0x009A0590U, -+ GPU_REG_RD32(pGpu, 0x009A0590U) & ~0x80000000U); -+ -+ if (fbpaCount == 0) -+ NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: no active FBPAs found\n"); -+ else if (failCount > 0) -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: %u/%u FBPAs failed to lock\n", -+ failCount, fbpaCount); -+ else -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: done, %u FBPAs at NDIV=%u (%u MHz)\n", -+ fbpaCount, newNdiv, 27 * newNdiv); -+ } -+ } -+ else -+ { -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: skipped, PCI device 0x%04x is not a CMP 170HX " -+ "(need 0x20C2 or 0x2082)\n", ocDevId); -+ } -+ } -+ - if (status != NV_OK) - { - NV_PRINTF(LEVEL_ERROR, "failed to execute Booter Load (ucode for initial boot): 0x%x\n", status); diff --git a/driver/patches/0009-mclk-overclock-post-gsp.patch b/driver/patches/0009-mclk-overclock-post-gsp.patch deleted file mode 100644 index 194effa..0000000 --- a/driver/patches/0009-mclk-overclock-post-gsp.patch +++ /dev/null @@ -1,59 +0,0 @@ ---- a/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:47:41.953643183 +0200 -+++ b/src/nvidia/src/kernel/gpu/gsp/kernel_gsp.c 2026-07-31 00:47:45.933556620 +0200 -@@ -5435,6 +5435,56 @@ - - NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, kgspStartLogPolling(pGpu, pKernelGsp), done); - -+ // Post-GSP HBMPLL OC: multicast COEFF write + PRI_FENCE (matching v3) -+ { -+ NvU32 ocDevId = pGpu->idInfo.PCIDeviceID >> 16; -+ if (_kgspSec2PostblTimingEnabled(pGpu)) -+ { -+ // XX is rewritten by driver/build.sh from --mclk-ndiv, and is left -+ // deliberately uncompilable so an unsubstituted tree cannot build. -+ static const NvU32 newNdiv = XX; -+ NvU32 coeff_pre = GPU_REG_RD32(pGpu, 0x00903C98U); -+ NvU32 plm_pre = GPU_REG_RD32(pGpu, 0x00903C7CU); -+ NvU32 newCoeff; -+ NvU32 cfg = 0; -+ NvU32 i; -+ -+ // -+ // Keep the MDIV/PDIV the VBIOS programmed and swap NDIV only, so -+ // this works on any VBIOS. Fall back to the 300W layout if the -+ // read came back as a PRI error. -+ // -+ if (coeff_pre == 0 || (coeff_pre & 0xFFF00000U) == 0xBAD00000U) -+ newCoeff = (1U << 16) | (newNdiv << 8) | 1U; -+ else -+ newCoeff = (coeff_pre & ~0xFF00U) | ((newNdiv & 0xFFU) << 8); -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: post-GSP PRE: COEFF=0x%08x(NDIV=%u) PLM=0x%08x " -+ "devid=0x%04x vbios=%s newCOEFF=0x%08x\n", -+ coeff_pre, (coeff_pre >> 8) & 0xFFU, plm_pre, -+ ocDevId, pKernelGsp->vbiosVersionStr, newCoeff); -+ -+ GPU_REG_WR32(pGpu, 0x0098BC98U, newCoeff); -+ GPU_REG_WR32(pGpu, 0x001211FCU, 0x0U); -+ for (i = 0; i < 500; i++) -+ (void)GPU_REG_RD32(pGpu, 0x00903C90U); -+ -+ for (i = 0; i < 200000; i++) -+ { -+ cfg = GPU_REG_RD32(pGpu, 0x00903C90U); -+ if (cfg & 0x20U) -+ break; -+ } -+ -+ NV_PRINTF(LEVEL_ERROR, -+ "HBMPLL_OC: post-GSP POST: COEFF=0x%08x(NDIV=%u) CFG=0x%08x lock=%u iter=%u\n", -+ GPU_REG_RD32(pGpu, 0x00903C98U), -+ (GPU_REG_RD32(pGpu, 0x00903C98U) >> 8) & 0xFFU, -+ cfg, (cfg >> 5) & 1U, i); -+ } -+ } -+ - done: - pKernelGsp->bInInit = NV_FALSE; - diff --git a/driver/src/cmpunlock.c b/driver/src/cmpunlock.c new file mode 100644 index 0000000..1e98574 --- /dev/null +++ b/driver/src/cmpunlock.c @@ -0,0 +1,1016 @@ +/* + * cmpunlock - NVIDIA CMP 170HX (GA100) unlock logic. + * + * The card ships with its SM throughput, framebuffer geometry and PCIe link + * speed clamped by PLM (priv level mask) gates that reject writes from the + * host. The SEC2 Booter, however, is trusted enough to write them, and there + * is a window during GSP bootstrap where its payload buffer can be pointed at + * an arbitrary register/value pair. cmpUnlockPreBoot() walks that window once + * per gate, then writes the real configuration and puts the stock signature + * back so GSP boots as usual. + * + * See cmpunlock.h for where each entry point is hooked into the stock driver. + */ + +#include "gpu/cmpunlock/cmpunlock.h" +#include "gpu/cmpunlock/cmpunlock_config.h" + +#include "gpu/mem_mgr/mem_mgr.h" +#include "gpu/mem_mgr/heap.h" +#include "gpu/mem_mgr/phys_mem_allocator/phys_mem_allocator.h" +#include "gpu/bus/kern_bus.h" +#include "platform/chipset/chipset.h" +#include "core/system.h" +#include "os/os.h" + +/* ------------------------------------------------------------------------- + * Register map + * ------------------------------------------------------------------------- */ + +/* WPR2 window, saved and restored around every Booter invocation. */ +#define CMP_REG_WPR2_LO 0x001fa824U +#define CMP_REG_WPR2_HI 0x001fa828U + +/* SM speed select and memory geometry. */ +#define CMP_REG_SM_SPEED_0 0x0082381cU +#define CMP_REG_SM_SPEED_1 0x00823820U +#define CMP_REG_FBPA_CFG1 0x009a0204U +#define CMP_REG_MMU_LMR 0x00100ce0U + +/* PCIe Gen2: XP LTSSM directed speed change. */ +#define CMP_REG_XP_CFG0 0x0008c040U +#define CMP_REG_XP_LCTRL2 0x0008c1c0U +#define CMP_REG_XP_CYA0 0x0008c2c0U +#define CMP_REG_XVE_LINK_CTRL_STAT 0x00088088U + +/* HBM PLL / FBPA. */ +#define CMP_REG_FBPA_PLL_PLM 0x00903c7cU +#define CMP_REG_FBPA_PLL_CFG 0x00903c90U +#define CMP_REG_FBPA_PLL_COEFF 0x00903c98U +#define CMP_REG_FBPA_PLL_COEFF_MC 0x0098bc98U /* multicast COEFF */ +#define CMP_REG_PRI_FENCE 0x001211fcU +#define CMP_REG_FBIO_BROADCAST 0x009a0590U +#define CMP_REG_HBM_SELF_REFRESH 0x009a031cU +#define CMP_REG_DDLL_CAL 0x009a11dcU +#define CMP_REG_DDLL_CAL_STATUS_0 0x009a0674U +#define CMP_REG_DDLL_CAL_STATUS_1 0x009a0678U + +#define CMP_FBPA_COUNT 12U +#define CMP_FBPA_STRIDE 0x4000U +#define CMP_FBPA_BASE 0x900000U +#define CMP_FBPA_PLL_CFG_OFFSET 0x3c90U +#define CMP_FBPA_PLL_COEFF_OFFSET 0x3c98U + +/* Booter payload geometry. */ +#define CMP_SIGNATURE_SIZE 0x0000f800ULL +#define CMP_PAYLOAD_FILL_DWORD 0x000004a7U +#define CMP_DMEM_PATH "/lib/firmware/nvidia/ga100/gsp/dmem.bin" + +/* Unlocked framebuffer sizes. */ +#define CMP_FB_BYTES_8GB 0x0000001000000000ULL /* 64GB */ +#define CMP_FB_BYTES_10GB 0x0000000A00000000ULL /* 40GB */ +#define CMP_FB_BYTES_STOCK 0x0000000200000000ULL /* 8GB */ + +/* A PRI read that comes back as 0xBAD?????? is an error, not data. */ +#define CMP_IS_PRI_ERROR(v) (((v) & 0xFFF00000U) == 0xBAD00000U) + +/* ------------------------------------------------------------------------- + * Stock signature cache + * + * The signature buffer is repurposed as the Booter payload, so the real + * signature has to be kept aside until the unlock is done. There is no room + * for it in KernelGsp without patching a generated header, so it is parked in + * a small table here instead. Entries are only touched during GSP init, which + * runs under the API lock. + * ------------------------------------------------------------------------- */ + +#define CMP_MAX_GPUS 32 + +static struct +{ + OBJGPU *pGpu; + NvU8 *pData; + NvU64 size; +} cmpStockSignature[CMP_MAX_GPUS]; + +static void +_cmpStockSignatureSet(OBJGPU *pGpu, NvU8 *pData, NvU64 size) +{ + NvU32 i, free = CMP_MAX_GPUS; + + for (i = 0; i < CMP_MAX_GPUS; i++) + { + if (cmpStockSignature[i].pGpu == pGpu) + { + /* Re-init of the same GPU: drop the previous copy first. */ + portMemFree(cmpStockSignature[i].pData); + cmpStockSignature[i].pData = pData; + cmpStockSignature[i].size = size; + return; + } + if (free == CMP_MAX_GPUS && cmpStockSignature[i].pGpu == NULL) + free = i; + } + + if (free == CMP_MAX_GPUS) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: stock signature table full\n"); + portMemFree(pData); + return; + } + + cmpStockSignature[free].pGpu = pGpu; + cmpStockSignature[free].pData = pData; + cmpStockSignature[free].size = size; +} + +static NvU8 * +_cmpStockSignatureGet(OBJGPU *pGpu, NvU64 *pSize) +{ + NvU32 i; + + for (i = 0; i < CMP_MAX_GPUS; i++) + { + if (cmpStockSignature[i].pGpu == pGpu) + { + *pSize = cmpStockSignature[i].size; + return cmpStockSignature[i].pData; + } + } + + *pSize = 0; + return NULL; +} + +/* ------------------------------------------------------------------------- + * Target detection + * ------------------------------------------------------------------------- */ + +NvBool +cmpUnlockIsTarget(OBJGPU *pGpu) +{ + NvU32 devId; + + if (pGpu == NULL) + return NV_FALSE; + + devId = pGpu->idInfo.PCIDeviceID >> 16; + + return (devId == CMPUNLOCK_DEVID_8GB || devId == CMPUNLOCK_DEVID_10GB); +} + +static NvU64 +_cmpUnlockedFbBytes(OBJGPU *pGpu) +{ + return ((pGpu->idInfo.PCIDeviceID >> 16) == CMPUNLOCK_DEVID_8GB) + ? CMP_FB_BYTES_8GB + : CMP_FB_BYTES_10GB; +} + +/* ------------------------------------------------------------------------- + * SEC2 Booter payload + * ------------------------------------------------------------------------- */ + +static void +_cmpPutU32(NvU8 *pBuffer, NvU32 offset, NvU32 value) +{ + pBuffer[offset + 0] = (NvU8)(value >> 0); + pBuffer[offset + 1] = (NvU8)(value >> 8); + pBuffer[offset + 2] = (NvU8)(value >> 16); + pBuffer[offset + 3] = (NvU8)(value >> 24); +} + +/* + * Build the Booter payload that makes SEC2 perform a single 32-bit write of + * writeValue to writeAddr. The constants are the DMEM image the Booter walks; + * only the address and value slots vary between calls. + */ +static void +_cmpFillPayload(NvU8 *pSignatureVa, NvU64 signatureSize, + NvU32 writeAddr, NvU32 writeValue) +{ + NvU64 i; + + for (i = 0; i + sizeof(NvU32) <= signatureSize; i += sizeof(NvU32)) + _cmpPutU32(pSignatureVa, (NvU32)i, CMP_PAYLOAD_FILL_DWORD); + + _cmpPutU32(pSignatureVa, 0x1100, 0x00000007U); + _cmpPutU32(pSignatureVa, 0x5b40, 0xc0deca7eU); + + _cmpPutU32(pSignatureVa, 0xf754, writeValue); + _cmpPutU32(pSignatureVa, 0xf758, 0xc0deca7eU); + _cmpPutU32(pSignatureVa, 0xf75c, 0x00000cbdU); + _cmpPutU32(pSignatureVa, 0xf76c, writeAddr); + _cmpPutU32(pSignatureVa, 0xf774, 0x00001fbdU); + _cmpPutU32(pSignatureVa, 0xf780, 0x00000000U); + _cmpPutU32(pSignatureVa, 0xf788, 0x000010aaU); + _cmpPutU32(pSignatureVa, 0xf78c, 0x0000815aU); + _cmpPutU32(pSignatureVa, 0xf790, 0x00008e18U); + _cmpPutU32(pSignatureVa, 0xf794, 0xc0deca7eU); + _cmpPutU32(pSignatureVa, 0xf798, 0x0000815aU); + _cmpPutU32(pSignatureVa, 0xf79c, 0x00000000U); + _cmpPutU32(pSignatureVa, 0xf7a0, 0xc0deca7eU); + _cmpPutU32(pSignatureVa, 0xf7a4, 0x00001fbdU); + _cmpPutU32(pSignatureVa, 0xf7b0, 0x0000ffbcU); + _cmpPutU32(pSignatureVa, 0xf7b8, 0x0000582dU); + _cmpPutU32(pSignatureVa, 0xf7c4, 0xc0deca7eU); + _cmpPutU32(pSignatureVa, 0xf7c8, 0x00000cbdU); + _cmpPutU32(pSignatureVa, 0xf7d8, 0x00000003U); + _cmpPutU32(pSignatureVa, 0xf7e0, 0x00001fbdU); + _cmpPutU32(pSignatureVa, 0xf7f4, 0x00000ccbU); + _cmpPutU32(pSignatureVa, 0xf7f8, 0x00007f2fU); +} + +/* Rewrite the payload in place for the next register write. */ +static NV_STATUS +_cmpRefillPayload(OBJGPU *pGpu, KernelGsp *pKernelGsp, + NvU32 writeAddr, NvU32 writeValue) +{ + NvU8 *pSignatureVa; + + if (pKernelGsp->pSignatureMemdesc == NULL) + return NV_ERR_INVALID_STATE; + + pSignatureVa = memdescMapInternal(pGpu, pKernelGsp->pSignatureMemdesc, TRANSFER_FLAGS_NONE); + if (pSignatureVa == NULL) + return NV_ERR_INSUFFICIENT_RESOURCES; + + _cmpFillPayload(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), + writeAddr, writeValue); + + memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); + memdescFlushCpuCaches(pGpu, pKernelGsp->pSignatureMemdesc); + + if (pKernelGsp->pWprMeta != NULL) + { + pKernelGsp->pWprMeta->sysmemAddrOfSignature = + memdescGetPhysAddr(pKernelGsp->pSignatureMemdesc, AT_GPU, 0); + pKernelGsp->pWprMeta->sizeOfSignature = + memdescGetSize(pKernelGsp->pSignatureMemdesc); + } + + if (pKernelGsp->pWprMetaDescriptor != NULL) + memdescFlushCpuCaches(pGpu, pKernelGsp->pWprMetaDescriptor); + + return NV_OK; +} + +NvU64 +cmpUnlockSignatureSize(OBJGPU *pGpu, NvU64 stockSize) +{ + return cmpUnlockIsTarget(pGpu) ? CMP_SIGNATURE_SIZE : stockSize; +} + +NvBool +cmpUnlockFillSignature(OBJGPU *pGpu, KernelGsp *pKernelGsp, + NvU8 *pSignatureVa, NvU64 signatureVaSize, + const void *pStockSignature, NvU64 stockSignatureSize) +{ + NV_STATUS dmemStatus; + + if (!cmpUnlockIsTarget(pGpu)) + return NV_FALSE; + + if (pStockSignature != NULL && stockSignatureSize > 0) + { + NvU8 *pCopy = portMemAllocNonPaged(stockSignatureSize); + if (pCopy != NULL) + { + portMemCopy(pCopy, stockSignatureSize, pStockSignature, stockSignatureSize); + _cmpStockSignatureSet(pGpu, pCopy, stockSignatureSize); + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: saved stock signature (%llu bytes)\n", + (unsigned long long)stockSignatureSize); + } + } + + /* + * Prefer the DMEM image on disk when it is present; the built-in payload + * is the same thing generated from scratch. + */ + dmemStatus = os_open_and_read_file(CMP_DMEM_PATH, pSignatureVa, signatureVaSize); + if (dmemStatus == NV_OK) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: loaded %llu bytes from %s\n", + (unsigned long long)signatureVaSize, CMP_DMEM_PATH); + } + else + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: %s not found (0x%x), using built-in payload\n", + CMP_DMEM_PATH, dmemStatus); + _cmpFillPayload(pSignatureVa, signatureVaSize, 0x009a0148U, 0xffffffffU); + } + + memdescFlushCpuCaches(pGpu, pKernelGsp->pSignatureMemdesc); + + return NV_TRUE; +} + +/* + * Swap the Booter payload back out for the real signature, so the GSP boot + * that follows sees exactly what the stock driver would have handed it. + */ +static NV_STATUS +_cmpRebuildStockSignature(OBJGPU *pGpu, KernelGsp *pKernelGsp) +{ + NV_STATUS status = NV_OK; + NvU8 *pSignatureVa = NULL; + NvU8 *pStockData; + NvU64 stockSize; + NvU64 sigSize; + NvU64 flags = MEMDESC_FLAGS_NONE; + + pStockData = _cmpStockSignatureGet(pGpu, &stockSize); + if (pStockData == NULL || stockSize == 0) + return NV_ERR_INVALID_STATE; + + if (pKernelGsp->pSignatureMemdesc != NULL) + { + memdescFree(pKernelGsp->pSignatureMemdesc); + memdescDestroy(pKernelGsp->pSignatureMemdesc); + pKernelGsp->pSignatureMemdesc = NULL; + } + + sigSize = NV_ALIGN_UP(stockSize, 256); + flags |= MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY; + + NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, + memdescCreate(&pKernelGsp->pSignatureMemdesc, pGpu, + sigSize, 256, + NV_TRUE, ADDR_SYSMEM, NV_MEMORY_CACHED, flags)); + + memdescTagAlloc(status, + NV_FB_ALLOC_RM_INTERNAL_OWNER_UNNAMED_TAG_16, pKernelGsp->pSignatureMemdesc); + NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, status, rebuild_fail_create); + + pSignatureVa = memdescMapInternal(pGpu, pKernelGsp->pSignatureMemdesc, TRANSFER_FLAGS_NONE); + NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, + (pSignatureVa != NULL) ? NV_OK : NV_ERR_INSUFFICIENT_RESOURCES, + rebuild_fail_alloc); + + portMemCopy(pSignatureVa, memdescGetSize(pKernelGsp->pSignatureMemdesc), + pStockData, stockSize); + + memdescUnmapInternal(pGpu, pKernelGsp->pSignatureMemdesc, 0); + + if (pKernelGsp->pWprMeta != NULL) + { + pKernelGsp->pWprMeta->sysmemAddrOfSignature = + memdescGetPhysAddr(pKernelGsp->pSignatureMemdesc, AT_GPU, 0); + pKernelGsp->pWprMeta->sizeOfSignature = + memdescGetSize(pKernelGsp->pSignatureMemdesc); + } + + if (pKernelGsp->pWprMetaDescriptor != NULL) + memdescFlushCpuCaches(pGpu, pKernelGsp->pWprMetaDescriptor); + + return NV_OK; + +rebuild_fail_alloc: + memdescFree(pKernelGsp->pSignatureMemdesc); + +rebuild_fail_create: + memdescDestroy(pKernelGsp->pSignatureMemdesc); + pKernelGsp->pSignatureMemdesc = NULL; + + return status; +} + +/* ------------------------------------------------------------------------- + * PLM gates + * ------------------------------------------------------------------------- */ + +/* + * Each entry is one SEC2 Booter round trip: point the payload at addr, run + * Booter Load, confirm the register reads back as value. + * + * The PCIe entries have to sit in this table rather than in a second pass of + * their own - by the time the first loop finishes, the Booter is no longer in + * a state where further payloads take effect. + */ +static const struct +{ + NvU32 addr; + NvU32 value; + const char *name; +} cmpPlmTable[] = { + { 0x001fa7ccU, 0xfffff0ffU, "WPR_CFG" }, + { 0x009a0148U, 0xffffffffU, "FBPA" }, + { 0x001fa7c4U, 0xffffffffU, "WPR" }, + { 0x00823804U, 0xffffffffU, "FEAT" }, + { 0x00088ff4U, 0xffffffffU, "XVE" }, + { 0x00088ab4U, 0xffffffffU, "XVE_B" }, + { 0x00088ff8U, 0xffffffffU, "XVE_C" }, + { 0x00823b00U, 0xffffffffU, "FEAT2" }, + { 0x008200fcU, 0xffffffffU, "OPT_PLM" }, + { 0x009a3c7cU, 0xffffffffU, "FBPA_PLL0" }, + { 0x009a3c80U, 0xffffffffU, "FBPA_PLL1" }, + { 0x009a3c84U, 0xffffffffU, "FBPA_PLL2" }, + { 0x00088fe8U, 0xffffffffU, "XVE_PLM" }, + { 0x00088fecU, 0xffffffffU, "XVE_CYA_PLM" }, + { 0x0008872cU, 0x0000000aU, "XVE_FUSE_OVR" }, + { 0x0008841cU, 0x4034ad00U, "XVE_CYA_SPD" }, + { 0x000880a8U, 0x00000002U, "XVE_TARGET" }, +}; + +static void +_cmpOpenPlmGates(OBJGPU *pGpu, KernelGsp *pKernelGsp, NvU32 wpr2Lo, NvU32 wpr2Hi) +{ + NvU32 idx, attempt; + + for (idx = 0; idx < NV_ARRAY_ELEMENTS(cmpPlmTable); idx++) + { + NvBool opened = NV_FALSE; + + for (attempt = 0; attempt < 2 && !opened; attempt++) + { + NV_STATUS status; + NvU32 regVal; + + /* Booter Load clobbers the WPR2 window; put it back each round. */ + GPU_REG_WR32(pGpu, CMP_REG_WPR2_LO, wpr2Lo); + GPU_REG_WR32(pGpu, CMP_REG_WPR2_HI, wpr2Hi); + + status = _cmpRefillPayload(pGpu, pKernelGsp, + cmpPlmTable[idx].addr, cmpPlmTable[idx].value); + if (status != NV_OK) + continue; + + status = kgspExecuteBooterLoad_HAL(pGpu, pKernelGsp, + memdescGetPhysAddr(pKernelGsp->pWprMetaDescriptor, AT_GPU, 0)); + + regVal = GPU_REG_RD32(pGpu, cmpPlmTable[idx].addr); + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: PLM[%u] %s(0x%x) attempt=%u status=0x%x reg=0x%08x\n", + idx, cmpPlmTable[idx].name, cmpPlmTable[idx].addr, + attempt, status, regVal); + + if (regVal == cmpPlmTable[idx].value) + opened = NV_TRUE; + } + + if (!opened) + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: FAILED to open %s after 2 attempts\n", + cmpPlmTable[idx].name); + } +} + +/* ------------------------------------------------------------------------- + * PCIe Gen2 + * ------------------------------------------------------------------------- */ + +/* + * Ask the link to retrain at Gen2. The PLM gates guarding the XP registers + * were opened by _cmpOpenPlmGates(), so these writes stick. + */ +static void +_cmpRetrainGen2(OBJGPU *pGpu) +{ + NvU32 xpCfg0 = GPU_REG_RD32(pGpu, CMP_REG_XP_CFG0); + NvU32 xpLctrl2 = GPU_REG_RD32(pGpu, CMP_REG_XP_LCTRL2); + NvU32 xpCya0 = GPU_REG_RD32(pGpu, CMP_REG_XP_CYA0); + NvU32 cfg0Now, cfg0After, linkCtrlStat; + NvU32 i; + + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: PCIe pre: CFG0=0x%08x LCTRL2=0x%08x CYA0=0x%08x\n", + xpCfg0, xpLctrl2, xpCya0); + + /* Clear the CYA bits that pin the link to Gen1, then select Gen2. */ + GPU_REG_WR32(pGpu, CMP_REG_XP_CYA0, xpCya0 & ~0x00802005U); + GPU_REG_WR32(pGpu, CMP_REG_XP_CFG0, (xpCfg0 & ~0xC0000U) | 0x80000U); + GPU_REG_WR32(pGpu, CMP_REG_XP_LCTRL2, (xpLctrl2 & ~0xF0000U) | 0x20000U); + + /* The root port has to agree on the target speed or it will refuse. */ + { + OBJCL *pCl = SYS_GET_CL(SYS_GET_INSTANCE()); + PORTDATA *pUpPort = &pGpu->gpuClData.upstreamPort; + + if (pCl != NULL && pUpPort->addr.valid) + { + NvU32 lnkCtl2Off = pUpPort->PCIECapPtr + 0x30U; + NvU16 rpLnkCtl2 = clPcieReadWord(pCl, + pUpPort->addr.domain, pUpPort->addr.bus, + pUpPort->addr.device, pUpPort->addr.func, lnkCtl2Off); + NvU16 rpLnkCtl2New = (rpLnkCtl2 & ~0xFU) | 0x2U; + + clPcieWriteWord(pCl, + pUpPort->addr.domain, pUpPort->addr.bus, + pUpPort->addr.device, pUpPort->addr.func, + lnkCtl2Off, rpLnkCtl2New); + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: PCIe root port LnkCtl2 @ 0x%x: 0x%04x -> 0x%04x\n", + lnkCtl2Off, rpLnkCtl2, rpLnkCtl2New); + } + else + { + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: PCIe upstream port not valid, cannot set root target\n"); + } + } + + /* Trigger the directed speed change and wait for the LTSSM to settle. */ + cfg0Now = GPU_REG_RD32(pGpu, CMP_REG_XP_CFG0); + GPU_REG_WR32(pGpu, CMP_REG_XP_CFG0, (cfg0Now & ~0xFU) | 0x1U); + + for (i = 0; i < 50; i++) + { + osDelay(10); + if ((GPU_REG_RD32(pGpu, CMP_REG_XP_CFG0) & 0x10U) == 0) + break; + } + + cfg0After = GPU_REG_RD32(pGpu, CMP_REG_XP_CFG0); + GPU_REG_WR32(pGpu, CMP_REG_XP_CFG0, cfg0After & ~0xFU); + + linkCtrlStat = GPU_REG_RD32(pGpu, CMP_REG_XVE_LINK_CTRL_STAT); + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: PCIe retrain done (polls=%u): LinkCtrlStat=0x%08x speed=%u width=x%u\n", + i, linkCtrlStat, + (linkCtrlStat >> 16) & 0xFU, + (linkCtrlStat >> 20) & 0x3FU); +} + +/* ------------------------------------------------------------------------- + * The unlock + * ------------------------------------------------------------------------- */ + +NV_STATUS +cmpUnlockPreBoot(OBJGPU *pGpu, KernelGsp *pKernelGsp, GSP_FIRMWARE *pGspFw) +{ + NvU32 devId = pGpu->idInfo.PCIDeviceID >> 16; + NvU32 wpr2Lo, wpr2Hi; + NvU32 cfg1Value, lmrValue; + NV_STATUS status; + + if (!cmpUnlockIsTarget(pGpu)) + return NV_OK; + + wpr2Lo = GPU_REG_RD32(pGpu, CMP_REG_WPR2_LO); + wpr2Hi = GPU_REG_RD32(pGpu, CMP_REG_WPR2_HI); + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: saved WPR2 lo=0x%08x hi=0x%08x\n", wpr2Lo, wpr2Hi); + + _cmpOpenPlmGates(pGpu, pKernelGsp, wpr2Lo, wpr2Hi); + + GPU_REG_WR32(pGpu, CMP_REG_WPR2_LO, wpr2Lo); + GPU_REG_WR32(pGpu, CMP_REG_WPR2_HI, wpr2Hi); + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: PLMs: FEAT=0x%08x FBPA=0x%08x WPR=0x%08x WPR_CFG=0x%08x\n", + GPU_REG_RD32(pGpu, 0x00823804U), + GPU_REG_RD32(pGpu, 0x009a0148U), + GPU_REG_RD32(pGpu, 0x001fa7c4U), + GPU_REG_RD32(pGpu, 0x001fa7ccU)); + + /* With the gates open, write the real configuration. */ + if (devId == CMPUNLOCK_DEVID_8GB) + { + cfg1Value = 0x02779000U; + lmrValue = 0x0000020BU; + } + else + { + cfg1Value = 0x02669000U; + lmrValue = 0x0000028AU; + } + + GPU_REG_WR32(pGpu, CMP_REG_SM_SPEED_0, 0x88888888U); + GPU_REG_WR32(pGpu, CMP_REG_SM_SPEED_1, 0x00000008U); + GPU_REG_WR32(pGpu, CMP_REG_FBPA_CFG1, cfg1Value); + GPU_REG_WR32(pGpu, CMP_REG_MMU_LMR, lmrValue); + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: POST-WRITE SS0=0x%08x SS1=0x%08x CFG1=0x%08x LMR=0x%08x (devId=0x%x)\n", + GPU_REG_RD32(pGpu, CMP_REG_SM_SPEED_0), + GPU_REG_RD32(pGpu, CMP_REG_SM_SPEED_1), + GPU_REG_RD32(pGpu, CMP_REG_FBPA_CFG1), + GPU_REG_RD32(pGpu, CMP_REG_MMU_LMR), + devId); + + _cmpRetrainGen2(pGpu); + + /* Put the real signature back before GSP boots. */ + status = _cmpRebuildStockSignature(pGpu, pKernelGsp); + if (status != NV_OK) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: rebuild stock signature failed: 0x%x\n", status); + return status; + } + + /* FB size changed under us, so the WPR layout has to be recomputed. */ + NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kgspPopulateWprMeta_HAL(pGpu, pKernelGsp, pGspFw)); + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: WPR meta updated fbSize=0x%016llx wprStart=0x%016llx " + "wprEnd=0x%016llx heapOffset=0x%016llx heapSize=0x%016llx\n", + pKernelGsp->pWprMeta->fbSize, + pKernelGsp->pWprMeta->gspFwWprStart, + pKernelGsp->pWprMeta->gspFwWprEnd, + pKernelGsp->pWprMeta->gspFwHeapOffset, + pKernelGsp->pWprMeta->gspFwHeapSize); + + return NV_OK; +} + +/* ------------------------------------------------------------------------- + * Static config info + * ------------------------------------------------------------------------- */ + +void +cmpUnlockFixStaticInfo(OBJGPU *pGpu, KernelGsp *pKernelGsp) +{ + GspStaticConfigInfo *pGSCI; + NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS *pFbRegionInfoParams; + NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO *pLastRegion; + NvU64 targetFbBytes, highLimit; + NvU32 numRegions; + + if (!cmpUnlockIsTarget(pGpu)) + return; + + pGSCI = &pKernelGsp->gspStaticInfo; + pFbRegionInfoParams = &pGSCI->fbRegionInfoParams; + targetFbBytes = _cmpUnlockedFbBytes(pGpu); + numRegions = pFbRegionInfoParams->numFBRegions; + + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: static-info BEFORE: fb_length=0x%llx numRegions=%u\n", + pGSCI->fb_length, numRegions); + + pGSCI->fb_length = targetFbBytes; + + if (numRegions == 0 || numRegions > NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_MAX_ENTRIES) + return; + + pLastRegion = &pFbRegionInfoParams->fbRegion[numRegions - 1]; + highLimit = targetFbBytes - 1; + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: last region[%u] base=0x%llx limit=0x%llx reserved=0x%llx\n", + numRegions - 1, pLastRegion->base, pLastRegion->limit, pLastRegion->reserved); + + if (pLastRegion->limit < highLimit) + { + pLastRegion->limit = highLimit; + pLastRegion->reserved = pLastRegion->limit - pLastRegion->base + 1; + pLastRegion->supportCompressed = NV_TRUE; + pLastRegion->supportISO = NV_TRUE; + pLastRegion->performance = 20; + } + + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: static-info AFTER: fb_length=0x%llx last_limit=0x%llx\n", + pGSCI->fb_length, pLastRegion->limit); +} + +/* ------------------------------------------------------------------------- + * HBM PLL overclock + * + * Both halves are compiled out unless the build sets CMPUNLOCK_MCLK_NDIV + * (driver/build.sh passes -DCMPUNLOCK_MCLK_NDIV=N for --mclk-ndiv=N). + * + * The sequence is VBIOS-agnostic: the stock NDIV is read out of the PLL + * rather than assumed, and every COEFF write is a read-modify-write that + * keeps the MDIV/PDIV the VBIOS programmed. + * ------------------------------------------------------------------------- */ + +void +cmpUnlockPostBooterLoad(OBJGPU *pGpu, KernelGsp *pKernelGsp) +{ + if (!cmpUnlockIsTarget(pGpu)) + return; + + /* + * Booter Load is the last thing that can silently undo the unlock, so + * report what the gated registers actually ended up holding. + */ + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK: post-BooterLoad verify PLM=0x%08x SS0=0x%08x SS1=0x%08x " + "CFG1=0x%08x LMR=0x%08x\n", + GPU_REG_RD32(pGpu, 0x00823804U), + GPU_REG_RD32(pGpu, CMP_REG_SM_SPEED_0), + GPU_REG_RD32(pGpu, CMP_REG_SM_SPEED_1), + GPU_REG_RD32(pGpu, CMP_REG_FBPA_CFG1), + GPU_REG_RD32(pGpu, CMP_REG_MMU_LMR)); + +#ifdef CMPUNLOCK_MCLK_NDIV + { + const NvU32 newNdiv = CMPUNLOCK_MCLK_NDIV; + NvU32 fbpaIdx, pollIdx; + NvU32 fbpaCount = 0, failCount = 0; + NvU32 plm0, fbio0, curNdiv; + NvU32 ddll0, calSt0 = 0, calSt1 = 0; + + plm0 = GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_PLM); + curNdiv = (GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_COEFF) >> 8) & 0xFFU; + + if ((plm0 & 0x10U) == 0) + { + NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: aborted, PLM=0x%08x (bit4 closed)\n", plm0); + return; + } + + NV_PRINTF(LEVEL_ERROR, + "HBMPLL_OC: start NDIV %u->%u (%u->%u MHz) devid=0x%04x vbios=%s PLM=0x%08x\n", + curNdiv, newNdiv, 27 * curNdiv, 27 * newNdiv, + pGpu->idInfo.PCIDeviceID >> 16, pKernelGsp->vbiosVersionStr, plm0); + + /* 1. Assert MEMCLK_CHANGE_ALERT (FBIO broadcast bit 31) */ + fbio0 = GPU_REG_RD32(pGpu, CMP_REG_FBIO_BROADCAST); + GPU_REG_WR32(pGpu, CMP_REG_FBIO_BROADCAST, fbio0 | 0x80000000U); + + /* 2. Enter HBM self-refresh */ + GPU_REG_WR32(pGpu, CMP_REG_HBM_SELF_REFRESH, 0x00000001U); + osDelay(5); + + /* 3. PLL cycle on each active FBPA */ + for (fbpaIdx = 0; fbpaIdx < CMP_FBPA_COUNT; fbpaIdx++) + { + NvU32 base = CMP_FBPA_BASE + fbpaIdx * CMP_FBPA_STRIDE; + NvU32 cfgAddr = base + CMP_FBPA_PLL_CFG_OFFSET; + NvU32 coeffAddr = base + CMP_FBPA_PLL_COEFF_OFFSET; + NvU32 origCfg = GPU_REG_RD32(pGpu, cfgAddr); + NvU32 origCoeff = GPU_REG_RD32(pGpu, coeffAddr); + NvU32 newCoeff, lockCfg = 0; + + if (origCfg == 0 || origCoeff == 0 || CMP_IS_PRI_ERROR(origCfg)) + continue; + + fbpaCount++; + + GPU_REG_WR32(pGpu, cfgAddr, origCfg & ~0x09U); + osDelay(2); + + newCoeff = (origCoeff & ~0xFF00U) | ((newNdiv & 0xFFU) << 8); + GPU_REG_WR32(pGpu, coeffAddr, newCoeff); + + GPU_REG_WR32(pGpu, cfgAddr, (origCfg | 0x09U) & ~0x20U); + + for (pollIdx = 0; pollIdx < 200; pollIdx++) + { + osDelay(1); + lockCfg = GPU_REG_RD32(pGpu, cfgAddr); + if (lockCfg & 0x20U) + break; + } + + if (!(lockCfg & 0x20U)) + { + NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: FBPA%u PLL lock timeout\n", fbpaIdx); + failCount++; + continue; + } + + GPU_REG_WR32(pGpu, cfgAddr, lockCfg & ~0x1000U); + } + + /* 4. Exit self-refresh */ + GPU_REG_WR32(pGpu, CMP_REG_HBM_SELF_REFRESH, 0x00000000U); + osDelay(10); + + /* 5. DDLL calibration */ + ddll0 = GPU_REG_RD32(pGpu, CMP_REG_DDLL_CAL); + GPU_REG_WR32(pGpu, CMP_REG_DDLL_CAL, ddll0 | 0x40U); + osDelay(10); + for (pollIdx = 0; pollIdx < 100; pollIdx++) + { + osDelay(1); + calSt0 = GPU_REG_RD32(pGpu, CMP_REG_DDLL_CAL_STATUS_0); + calSt1 = GPU_REG_RD32(pGpu, CMP_REG_DDLL_CAL_STATUS_1); + } + GPU_REG_WR32(pGpu, CMP_REG_DDLL_CAL, ddll0 & ~0x40U); + NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: DDLL cal status 0x%08x 0x%08x\n", calSt0, calSt1); + + /* 6. Clear MEMCLK_CHANGE_ALERT */ + GPU_REG_WR32(pGpu, CMP_REG_FBIO_BROADCAST, + GPU_REG_RD32(pGpu, CMP_REG_FBIO_BROADCAST) & ~0x80000000U); + + if (fbpaCount == 0) + NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: no active FBPAs found\n"); + else if (failCount > 0) + NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: %u/%u FBPAs failed to lock\n", + failCount, fbpaCount); + else + NV_PRINTF(LEVEL_ERROR, "HBMPLL_OC: done, %u FBPAs at NDIV=%u (%u MHz)\n", + fbpaCount, newNdiv, 27 * newNdiv); + } +#else + (void)pKernelGsp; +#endif +} + +void +cmpUnlockMclkPostGsp(OBJGPU *pGpu, KernelGsp *pKernelGsp) +{ +#ifdef CMPUNLOCK_MCLK_NDIV + const NvU32 newNdiv = CMPUNLOCK_MCLK_NDIV; + NvU32 coeffPre, plmPre, newCoeff, cfg = 0; + NvU32 i; + + if (!cmpUnlockIsTarget(pGpu)) + return; + + coeffPre = GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_COEFF); + plmPre = GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_PLM); + + /* Fall back to the 300W layout if the read came back as a PRI error. */ + if (coeffPre == 0 || CMP_IS_PRI_ERROR(coeffPre)) + newCoeff = (1U << 16) | (newNdiv << 8) | 1U; + else + newCoeff = (coeffPre & ~0xFF00U) | ((newNdiv & 0xFFU) << 8); + + NV_PRINTF(LEVEL_ERROR, + "HBMPLL_OC: post-GSP PRE: COEFF=0x%08x(NDIV=%u) PLM=0x%08x " + "devid=0x%04x vbios=%s newCOEFF=0x%08x\n", + coeffPre, (coeffPre >> 8) & 0xFFU, plmPre, + pGpu->idInfo.PCIDeviceID >> 16, pKernelGsp->vbiosVersionStr, newCoeff); + + GPU_REG_WR32(pGpu, CMP_REG_FBPA_PLL_COEFF_MC, newCoeff); + GPU_REG_WR32(pGpu, CMP_REG_PRI_FENCE, 0x0U); + for (i = 0; i < 500; i++) + (void)GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_CFG); + + for (i = 0; i < 200000; i++) + { + cfg = GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_CFG); + if (cfg & 0x20U) + break; + } + + NV_PRINTF(LEVEL_ERROR, + "HBMPLL_OC: post-GSP POST: COEFF=0x%08x(NDIV=%u) CFG=0x%08x lock=%u iter=%u\n", + GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_COEFF), + (GPU_REG_RD32(pGpu, CMP_REG_FBPA_PLL_COEFF) >> 8) & 0xFFU, + cfg, (cfg >> 5) & 1U, i); +#else + (void)pGpu; + (void)pKernelGsp; +#endif +} + +/* ------------------------------------------------------------------------- + * Late PMA extension + * + * GSP hands back a heap sized for the stock 8GB. The memory above that is + * present but sitting in a reserved FB region, so it is carved out and + * registered with PMA once everything else has finished initialising. + * ------------------------------------------------------------------------- */ + +NV_STATUS +cmpUnlockLateExtendPma(OBJGPU *pGpu) +{ + MemoryManager *pMemoryManager; + Heap *pHeap; + PMA *pPma; + PMA_REGION_DESCRIPTOR pmaRegion = {0}; + PMA_REGION_DESCRIPTOR *pFirstPmaRegionDesc = NULL; + FB_REGION_DESCRIPTOR *pCandidate = NULL; + NvU32 numPmaRegions = 0; + NvU32 candidateIdx = MAX_FB_REGIONS; + NvU64 pmaFreeBefore = 0, pmaTotalBefore = 0; + NvU64 pmaFreeAfter = 0, pmaTotalAfter = 0; + NvU64 heapFree = 0, heapTotal = 0; + NvU32 i; + NV_STATUS status; + + if (!cmpUnlockIsTarget(pGpu)) + return NV_OK; + + pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu); + if (pMemoryManager == NULL) + return NV_ERR_INVALID_ARGUMENT; + + pHeap = pMemoryManager->pHeap; + if (pHeap == NULL || pHeap->pPmaObject == NULL || !memmgrIsPmaInitialized(pMemoryManager)) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK_PMA: no PMA, skipped heap=%p init=%u\n", + pHeap, pHeap ? memmgrIsPmaInitialized(pMemoryManager) : 0); + return NV_OK; + } + + pPma = pHeap->pPmaObject; + heapGetFree(pHeap, &heapFree); + heapGetSize(pHeap, &heapTotal); + pmaGetFreeMemory(pPma, &pmaFreeBefore); + pmaGetTotalMemory(pPma, &pmaTotalBefore); + + for (i = 0; i < pMemoryManager->Ram.numFBRegions; i++) + { + FB_REGION_DESCRIPTOR *pRegion = &pMemoryManager->Ram.fbRegion[i]; + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK_PMA: region[%u] base=0x%llx limit=0x%llx " + "rsvd=%u rsvdSize=0x%llx intHeap=%u\n", + i, pRegion->base, pRegion->limit, + pRegion->bRsvdRegion, pRegion->rsvdSize, pRegion->bInternalHeap); + } + + status = pmaGetRegionInfo(pPma, &numPmaRegions, &pFirstPmaRegionDesc); + if (status != NV_OK) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK_PMA: pmaGetRegionInfo failed 0x%x\n", status); + return status; + } + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK_PMA: numFBRegions=%u numPmaRegions=%u stockFb=0x%llx " + "pma_total=0x%llx pma_free=0x%llx heap_total=0x%llx heap_free=0x%llx\n", + pMemoryManager->Ram.numFBRegions, numPmaRegions, + CMP_FB_BYTES_STOCK, pmaTotalBefore, pmaFreeBefore, heapTotal, heapFree); + + /* Find the highest reserved region that reaches past the stock limit. */ + for (i = 0; i < pMemoryManager->Ram.numFBRegions; i++) + { + FB_REGION_DESCRIPTOR *pRegion = &pMemoryManager->Ram.fbRegion[i]; + if (pRegion->bRsvdRegion && !pRegion->bInternalHeap && + pRegion->limit >= CMP_FB_BYTES_STOCK && pRegion->base <= pRegion->limit && + (pCandidate == NULL || pRegion->limit > pCandidate->limit)) + { + pCandidate = pRegion; + candidateIdx = i; + } + } + + if (pCandidate == NULL) + { + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK_PMA: no high reserved region found " + "(looking for bRsvdRegion && limit>=0x%llx)\n", CMP_FB_BYTES_STOCK); + return NV_OK; + } + + pmaRegion.base = NV_MAX(pCandidate->base, CMP_FB_BYTES_STOCK); + pmaRegion.limit = pCandidate->limit; + pmaRegion.performance = pCandidate->performance; + pmaRegion.bSupportCompressed = NV_TRUE; + pmaRegion.bSupportISO = pCandidate->bSupportISO; + pmaRegion.bProtected = pCandidate->bProtected; + + if (pmaRegion.base > pmaRegion.limit) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK_PMA: empty range base=0x%llx > limit=0x%llx\n", + pmaRegion.base, pmaRegion.limit); + return NV_OK; + } + + if (pmaIsPmaManaged(pPma, pmaRegion.base, pmaRegion.limit)) + { + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK_PMA: already managed base=0x%llx limit=0x%llx\n", + pmaRegion.base, pmaRegion.limit); + return NV_OK; + } + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK_PMA: registering candidate=%u base=0x%llx limit=0x%llx " + "cand_base=0x%llx cand_limit=0x%llx pma_region_id=%u\n", + candidateIdx, pmaRegion.base, pmaRegion.limit, + pCandidate->base, pCandidate->limit, numPmaRegions); + + /* Splitting the candidate needs a spare FB region slot. */ + if (pCandidate->base < CMP_FB_BYTES_STOCK && + pMemoryManager->Ram.numFBRegions >= MAX_FB_REGIONS) + { + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK_PMA: no FB region slot for split, numRegions=%u max=%u\n", + pMemoryManager->Ram.numFBRegions, MAX_FB_REGIONS); + return NV_ERR_INSUFFICIENT_RESOURCES; + } + + status = pmaRegisterRegion(pPma, numPmaRegions, NV_FALSE, &pmaRegion, 0, NULL); + + if (status == NV_OK) + { + if (pCandidate->base < CMP_FB_BYTES_STOCK) + { + /* Straddles the stock limit: keep the low half reserved, publish the high half. */ + FB_REGION_DESCRIPTOR publicRegion = *pCandidate; + publicRegion.base = CMP_FB_BYTES_STOCK; + publicRegion.limit = pCandidate->limit; + publicRegion.rsvdSize = 0; + publicRegion.bRsvdRegion = NV_FALSE; + publicRegion.bInternalHeap = NV_FALSE; + publicRegion.bSupportCompressed = NV_FALSE; + + pCandidate->limit = CMP_FB_BYTES_STOCK - 1; + pCandidate->rsvdSize = NV_MIN(pCandidate->rsvdSize, + pCandidate->limit - pCandidate->base + 1); + + pMemoryManager->Ram.fbRegion[pMemoryManager->Ram.numFBRegions] = publicRegion; + pMemoryManager->Ram.numFBRegions++; + } + else + { + /* Entirely above the stock limit: publish it as-is. */ + pCandidate->bRsvdRegion = NV_FALSE; + pCandidate->rsvdSize = 0; + pCandidate->bInternalHeap = NV_FALSE; + pCandidate->bSupportCompressed = NV_FALSE; + } + memmgrRegenerateFbRegionPriority(pGpu, pMemoryManager); + } + + pmaGetFreeMemory(pPma, &pmaFreeAfter); + pmaGetTotalMemory(pPma, &pmaTotalAfter); + + NV_PRINTF(LEVEL_ERROR, + "CMPUNLOCK_PMA: status=0x%x pma_total 0x%llx->0x%llx pma_free 0x%llx->0x%llx\n", + status, pmaTotalBefore, pmaTotalAfter, pmaFreeBefore, pmaFreeAfter); + + return status; +} diff --git a/driver/src/cmpunlock.h b/driver/src/cmpunlock.h new file mode 100644 index 0000000..6cd7022 --- /dev/null +++ b/driver/src/cmpunlock.h @@ -0,0 +1,96 @@ +/* + * cmpunlock - NVIDIA CMP 170HX (GA100) unlock logic. + * + * Every behavioural change lives in cmpunlock.c. The stock driver sources are + * patched only with the small hook calls declared below, so moving to a new + * nvidia-open release means re-checking a handful of one-line insertions + * instead of re-merging several hundred lines of diff. + * + * On any GPU that is not a CMP 170HX every hook is a no-op, so the patched + * modules stay safe to run on a mixed system. + */ + +#ifndef CMPUNLOCK_H +#define CMPUNLOCK_H + +#include "core/core.h" +#include "gpu/gpu.h" +#include "gpu/gsp/kernel_gsp.h" + +/* PCI device IDs of the two CMP 170HX variants (upper half of PCIDeviceID). */ +#define CMPUNLOCK_DEVID_8GB 0x20C2U +#define CMPUNLOCK_DEVID_10GB 0x2082U + +/* + * NV_TRUE if this GPU is a CMP 170HX. Every other entry point calls this + * first, so hooks can be placed unconditionally. + */ +NvBool cmpUnlockIsTarget(OBJGPU *pGpu); + +/* + * Size of the GSP signature buffer. On a CMP the buffer doubles as the SEC2 + * Booter payload and has to be large enough for it; elsewhere the stock size + * is returned unchanged. + * + * Hook: _kgspCreateSignatureMemdesc(), memdescCreate() size argument. + */ +NvU64 cmpUnlockSignatureSize(OBJGPU *pGpu, NvU64 stockSize); + +/* + * Fill the freshly allocated signature buffer. Stashes the stock signature so + * it can be restored later (see cmpUnlockPreBoot) and writes the Booter + * payload in its place. + * + * Returns NV_TRUE when it took ownership of the buffer, NV_FALSE when the + * caller should perform its normal copy. + * + * Hook: _kgspCreateSignatureMemdesc(), replacing the portMemCopy(). + */ +NvBool cmpUnlockFillSignature(OBJGPU *pGpu, KernelGsp *pKernelGsp, + NvU8 *pSignatureVa, NvU64 signatureVaSize, + const void *pStockSignature, NvU64 stockSignatureSize); + +/* + * The unlock itself. Runs in the window after kgspPrepareForBootstrap_HAL() + * and before GSP is released: opens the PLM gates through the SEC2 Booter, + * writes the SM/memory/PCIe configuration, retrains the link at Gen2, then + * restores the stock signature so GSP boots normally. + * + * Hook: _kgspBootGspRm(), after kgspPrepareForBootstrap_HAL(). + */ +NV_STATUS cmpUnlockPreBoot(OBJGPU *pGpu, KernelGsp *pKernelGsp, GSP_FIRMWARE *pGspFw); + +/* + * Widen the framebuffer geometry GSP reported back to the unlocked size. + * + * Hook: kgspInitRm_IMPL(), after the static config info is fetched. + */ +void cmpUnlockFixStaticInfo(OBJGPU *pGpu, KernelGsp *pKernelGsp); + +/* + * Runs right after Booter Load, while the PLM gates are still open. Reports + * what the unlock actually took effect as, then performs the first half of + * the HBM PLL overclock (a per-FBPA PLL cycle). + * + * Hook: kgspBootstrap_TU102(), after Booter Load succeeds. + */ +void cmpUnlockPostBooterLoad(OBJGPU *pGpu, KernelGsp *pKernelGsp); + +/* + * Second half of the HBM PLL overclock: a multicast COEFF write once GSP is + * up. Like the first half, a no-op unless the build defines + * CMPUNLOCK_MCLK_NDIV. + * + * Hook: kgspInitRm_IMPL(), after kgspStartLogPolling(). + */ +void cmpUnlockMclkPostGsp(OBJGPU *pGpu, KernelGsp *pKernelGsp); + +/* + * Hand the memory above the stock 8GB limit to PMA. Has to run late, once the + * heap and PMA are fully initialised. + * + * Hook: RmInitNvDevice() in osinit.c, after the GPU finishes initialising. + */ +NV_STATUS cmpUnlockLateExtendPma(OBJGPU *pGpu); + +#endif /* CMPUNLOCK_H */ diff --git a/driver/src/cmpunlock_config.h b/driver/src/cmpunlock_config.h new file mode 100644 index 0000000..74f6589 --- /dev/null +++ b/driver/src/cmpunlock_config.h @@ -0,0 +1,17 @@ +/* + * cmpunlock build configuration. + * + * driver/build.sh overwrites this file in the extracted source tree. The copy + * kept in the repository is the default: no HBM overclock. + * + * Defining CMPUNLOCK_MCLK_NDIV to N compiles in the HBM PLL overclock and + * targets N * 27 MHz. Leaving it undefined compiles both halves of the + * overclock out entirely. + */ + +#ifndef CMPUNLOCK_CONFIG_H +#define CMPUNLOCK_CONFIG_H + +/* #define CMPUNLOCK_MCLK_NDIV 70 */ + +#endif /* CMPUNLOCK_CONFIG_H */ diff --git a/install.sh b/install.sh index 3d4f4b0..08f722d 100755 --- a/install.sh +++ b/install.sh @@ -489,16 +489,11 @@ for i in "${!GPU_BDFS[@]}"; do done echo "" echo "Next:" -echo -e " 1. Cold reboot recommended: ${CYAN}sudo shutdown -h now${NC} (then power on)" -echo -e " 2. Verify all GPUs: ${CYAN}sudo ./verify.sh${NC}" -echo -e " 3. Verify PCIe Gen2: ${CYAN}nvidia-smi --query-gpu=pcie.link.gen.current,pcie.link.gen.max --format=csv${NC} (expect 2,2)" -echo -e " 4. Or check manually: ${CYAN}nvidia-smi${NC}" -echo -e " 5. Unlock logs: ${CYAN}sudo dmesg | grep SEC2_DEBUG${NC}" -if [[ -n "${MCLK_NDIV}" ]]; then - echo -e " Memory clock logs: ${CYAN}sudo dmesg | grep HBMPLL_OC${NC} (expect NDIV=${MCLK_NDIV})" -fi +echo -e " 1. Cold reboot: ${CYAN}sudo shutdown -h now${NC} (then power on)" +echo -e " 2. Benchmark: ${CYAN}./benchmark/nvidia_bench${NC}" +echo -e " 3. Unlock logs: ${CYAN}sudo dmesg | grep CMPUNLOCK${NC}" if [[ -n "${IOMMU_PARAMS}" && "${IOMMU_STATUS}" != "skipped" ]]; then - echo -e " 6. Verify IOMMU after reboot: ${CYAN}cat /proc/cmdline${NC} and ${CYAN}ls /sys/class/iommu${NC}" + echo -e " 4. Verify IOMMU after reboot: ${CYAN}cat /proc/cmdline${NC}" fi echo "" echo "Log saved to: ${LOG_FILE}" diff --git a/remove.sh b/remove.sh index d16eac7..2940b01 100755 --- a/remove.sh +++ b/remove.sh @@ -2,9 +2,6 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SERVICE_NAME="cmpunlocker" -SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" -INSTALL_DIR="/opt/cmpunlocker" if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' @@ -15,15 +12,7 @@ fi info() { echo -e "${CYAN}==>${NC} $*"; } ok() { echo -e "${GREEN}✓${NC} $*"; } warn() { echo -e "${YELLOW}!${NC} $*"; } -err() { echo -e "${RED}✗${NC} $*" >&2; } -die() { err "$*"; exit 1; } - -step() { - echo "" - echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" - echo -e "${CYAN}$*${NC}" - echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" -} +die() { echo -e "${RED}✗${NC} $*" >&2; exit 1; } echo "" echo -e "${CYAN}╔════════════════════════════════════════╗${NC}" @@ -33,20 +22,16 @@ echo "" if [[ "${1:-}" != "--yes" && "${1:-}" != "-y" ]]; then warn "This removes cmpunlocker patched kernel modules:" - echo " - Stops cmpunlocker systemd service" echo " - Removes /lib/modules/*/updates/cmpunlocker/" - echo " - Removes ${INSTALL_DIR} (legacy install dir, if present)" + echo " - Rebuilds initramfs" echo " - Reloads stock NVIDIA modules (brief display interruption)" - echo " - Removes cmpretrain service / modprobe Gen2 helpers" echo " - Restores the pre-install kernel command line (reverts IOMMU changes)" echo "" echo "Run: sudo ./remove.sh --yes" exit 1 fi -step "Step 1/5: Verifying root privileges" [[ "${EUID}" -eq 0 ]] || die "Run as root: sudo ./remove.sh --yes" -ok "Running as root" LOG_DIR="${SCRIPT_DIR}/logs" if ! mkdir -p "${LOG_DIR}" 2>/dev/null || [[ ! -w "${LOG_DIR}" ]]; then @@ -55,38 +40,7 @@ fi LOG_FILE="${LOG_DIR}/remove_$(date +%Y%m%d_%H%M%S).log" exec > >(tee -a "${LOG_FILE}") 2>&1 -step "Step 2/5: Stopping leftover cmpunlocker service" -if systemctl is-active --quiet "${SERVICE_NAME}" 2>/dev/null; then - systemctl stop "${SERVICE_NAME}" || true - ok "Service stopped" -else - warn "Service not running" -fi -if systemctl is-enabled --quiet "${SERVICE_NAME}" 2>/dev/null; then - systemctl disable "${SERVICE_NAME}" || true - ok "Service disabled" -fi -if [[ -f "${SERVICE_FILE}" ]]; then - rm -f "${SERVICE_FILE}" - systemctl daemon-reload - systemctl reset-failed "${SERVICE_NAME}" 2>/dev/null || true - ok "Removed ${SERVICE_FILE}" -fi -pkill -f "${INSTALL_DIR}/daemon/watchdog.py" 2>/dev/null || true - -for legacy_unit in cmpretrain.service cmp-gen2-retrain.service; do - systemctl disable --now "${legacy_unit}" 2>/dev/null || true - systemctl reset-failed "${legacy_unit}" 2>/dev/null || true -done -rm -f /etc/systemd/system/cmpretrain.service /usr/local/sbin/retrain.sh -rm -f /etc/systemd/system/cmp-gen2-retrain.service /usr/local/sbin/cmp-gen2-retrain.sh -rm -f /etc/modprobe.d/cmp-pcie-gen2.conf -systemctl disable --now gen2.service 2>/dev/null || true -systemctl reset-failed gen2.service 2>/dev/null || true -rm -f /etc/systemd/system/gen2.service /usr/local/sbin/gen2-hammer -systemctl daemon-reload 2>/dev/null || true -ok "Removed PCIe Gen2 helpers" - +info "Reverting IOMMU kernel parameters..." iommu_restored=0 for cfg in /etc/default/grub /etc/kernel/cmdline; do if [[ -f "${cfg}.cmpunlocker.bak" ]]; then @@ -105,10 +59,10 @@ if (( iommu_restored )); then fi ok "Reverted IOMMU kernel parameters (effective after reboot)" else - warn "No IOMMU config backup found — kernel command line left as-is" + info "No IOMMU config backup found — kernel command line left as-is" fi -step "Step 3/5: Removing patched modules and legacy files" +info "Removing patched modules..." mod_removed=0 kernels_touched=() shopt -s nullglob @@ -125,7 +79,7 @@ done [[ "${mod_removed}" -gt 0 ]] || warn "No patched kernel modules found" if [[ ${#kernels_touched[@]} -gt 0 ]]; then - info "Rebuilding initramfs so stock modules are packed again..." + info "Rebuilding initramfs..." for kernel in "${kernels_touched[@]}"; do if command -v update-initramfs &>/dev/null; then update-initramfs -u -k "${kernel}" 2>/dev/null || true @@ -136,26 +90,10 @@ if [[ ${#kernels_touched[@]} -gt 0 ]]; then if command -v mkinitcpio &>/dev/null && ! command -v update-initramfs &>/dev/null && ! command -v dracut &>/dev/null; then mkinitcpio -P 2>/dev/null || true fi - ok "initramfs rebuild attempted" + ok "initramfs rebuilt" fi -for gsp in /lib/firmware/nvidia/*/gsp_tu10x.bin; do - rm -f \ - "${gsp}.cmpunlocker.bak" \ - "${gsp}.cmpunlocker.patched" \ - "${gsp}.cmpunlocker.tmp" \ - "${gsp}.cmpunlocker.cleanup" \ - "${gsp}.cmpunlocker.pat" -done - -if [[ -d "${INSTALL_DIR}" ]]; then - rm -rf "${INSTALL_DIR}" - ok "Removed ${INSTALL_DIR}" -else - warn "${INSTALL_DIR} not found (ok for module-only installs)" -fi - -step "Step 4/5: Reloading stock NVIDIA driver" +info "Reloading stock NVIDIA driver..." if lsmod | grep -q '^nvidia'; then warn "Unloading NVIDIA modules (display may flicker)" for svc in gdm3 sddm lightdm display-manager; do @@ -196,14 +134,9 @@ else fi echo "" -echo -e "${CYAN}╔════════════════════════════════════════╗${NC}" -echo -e "${CYAN}║ cmpunlocker ║${NC}" -echo -e "${CYAN}╚════════════════════════════════════════╝${NC}" -echo "" - -echo "cmpunlocker has been removed from system." +ok "cmpunlocker removed" echo "Log saved to: ${LOG_FILE}" echo "" -echo "If the GPU or display is not working, reboot once:" +echo "If the GPU or display is not working, reboot:" echo -e " ${CYAN}sudo reboot${NC}" echo "" diff --git a/verify.sh b/verify.sh deleted file mode 100755 index ea44a8c..0000000 --- a/verify.sh +++ /dev/null @@ -1,221 +0,0 @@ -#!/bin/bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -KVER="$(uname -r)" -INSTALL_MOD_DIR="/lib/modules/${KVER}/updates/cmpunlocker" -INVENTORY_FILE="${INSTALL_MOD_DIR}/gpu_inventory" - -if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then - RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' -else - RED=""; GREEN=""; YELLOW=""; CYAN=""; NC="" -fi - -info() { echo -e "${CYAN}==>${NC} $*"; } -ok() { echo -e "${GREEN}✓${NC} $*"; } -warn() { echo -e "${YELLOW}!${NC} $*"; } -err() { echo -e "${RED}✗${NC} $*" >&2; } -die() { err "$*"; exit 1; } - -normalize_bus_id() { - local raw="$1" - raw="$(echo "${raw}" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')" - if [[ "${raw}" =~ ^([0-9a-f]+):([0-9a-f]{2}):([0-9a-f]{2})\.([0-9a-f])$ ]]; then - printf '%04x:%s:%s.%s\n' "$((16#${BASH_REMATCH[1]}))" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "${BASH_REMATCH[4]}" - elif [[ "${raw}" =~ ^[0-9a-f]{2}:[0-9a-f]{2}\.[0-9a-f]$ ]]; then - echo "0000:${raw}" - else - echo "${raw}" - fi -} - -profile_from_devid() { - case "$1" in - 20c2) echo "8gb" ;; - 2082) echo "10gb" ;; - *) echo "unsupported" ;; - esac -} - -expected_mib_for_profile() { - case "$1" in - 8gb) echo "65536" ;; - 10gb) echo "40960" ;; - *) echo "" ;; - esac -} - -is_unlocked_memory() { - local profile="$1" - local mem_mib="$2" - [[ "${mem_mib}" =~ ^[0-9]+$ ]] || return 1 - case "${profile}" in - 8gb) - (( mem_mib >= 60000 )) && return 0 - ;; - 10gb) - (( mem_mib >= 35000 && mem_mib < 60000 )) && return 0 - ;; - esac - return 1 -} - -is_stock_memory() { - local profile="$1" - local mem_mib="$2" - [[ "${mem_mib}" =~ ^[0-9]+$ ]] || return 1 - case "${profile}" in - 8gb) - (( mem_mib >= 7680 && mem_mib <= 8704 )) && return 0 - ;; - 10gb) - (( mem_mib >= 9728 && mem_mib <= 10752 )) && return 0 - ;; - esac - return 1 -} - -smi_memory_for_bus() { - local want="$1" - local line bus mem - while IFS= read -r line; do - [[ -n "${line}" ]] || continue - bus="$(normalize_bus_id "$(echo "${line}" | cut -d, -f1)")" - mem="$(echo "${line}" | cut -d, -f2 | tr -d '[:space:]')" - if [[ "${bus}" == "${want}" ]]; then - echo "${mem}" - return 0 - fi - done <<< "${SMI_MEM_CACHE}" -} - -echo "" -echo -e "${CYAN}╔════════════════════════════════════════╗${NC}" -echo -e "${CYAN}║ cmpunlocker ║${NC}" -echo -e "${CYAN}╚════════════════════════════════════════╝${NC}" -echo "" - -command -v nvidia-smi &>/dev/null || die "nvidia-smi not found" -SMI_MEM_CACHE="$(nvidia-smi --query-gpu=pci.bus_id,memory.total --format=csv,noheader,nounits 2>/dev/null || true)" -[[ -n "${SMI_MEM_CACHE}" ]] || die "nvidia-smi returned no GPU memory data" - -GPU_BDFS=() -GPU_DEVIDS=() -GPU_PROFILES=() -GPU_EXPECTED=() - -if [[ -r "${INVENTORY_FILE}" ]] && [[ -s "${INVENTORY_FILE}" ]]; then - info "Using inventory: ${INVENTORY_FILE}" - while read -r bdf devid profile expected || [[ -n "${bdf:-}" ]]; do - [[ -n "${bdf:-}" ]] || continue - [[ "${bdf}" =~ ^# ]] && continue - GPU_BDFS+=("$(normalize_bus_id "${bdf}")") - GPU_DEVIDS+=("${devid}") - GPU_PROFILES+=("${profile}") - GPU_EXPECTED+=("${expected}") - done < "${INVENTORY_FILE}" -else - info "No installed gpu_inventory; enumerating via lspci" - mapfile -t PCI_LINES < <(lspci -nn 2>/dev/null | grep -iE '10de:20c2|10de:2082' || true) - [[ ${#PCI_LINES[@]} -gt 0 ]] || die "No unlockable CMP 170HX GPU found (10de:20c2 / 10de:2082)" - for PCI_LINE in "${PCI_LINES[@]}"; do - PCI="$(echo "${PCI_LINE}" | awk '{print $1}')" - PCI_FULL="$(normalize_bus_id "${PCI}")" - DEVID="$(echo "${PCI_LINE}" | grep -oE '10de:[0-9a-fA-F]{4}' | head -1 | cut -d: -f2 | tr '[:upper:]' '[:lower:]')" - PROF="$(profile_from_devid "${DEVID}")" - [[ "${PROF}" != "unsupported" ]] || continue - EXP="$(expected_mib_for_profile "${PROF}")" - GPU_BDFS+=("${PCI_FULL}") - GPU_DEVIDS+=("${DEVID}") - GPU_PROFILES+=("${PROF}") - GPU_EXPECTED+=("${EXP}") - done -fi - -[[ ${#GPU_BDFS[@]} -gt 0 ]] || die "No unlockable GPUs to verify" - -failures=0 -printf "\n%-16s %-8s %-8s %-12s %-12s %s\n" "BDF" "PCI ID" "Variant" "Expect" "Actual" "Status" -for i in "${!GPU_BDFS[@]}"; do - bdf="${GPU_BDFS[$i]}" - devid="${GPU_DEVIDS[$i]}" - profile="${GPU_PROFILES[$i]}" - expected="${GPU_EXPECTED[$i]}" - actual="$(smi_memory_for_bus "${bdf}" || true)" - [[ -n "${actual}" ]] || actual="?" - - status="FAIL" - if is_unlocked_memory "${profile}" "${actual}"; then - status="OK" - ok "${bdf}: ${actual} MiB (unlocked ${profile})" - elif is_stock_memory "${profile}" "${actual}"; then - status="STOCK" - err "${bdf}: still stock ${actual} MiB (expect ~${expected})" - failures=$((failures + 1)) - elif [[ "${actual}" == "?" ]]; then - status="MISSING" - err "${bdf}: not found in nvidia-smi" - failures=$((failures + 1)) - else - status="UNEXPECTED" - err "${bdf}: unexpected ${actual} MiB (expect ~${expected} for ${profile})" - failures=$((failures + 1)) - fi - - printf "%-16s %-8s %-8s ~%-11s %-12s %s\n" "${bdf}" "${devid}" "${profile}" "${expected}" "${actual}" "${status}" -done - -echo "" -sec2_logs="$(dmesg 2>/dev/null | grep 'SEC2_DEBUG' || true)" -if [[ -n "${sec2_logs}" ]]; then - ok "dmesg contains SEC2_DEBUG unlock logs" - info "Sample:" - printf '%s\n' "${sec2_logs}" | tail -n 8 | sed 's/^/ /' -else - warn "No SEC2_DEBUG lines in dmesg (logs may have rotated; unlock can still be OK if memory is unlocked)" -fi - -installed_ndiv="$(cat "${INSTALL_MOD_DIR}/mclk_ndiv" 2>/dev/null || echo 'none')" -if [[ "${installed_ndiv}" != "none" && -n "${installed_ndiv}" ]]; then - echo "" - mclk_logs="$(dmesg 2>/dev/null | grep 'HBMPLL_OC' || true)" - if [[ -n "${mclk_logs}" ]]; then - ok "dmesg contains HBMPLL_OC logs (installed NDIV=${installed_ndiv}, $((installed_ndiv * 27)) MHz)" - printf '%s\n' "${mclk_logs}" | tail -n 6 | sed 's/^/ /' - else - warn "Installed with --mclk-ndiv=${installed_ndiv} but no HBMPLL_OC lines in dmesg" - warn "(logs may have rotated; otherwise the memory is still running at stock)" - fi -fi - -echo "" -if [[ -r "${INSTALL_MOD_DIR}/card_profile" ]]; then - info "Installed profile: $(cat "${INSTALL_MOD_DIR}/card_profile") / geometry: $(cat "${INSTALL_MOD_DIR}/unlock_geometry" 2>/dev/null || echo '?') / mclk_ndiv: ${installed_ndiv}" -fi - -if (( failures > 0 )); then - echo "" - die "${failures} GPU(s) failed unlock verification. Cold reboot if modules were just installed." -fi - -echo "" -ok "All ${#GPU_BDFS[@]} unlockable GPU(s) report unlocked memory" - -pcie_info="$(nvidia-smi --query-gpu=pci.bus_id,pcie.link.gen.current --format=csv,noheader 2>/dev/null || true)" -if [[ -n "${pcie_info}" ]]; then - echo "" - info "PCIe link speed:" - while IFS=, read -r bus gen; do - bus="$(echo "${bus}" | tr -d '[:space:]')" - gen="$(echo "${gen}" | tr -d '[:space:]')" - if [[ "${gen}" == "2" ]]; then - ok "${bus}: Gen${gen}" - elif [[ "${gen}" == "1" ]]; then - warn "${bus}: Gen${gen} (Gen2 retrain may not have completed)" - else - info "${bus}: Gen${gen}" - fi - done <<< "${pcie_info}" -fi -exit 0 -- 2.51.2 From 98ca85bf30cd78e33c9dd47399872cdec17cbd8b Mon Sep 17 00:00:00 2001 From: asm64-hooligan <52560948+asm64-hooligan@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:10:19 +0300 Subject: [PATCH 3/9] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 627cbcb..3bd6348 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,9 @@ Unlock tool for the NVIDIA CMP 170HX (GA100). Restores full SM compute, unlocked Below are memory and performance results after applying the unlock: -### Memory Unlock Results +### Unlock Results -memory unlock - -### Performance Benchmarks ([OpenCL-Benchmark](https://github.com/ProjectPhysX/OpenCL-Benchmark)) - -performance benchmarks +image --- -- 2.51.2 From 83f7199aab49cc6b5d5cd9d4463094f380e343ee Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 15:25:56 +0200 Subject: [PATCH 4/9] added compatibility with cuda11 --- benchmark/nvidia_bench.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/nvidia_bench.cu b/benchmark/nvidia_bench.cu index 5a02392..0c66a1c 100644 --- a/benchmark/nvidia_bench.cu +++ b/benchmark/nvidia_bench.cu @@ -57,7 +57,7 @@ // it weakly so older drivers skip the CUDA Cores line instead of dying with a // dynamic-loader "undefined symbol" before any output. #if defined(CUDART_VERSION) && CUDART_VERSION >= 11050 && defined(__GNUC__) -#pragma weak nvmlDeviceGetNumGpuCores +extern "C" nvmlReturn_t nvmlDeviceGetNumGpuCores(nvmlDevice_t, unsigned int *) __attribute__((weak)); #define HAVE_NUM_GPU_CORES 1 #endif -- 2.51.2 From eccb7e1851e9f0e1b91bbecd51b59bca935b109b Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 15:26:37 +0200 Subject: [PATCH 5/9] remove 8gb/10gb profiles --- README.md | 9 +--- docs/INSTALLATION.md | 7 --- driver/build.sh | 25 --------- install.sh | 125 ++++++++----------------------------------- 4 files changed, 22 insertions(+), 144 deletions(-) diff --git a/README.md b/README.md index 3bd6348..e2d679f 100644 --- a/README.md +++ b/README.md @@ -33,14 +33,7 @@ Below are memory and performance results after applying the unlock: sudo ./install.sh ``` -To force a certain memory profile: - -```bash -sudo ./install.sh --profile=8gb # 8GB card -> 64GB unlock -sudo ./install.sh --profile=10gb # 10GB card -> 40GB unlock -``` - -Then perform a cold reboot (full power off, then boot). +Then perform a cold reboot (full power off, then boot). The correct memory geometry is selected automatically from the PCI device ID (`0x20C2` = 8GB -> 64GB, `0x2082` = 10GB -> 40GB). ### HBM Memory Clock diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 981b683..623e5eb 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -16,13 +16,6 @@ sudo ./install.sh ``` -To force a certain memory profile: - -```bash -sudo ./install.sh --profile=8gb # 8GB card -> 64GB unlock -sudo ./install.sh --profile=10gb # 10GB card -> 40GB unlock -``` - To set the HBM memory clock (multiplier x 27 MHz, any VBIOS, both card variants): ```bash diff --git a/driver/build.sh b/driver/build.sh index 8713f35..4555d0b 100755 --- a/driver/build.sh +++ b/driver/build.sh @@ -113,32 +113,7 @@ for p in "${patches[@]}"; do done ok "All patches applied" -# -# The geometry is selected at runtime from the PCI device ID (see -# cmpUnlockPreBoot / cmpUnlockFixStaticInfo), so the profile is only a label -# recorded for the install summary. -# -PROFILE="${CMPUNLOCKER_CARD_PROFILE:-8gb}" -case "${PROFILE}" in - 8gb|8GB) PROFILE="8gb"; UNLOCK_LABEL="64GB" ;; - 10gb|10GB) PROFILE="10gb"; UNLOCK_LABEL="40GB" ;; - mixed|MIXED) PROFILE="mixed"; UNLOCK_LABEL="mixed" ;; - *) - die "Unknown CMPUNLOCKER_CARD_PROFILE='${PROFILE}' (use 8gb, 10gb, or mixed)" - ;; -esac -ok "Memory profile ${PROFILE}: unlock_geometry=${UNLOCK_LABEL} (chosen per PCI ID at runtime)" mkdir -p "${INSTALL_MOD_DIR}" -printf '%s\n' "${VERSION}" > "${INSTALL_MOD_DIR}/driver_version" -printf '%s\n' "${PROFILE}" > "${INSTALL_MOD_DIR}/card_profile" -printf '%s\n' "${UNLOCK_LABEL}" > "${INSTALL_MOD_DIR}/unlock_geometry" -printf '%s\n' "${MCLK_NDIV:-none}" > "${INSTALL_MOD_DIR}/mclk_ndiv" -if [[ -n "${CMPUNLOCKER_GPU_INVENTORY:-}" ]]; then - printf '%s\n' "${CMPUNLOCKER_GPU_INVENTORY}" > "${INSTALL_MOD_DIR}/gpu_inventory" - ok "Wrote gpu_inventory ($(echo "${CMPUNLOCKER_GPU_INVENTORY}" | grep -c . || true) GPU(s))" -else - : > "${INSTALL_MOD_DIR}/gpu_inventory" -fi info "Building modules for kernel ${KVER}..." cd "${SRC_DIR}" diff --git a/install.sh b/install.sh index 08f722d..46b7f33 100755 --- a/install.sh +++ b/install.sh @@ -8,32 +8,27 @@ LOG_DIR="${SCRIPT_DIR}/logs" mkdir -p "${LOG_DIR}" LOG_FILE="${LOG_DIR}/install_$(date +%Y%m%d_%H%M%S).log" -PROFILE_OVERRIDE="" CONFIGURE_IOMMU=0 MCLK_NDIV="" for arg in "$@"; do case "${arg}" in - --profile=8gb|--profile=8GB) PROFILE_OVERRIDE="8gb" ;; - --profile=10gb|--profile=10GB) PROFILE_OVERRIDE="10gb" ;; --iommu) CONFIGURE_IOMMU=1 ;; --mclk-ndiv=*) MCLK_NDIV="${arg#*=}" ;; -h|--help) cat <<'EOF' -Usage: sudo ./install.sh [--profile=8gb|10gb] [--iommu] [--mclk-ndiv=N] +Usage: sudo ./install.sh [--iommu] [--mclk-ndiv=N] - --profile=8gb Force 8GB metadata label (geometry is still chosen per PCI ID) - --profile=10gb Force 10GB metadata label (geometry is still chosen per PCI ID) --iommu Add iommu=pt to the kernel command line (see README for details) --mclk-ndiv=N HBM memory clock: set PLL multiplier (30-80), N * 27 MHz. Works on any VBIOS, on both 0x20C2 and 0x2082. Stock is 64 on 8GB 300W, 54 on 8GB 250W, 45 on 10GB. Without this flag the - overclock patches are not applied at all. + overclock is not applied at all. -Without --profile, each unlockable GPU is classified by PCI device ID: - 10de:20c2 → 8gb / 64GB unlock - 10de:2082 → 10gb / 40GB unlock +Memory geometry is selected automatically from PCI device ID: + 10de:20c2 → 8GB card → 64GB unlock + 10de:2082 → 10GB card → 40GB unlock -Multi-GPU and mixed 8GB+10GB systems are supported in one install. +Multi-GPU and mixed 8GB+10GB systems are supported. EOF exit 0 ;; @@ -115,11 +110,11 @@ echo -e "${CYAN}║ cmpunlocker ║${NC}" echo -e "${CYAN}╚════════════════════════════════════════╝${NC}" echo "" -step "Step 1/6: Verifying root privileges" +step "Verifying root privileges" [[ "${EUID}" -eq 0 ]] || die "Run as root: sudo ./install.sh" ok "Running as root" -step "Step 2/6: Detecting CMP 170HX GPU(s)" +step "Detecting CMP 170HX GPU(s)" mapfile -t PCI_LINES < <(lspci -nn 2>/dev/null | grep -iE '10de:20b0|10de:20c2|10de:2082' || true) [[ ${#PCI_LINES[@]} -gt 0 ]] || die "No CMP 170HX GPU found (10de:20b0 / 10de:20c2 / 10de:2082)" @@ -128,14 +123,9 @@ if command -v nvidia-smi &>/dev/null; then SMI_MEM_CACHE="$(nvidia-smi --query-gpu=pci.bus_id,memory.total --format=csv,noheader,nounits 2>/dev/null || true)" fi -GPU_BDFS=() -GPU_DEVIDS=() -GPU_PROFILES=() -GPU_EXPECTED=() -GPU_CURRENT=() +GPU_COUNT=0 COUNT_8GB=0 COUNT_10GB=0 -COUNT_UNSUPPORTED=0 for PCI_LINE in "${PCI_LINES[@]}"; do PCI="$(echo "${PCI_LINE}" | awk '{print $1}')" @@ -146,17 +136,12 @@ for PCI_LINE in "${PCI_LINES[@]}"; do [[ -n "${CUR_MEM}" ]] || CUR_MEM="?" if [[ "${PROF}" == "unsupported" ]]; then - COUNT_UNSUPPORTED=$((COUNT_UNSUPPORTED + 1)) - warn "GPU ${PCI_FULL} (10de:${DEVID}) — unlock path not gated for this ID; skipping" + warn "GPU ${PCI_FULL} (10de:${DEVID}) — not a supported device ID; skipping" continue fi EXP="$(expected_mib_for_profile "${PROF}")" - GPU_BDFS+=("${PCI_FULL}") - GPU_DEVIDS+=("${DEVID}") - GPU_PROFILES+=("${PROF}") - GPU_EXPECTED+=("${EXP}") - GPU_CURRENT+=("${CUR_MEM}") + GPU_COUNT=$((GPU_COUNT + 1)) if [[ "${PROF}" == "8gb" ]]; then COUNT_8GB=$((COUNT_8GB + 1)) @@ -171,59 +156,8 @@ for PCI_LINE in "${PCI_LINES[@]}"; do fi done -[[ ${#GPU_BDFS[@]} -gt 0 ]] || die "No unlockable CMP 170HX GPUs found (need 10de:20c2 and/or 10de:2082)" -if (( COUNT_UNSUPPORTED > 0 )); then - info "Inventory: ${#GPU_BDFS[@]} unlockable (${COUNT_8GB}× 8gb, ${COUNT_10GB}× 10gb), ${COUNT_UNSUPPORTED} unsupported" -else - info "Inventory: ${#GPU_BDFS[@]} unlockable (${COUNT_8GB}× 8gb, ${COUNT_10GB}× 10gb)" -fi - -step "Step 3/6: Selecting card memory profile" -CARD_PROFILE="" -if (( COUNT_8GB > 0 && COUNT_10GB > 0 )); then - CARD_PROFILE="mixed" - ok "Mixed variants detected → profile mixed (runtime geometry by PCI ID)" - if [[ -n "${PROFILE_OVERRIDE}" ]]; then - warn "--profile=${PROFILE_OVERRIDE} ignored for mixed inventory; card_profile stays mixed (each card unlocks by PCI ID)" - fi -elif (( COUNT_8GB > 0 )); then - CARD_PROFILE="8gb" -elif (( COUNT_10GB > 0 )); then - CARD_PROFILE="10gb" -else - die "Internal error: no unlockable profiles counted" -fi - -if [[ -n "${PROFILE_OVERRIDE}" && "${CARD_PROFILE}" != "mixed" ]]; then - if [[ "${PROFILE_OVERRIDE}" != "${CARD_PROFILE}" ]]; then - warn "Inventory is ${CARD_PROFILE} but --profile=${PROFILE_OVERRIDE} was forced (metadata only; geometry follows PCI ID)" - else - ok "Profile forced via --profile=${CARD_PROFILE}" - fi - CARD_PROFILE="${PROFILE_OVERRIDE}" -fi - -case "${CARD_PROFILE}" in - 8gb) - info "Unlock geometry: 64GB per card (CFG1=0x02779000 LMR=0x0000020B)" - ;; - 10gb) - info "Unlock geometry: 40GB per card (CFG1=0x02669000 LMR=0x0000028A)" - ;; - mixed) - info "Unlock geometry: 64GB for 20c2 / 40GB for 2082" - ;; - *) - die "Internal error: bad profile ${CARD_PROFILE}" - ;; -esac - -GPU_INVENTORY_LINES=() -for i in "${!GPU_BDFS[@]}"; do - GPU_INVENTORY_LINES+=("${GPU_BDFS[$i]} ${GPU_DEVIDS[$i]} ${GPU_PROFILES[$i]} ${GPU_EXPECTED[$i]}") -done -export CMPUNLOCKER_CARD_PROFILE="${CARD_PROFILE}" -export CMPUNLOCKER_GPU_INVENTORY="$(printf '%s\n' "${GPU_INVENTORY_LINES[@]}")" +[[ "${GPU_COUNT}" -gt 0 ]] || die "No unlockable CMP 170HX GPUs found (need 10de:20c2 and/or 10de:2082)" +info "Found ${GPU_COUNT} unlockable GPU(s): ${COUNT_8GB}x 8gb, ${COUNT_10GB}x 10gb" if [[ -n "${MCLK_NDIV}" ]]; then if ! [[ "${MCLK_NDIV}" =~ ^[0-9]+$ ]] || [[ "${MCLK_NDIV}" -lt 30 || "${MCLK_NDIV}" -gt 80 ]]; then @@ -244,7 +178,7 @@ else fi export CMPUNLOCKER_MCLK_NDIV="${MCLK_NDIV}" -step "Step 4/6: Verifying nvidia-open (${SUPPORTED_VERSIONS_CSV})" +step "Verifying nvidia-open (${SUPPORTED_VERSIONS_CSV})" [[ ${#SUPPORTED_VERSIONS[@]} -gt 0 ]] || die "No supported versions listed in driver/VERSION" if [[ -d /sys/firmware/efi ]] && command -v mokutil &>/dev/null; then if mokutil --sb-state 2>/dev/null | grep -qi 'SecureBoot enabled'; then @@ -288,16 +222,14 @@ ok "NVIDIA driver ${detected} is supported" [[ -d "/lib/modules/$(uname -r)/build" ]] || die "Kernel headers missing for $(uname -r). Install linux-headers-$(uname -r) or kernel-devel." ok "Kernel headers present for $(uname -r)" -step "Step 5/6: Building and installing patched modules" +step "Building and installing patched modules" chmod +x "${SCRIPT_DIR}/driver/build.sh" CMPUNLOCKER_DRIVER_VERSION="${detected}" \ -CMPUNLOCKER_CARD_PROFILE="${CARD_PROFILE}" \ -CMPUNLOCKER_GPU_INVENTORY="${CMPUNLOCKER_GPU_INVENTORY}" \ CMPUNLOCKER_MCLK_NDIV="${MCLK_NDIV}" \ "${SCRIPT_DIR}/driver/build.sh" -ok "Patched modules installed (profile ${CARD_PROFILE})" +ok "Patched modules installed" -step "Step 5b/6: Configuring IOMMU (passthrough)" +step "Configuring IOMMU (passthrough)" IOMMU_STATUS="skipped" IOMMU_PARAMS="" @@ -463,38 +395,23 @@ else fi fi -step "Step 6/6: Done" echo "" echo -e "${CYAN}╔════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ cmpunlocker ║${NC}" echo -e "${CYAN}╚════════════════════════════════════════╝${NC}" echo "" -echo "cmpunlocker install finished!" -echo "Profile: ${CARD_PROFILE} | ${#GPU_BDFS[@]} GPU(s): ${COUNT_8GB}× 8gb, ${COUNT_10GB}× 10gb" -if [[ -n "${IOMMU_PARAMS}" && "${IOMMU_STATUS}" != "skipped" ]]; then - echo "IOMMU: ${IOMMU_PARAMS} (${IOMMU_STATUS})" -else - echo "IOMMU: not configured" -fi +echo "Installed for ${GPU_COUNT} GPU(s): ${COUNT_8GB}x 8gb, ${COUNT_10GB}x 10gb" if [[ -n "${MCLK_NDIV}" ]]; then - echo "MCLK: NDIV=${MCLK_NDIV} → $((MCLK_NDIV * 27)) MHz" -else - echo "MCLK: stock (overclock patches not compiled in)" + echo "MCLK: NDIV=${MCLK_NDIV} ($((MCLK_NDIV * 27)) MHz)" fi echo "" -echo "Per-GPU expectations after unlock:" -printf " %-16s %-8s %-8s %s\n" "BDF" "PCI ID" "Variant" "Expect MiB" -for i in "${!GPU_BDFS[@]}"; do - printf " %-16s %-8s %-8s ~%s\n" "${GPU_BDFS[$i]}" "${GPU_DEVIDS[$i]}" "${GPU_PROFILES[$i]}" "${GPU_EXPECTED[$i]}" -done -echo "" echo "Next:" echo -e " 1. Cold reboot: ${CYAN}sudo shutdown -h now${NC} (then power on)" echo -e " 2. Benchmark: ${CYAN}./benchmark/nvidia_bench${NC}" echo -e " 3. Unlock logs: ${CYAN}sudo dmesg | grep CMPUNLOCK${NC}" if [[ -n "${IOMMU_PARAMS}" && "${IOMMU_STATUS}" != "skipped" ]]; then - echo -e " 4. Verify IOMMU after reboot: ${CYAN}cat /proc/cmdline${NC}" + echo -e " 4. Verify IOMMU: ${CYAN}cat /proc/cmdline${NC}" fi echo "" -echo "Log saved to: ${LOG_FILE}" +echo "Log: ${LOG_FILE}" echo "" -- 2.51.2 From 021cb6be84d5096949e183805e67d0ce3c4c8e59 Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 18:26:34 +0200 Subject: [PATCH 6/9] add p2p gpu connections --- README.md | 26 ++++++++++++++++++++----- docs/ARCHITECTURE.md | 16 ++++++++++++++- driver/patches/0007-p2p-caps-hook.patch | 19 ++++++++++++++++++ driver/src/cmpunlock.c | 12 ++++++++++++ driver/src/cmpunlock.h | 9 +++++++++ 5 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 driver/patches/0007-p2p-caps-hook.patch diff --git a/README.md b/README.md index e2d679f..6460942 100644 --- a/README.md +++ b/README.md @@ -70,21 +70,36 @@ Or add `iommu=pt` to your kernel cmdline manually. IOMMU must also be enabled in --- -## Verify & Benchmark +## Verify -After install and cold reboot, run the built-in GPU benchmark: +After install and cold reboot: ```bash -./benchmark/nvidia_bench +# Memory and SMs — 8GB card should show 65536 MiB, 10GB card 40960 MiB +nvidia-smi --query-gpu=index,memory.total,pci.bus_id --format=csv + +# Unlock logs +sudo dmesg | grep CMPUNLOCK + +# P2P support (multi-GPU) — should show PIX/PHB/SYS/OK, not GNS +nvidia-smi topo -m +nvidia-smi topo -p2p r + +# PCIe link speed, performance, memory amount, memory speed, SM count... +./benchmark/nvidia_bench [--cuda_gpu_id] + ``` -This measures memory bandwidth, tensor core throughput, PCIe speed, SM clock, and reports hardware features. An unlocked 8GB card should show ~64 GiB total memory and 56/70 SMs; a 10GB card should show ~40 GiB and 54/70 SMs. +### Benchmark ```bash -./benchmark/nvidia_bench 0 # test GPU 0 (default) +./benchmark/nvidia_bench # test GPU 0 +./benchmark/nvidia_bench 0 # explicit GPU index ./benchmark/nvidia_bench --csv # machine-readable output ``` +Measures memory bandwidth, tensor core throughput (TF32/BF16/INT8), PCIe H2D/D2H speed, SM clock, and reports hardware features (NVENC/NVDEC). + A pre-built x86-64 binary is included. On aarch64 (or to rebuild), install the CUDA toolkit and build from source: ```bash @@ -99,6 +114,7 @@ cd benchmark && nvcc -O3 -o nvidia_bench nvidia_bench.cu -lnvidia-ml -ldl \ | Full SM compute throughput (SS0/SS1) | Working | | Memory geometry (64GB on 8GB cards, 40GB on 10GB cards) | Working | | PCIe Gen 2 speeds | Working | +| GPU-to-GPU P2P (cudaDeviceEnablePeerAccess) | Working | | HBM2 memory overclock/downclock | Working | | Persistence across reboot (patched modules) | Working | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index f739151..23ed692 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -48,6 +48,7 @@ driver/ 0004-memmgr-quirks.patch mem_mgr*, mem_scrub 3 conditionals 0005-bar0-pramin-clamp.patch kern_bus_gm107.c 1 conditional 0006-persistent-sw-state.patch nv.c 1 conditional + 0007-p2p-caps-hook.patch gpu.c 1 hook ``` `build.sh` copies `driver/src/*` into `src/nvidia/{src,inc}/kernel/gpu/cmpunlock/`, appends one `SRCS +=` line to `src/nvidia/srcs.mk`, then applies the patches. @@ -141,7 +142,20 @@ The unlock is applied by **patched kernel modules**, not a userspace daemon: - Every time the driver initializes (on boot or after a reload), the patched sequence runs - The unlock persists indefinitely until `./remove.sh` is run -Card profile (8GB vs 10GB) is stored in `/lib/modules/$(uname -r)/updates/cmpunlocker/card_profile` at install time and used during every boot. +Card profile (8GB vs 10GB) is determined at runtime from PCI device ID. + +--- + +### GPU-to-GPU P2P + +GSP firmware reports `pcieP2PReadCaps` / `pcieP2PWriteCaps` = NOT_SUPPORTED for CMP device IDs. This blocks `cudaDeviceEnablePeerAccess()` even though the GA100 PCIe mailbox P2P hardware works. + +`cmpUnlockForceP2PCaps()` overrides the GSP response to OK after the RPC returns in `_gpuInitPcieP2PCapability()`. The driver then uses `P2P_CONNECTIVITY_PCIE_PROPRIETARY` (mailbox protocol through BAR0/PRAMIN) which does not require large BAR1. + +Expected dmesg output: +``` +CMPUNLOCK: PCIe P2P caps forced to OK +``` --- diff --git a/driver/patches/0007-p2p-caps-hook.patch b/driver/patches/0007-p2p-caps-hook.patch new file mode 100644 index 0000000..5fedacb --- /dev/null +++ b/driver/patches/0007-p2p-caps-hook.patch @@ -0,0 +1,19 @@ +diff --git a/src/nvidia/src/kernel/gpu/gpu.c b/src/nvidia/src/kernel/gpu/gpu.c +--- a/src/nvidia/src/kernel/gpu/gpu.c ++++ b/src/nvidia/src/kernel/gpu/gpu.c +@@ -77,6 +77,7 @@ + #include "platform/chipset/chipset.h" + #include "kernel/gpu/host_eng/host_eng.h" + #include "gpu/bif/kernel_bif.h" ++#include "gpu/cmpunlock/cmpunlock.h" + #include "gpu/ce/kernel_ce.h" + #include "kernel/gpu/mem_mgr/mem_mgr.h" + #include "kernel/gpu/mig_mgr/kernel_mig_manager.h" +@@ -2517,6 +2518,7 @@ + + pGpu->pcieP2PReadCaps = p2pCapsParams.p2pReadCapsStatus; + pGpu->pcieP2PWriteCaps = p2pCapsParams.p2pWriteCapsStatus; ++ cmpUnlockForceP2PCaps(pGpu); + } + + static void diff --git a/driver/src/cmpunlock.c b/driver/src/cmpunlock.c index 1e98574..00aa093 100644 --- a/driver/src/cmpunlock.c +++ b/driver/src/cmpunlock.c @@ -159,6 +159,18 @@ cmpUnlockIsTarget(OBJGPU *pGpu) return (devId == CMPUNLOCK_DEVID_8GB || devId == CMPUNLOCK_DEVID_10GB); } +void +cmpUnlockForceP2PCaps(OBJGPU *pGpu) +{ + if (!cmpUnlockIsTarget(pGpu)) + return; + + pGpu->pcieP2PReadCaps = 0; + pGpu->pcieP2PWriteCaps = 0; + + NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: PCIe P2P caps forced to OK\n"); +} + static NvU64 _cmpUnlockedFbBytes(OBJGPU *pGpu) { diff --git a/driver/src/cmpunlock.h b/driver/src/cmpunlock.h index 6cd7022..f59f773 100644 --- a/driver/src/cmpunlock.h +++ b/driver/src/cmpunlock.h @@ -93,4 +93,13 @@ void cmpUnlockMclkPostGsp(OBJGPU *pGpu, KernelGsp *pKernelGsp); */ NV_STATUS cmpUnlockLateExtendPma(OBJGPU *pGpu); +/* + * Force PCIe P2P caps to OK. GSP firmware reports NOT_SUPPORTED for CMP + * cards, but the GA100 mailbox P2P hardware works fine. This overrides the + * GSP response so cudaDeviceEnablePeerAccess() succeeds. + * + * Hook: _gpuInitPcieP2PCapability() in gpu.c, after the GSP RPC. + */ +void cmpUnlockForceP2PCaps(OBJGPU *pGpu); + #endif /* CMPUNLOCK_H */ -- 2.51.2 From 3d7005942f0dd4aaf94e327352f535907e4e68dc Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 18:58:12 +0200 Subject: [PATCH 7/9] update docs --- docs/ARCHITECTURE.md | 168 +++++++++++++++++++++---------------------- docs/DEBUGGING.md | 6 +- 2 files changed, 84 insertions(+), 90 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 23ed692..8a613c7 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -2,38 +2,35 @@ ## Overview -cmpunlocker restores full compute and memory capabilities to the NVIDIA CMP 170HX by patching the nvidia-open kernel modules. The unlock runs automatically during driver initialization and persists across reboots. +The CMP 170HX is a full GA100 die — the same silicon as the A100 — with SM throttle, memory and PCIe link speed clamped in firmware. The clamps are enforced by PLM (Priv Level Mask) gates: registers that reject writes coming from the host, no matter how privileged the driver is. -The CMP 170HX is physically a complete GA100 die (same silicon as the A100) but with compute and memory artificially restricted via firmware and OTP configuration. cmpunlocker bypasses these restrictions at the driver level without requiring hardware modifications. +cmpunlocker lifts those clamps during driver initialisation, before GSP boots. Nothing is flashed and no hardware is modified; the unlock is re-applied from scratch on every driver load. ---- - -## The Problem +| | Stock | Unlocked | +|---|---|---| +| Memory (`0x20C2`) | 8 GB | 64 GB | +| Memory (`0x2082`) | 10 GB | 40 GB | +| SM speed select | clamped | full | +| PCIe | Gen1 | Gen2 | +| GPU-to-GPU P2P | blocked | working | -The CMP 170HX ships with: +--- -- **Disabled SMs (Streaming Multiprocessors)**: SS0 and SS1 (Suspension State registers) artificially disable clusters of SMs -- **Restricted memory geometry**: The HBM2e controller is configured for 8GB or 10GB instead of the full 64GB or 40GB the die supports -- **Firmware locks**: OTP (One-Time Programmable) fuses prevent reconfiguration at runtime +## The SEC2 Booter Trick -All three are enforced during GSP (GPU System Processor) boot, which happens when the driver loads. +The host cannot write a PLM-gated register, but the SEC2 Booter can — it runs signed and is trusted by the PLM logic. ---- +During GSP bootstrap the driver allocates a *signature* buffer and hands its physical address to the Booter. cmpunlocker enlarges that buffer to `0xf800` bytes and fills it with a crafted Booter payload instead of the real signature. The payload makes SEC2 perform exactly one 32-bit register write, with the address and value taken from two slots inside it (`0xf76c` and `0xf754`). -## The Unlock Approach +One Booter Load = one gated write. Rewriting those two slots and running Booter Load again gives the next write, so the gates are opened one at a time in a loop. When the loop is done the real signature is put back and GSP boots on an already-unlocked GPU, seeing nothing unusual. -Instead of modifying OTP (which is physically locked), cmpunlocker intercepts the driver's boot flow and reconfigures the GPU before OTP locks take effect: - -1. **Open the SEC2 Booter PMM** — disable security restrictions on the Booter so it can execute custom PLM sequences -2. **Configure memory geometry** — write CFG1 (config) and LMR (LM Request) registers to unlock full HBM2e capacity -3. **Enable all SMs** — write SS0 and SS1 (Suspension State) to re-enable disabled SM clusters -4. **Finalize** — perform late PMA (Power Management Array) adjustments and allow normal boot to continue +The payload is loaded from `/lib/firmware/nvidia/ga100/gsp/dmem.bin` when present, otherwise it is generated in place — both produce the same image. --- ## Code Layout -The unlock is a single source file that is dropped into the stock driver tree, plus a handful of one-line hooks that call into it: +All logic lives in one source file that is dropped into the stock tree. The patches only add the calls that reach it, which is why they are a few lines each. ``` driver/ @@ -53,116 +50,113 @@ driver/ `build.sh` copies `driver/src/*` into `src/nvidia/{src,inc}/kernel/gpu/cmpunlock/`, appends one `SRCS +=` line to `src/nvidia/srcs.mk`, then applies the patches. -Keeping the logic out of the patches means editing the unlock is ordinary C editing, and moving to a new nvidia-open release only requires re-checking the hook insertion points rather than re-merging large diffs. Every hook is a no-op on non-CMP GPUs, so the patched modules stay safe on mixed systems. +Every hook starts with `cmpUnlockIsTarget()`, which matches PCI device ID `0x20C2` or `0x2082`. On any other GPU each hook is a no-op, so the patched modules are safe on mixed systems. Keeping the logic outside the patches means moving to a new nvidia-open release only requires re-checking the insertion points instead of re-merging large diffs. --- -## Technical Components +## Boot Sequence -### SEC2 Booter & PLM +| Where | Hook | What it does | +|---|---|---| +| `_kgspCreateSignatureMemdesc()` | `cmpUnlockSignatureSize`
`cmpUnlockFillSignature` | Enlarge the signature buffer, stash the real signature aside, write the Booter payload in its place | +| `_kgspBootGspRm()`, after `kgspPrepareForBootstrap_HAL()` | `cmpUnlockPreBoot` | The unlock itself (below) | +| `kgspBootstrap_TU102()`, after Booter Load | `cmpUnlockPostBooterLoad` | Verify the gated registers survived; first half of the HBM overclock | +| `kgspInitRm_IMPL()`, after static config fetch | `cmpUnlockFixStaticInfo` | Widen the FB geometry GSP reported back to the unlocked size | +| `kgspInitRm_IMPL()`, after `kgspStartLogPolling()` | `cmpUnlockMclkPostGsp` | Second half of the HBM overclock | +| `_gpuInitPcieP2PCapability()` | `cmpUnlockForceP2PCaps` | Override the GSP P2P capability response | +| `RmInitNvDevice()` | `cmpUnlockLateExtendPma` | Hand the memory above the stock limit to PMA | -The SEC2 Booter executes firmware sequences (PLMs: "Program Logic Modules") during GPU power-on and reset. Normally, PLMs are locked to a restricted set via security fuses. +`cmpUnlockPreBoot()` runs in the window after the bootstrap is prepared and before GSP is released: -cmpunlocker: -- Patches the driver to open the PMM (Permute Mask Model) during boot -- Sets PLM permissions to `0xffffffff` (all PLMs enabled) -- Injects custom PLM sequences that reconfigure GPU state +1. Save the WPR2 window (`0x1fa824` / `0x1fa828`) — Booter Load clobbers it and it is restored before every round trip. +2. Walk the PLM table: 17 entries, each one Booter Load that opens a gate, retried once if the register does not read back as expected. +3. With the gates open, write the SM speed select and memory geometry registers. +4. Retrain the PCIe link at Gen2. +5. Restore the stock signature, then call `kgspPopulateWprMeta_HAL()` — the framebuffer size changed underneath, so the WPR layout has to be recomputed. -Expected dmesg output: -``` -CMPUNLOCK: PLM[0] WPR_CFG(0x1fa7cc) attempt=0 status=0x0 reg=0xfffff0ff -CMPUNLOCK: PLMs: FEAT=0xffffffff FBPA=0xffffffff WPR=0xffffffff WPR_CFG=0xfffff0ff -``` - -Booter status codes like `0x31` or `0xffff` during early PLM passes are often harmless if the final boot succeeds. +Patch `0001` also stops the stock "WPR2 already up, cannot proceed" bail-out from firing on a CMP, because cmpunlocker recovers from that state instead of treating it as fatal. --- -### Memory Geometry (CFG1 & LMR) +## Register Map -The GPU memory controller is configured by two registers: +Written once the gates are open: -| Card | CFG1 | LMR | Unlocked Capacity | -|---|---|---|---| -| 8GB | `0x02779000` | `0x0000020B` | 64GB | -| 10GB | `0x02669000` | `0x0000028A` | 40GB | +| Register | Address | Value | +|---|---|---| +| SM speed select 0 | `0x0082381c` | `0x88888888` | +| SM speed select 1 | `0x00823820` | `0x00000008` | +| FBPA CFG1 | `0x009a0204` | `0x02779000` (8GB) / `0x02669000` (10GB) | +| MMU LMR | `0x00100ce0` | `0x0000020B` (8GB) / `0x0000028A` (10GB) | + +CFG1 sets the memory address mapping and bank layout; LMR selects the capacity. 8GB vs 10GB is decided at runtime from the device ID, so one build covers both variants and mixed systems. + +--- -- **CFG1**: Memory configuration register (address mapping, bank layout) -- **LMR**: LM (Local Memory) Request register (capacity/geometry selector) +## PCIe Gen2 -cmpunlocker writes both during the unlock sequence. 8GB vs 10GB is decided at runtime from the PCI device ID (`0x20C2` / `0x2082`), so one build works on either card and on mixed systems. +The XP registers that control link speed are PLM-gated, so they are only writable inside the unlock window. The retrain clears the CYA bits pinning the link to Gen1, selects Gen2 in `XP_CFG0` and `XP_LCTRL2`, sets the *root port's* target speed via its LnkCtl2 config word (the link will not come up at Gen2 unless both ends agree), then triggers a directed speed change and polls the LTSSM until it settles. --- -### Compute State (SS0 & SS1) +## GPU-to-GPU P2P -SS0 and SS1 are Suspension State registers that control which SM clusters are active: +GSP firmware reports `pcieP2PReadCaps` / `pcieP2PWriteCaps` as `NOT_SUPPORTED` for CMP device IDs. The driver stores that verdict and `p2pGetCapsStatus()` then refuses every PCIe P2P path, so `cudaDeviceEnablePeerAccess()` fails and `nvidia-smi topo -m` shows `GNS`. -- Stock firmware sets these to disable ~50% of the SMs -- cmpunlocker writes `0xffffffff` to both, enabling all clusters -- The GPU can then use full compute throughput +The restriction is purely in that reported capability — the GA100 mailbox P2P hardware works. `cmpUnlockForceP2PCaps()` overwrites both fields with `OK` right after the RPC returns, and the driver falls into `P2P_CONNECTIVITY_PCIE_PROPRIETARY`: the mailbox protocol, which does not need a large BAR1 (the CMP's is 64 MiB and locked by VBIOS). -Expected dmesg output: -``` -CMPUNLOCK: POST-WRITE SS0=0x88888888 SS1=0x00000008 CFG1=0x02779000 LMR=0x0000020b (devId=0x20c2) -``` +Throughput follows the PCIe topology — roughly 1.7 GB/s between GPUs behind one switch at Gen2 x4, less across a host bridge or NUMA node. --- -### FB & PMA Adjustments +## HBM Memory Clock + +Compiled out entirely unless `--mclk-ndiv=N` is passed; `build.sh` then generates `cmpunlock_config.h` with `CMPUNLOCK_MCLK_NDIV`. The clock is `N * 27` MHz. -After core reconfiguration, the frame buffer (FB) and power management array (PMA) are adjusted to support the new memory geometry and active SMs: +The sequence is VBIOS-agnostic: the stock NDIV is read out of the PLL rather than assumed, and every COEFF write is a read-modify-write that preserves the MDIV/PDIV the VBIOS programmed. It runs in two halves: -- FB is resized to reflect the new memory capacity -- PMA is reconfigured for the enabled SM clusters -- These changes are performed in "late PMA" phase, near the end of boot +- **After Booter Load** — assert MEMCLK_CHANGE_ALERT, enter HBM self-refresh, cycle the PLL on each of the 12 FBPAs (drop the enable bits, write the new NDIV, re-enable, poll for lock), exit self-refresh, run a DDLL calibration, clear the alert. +- **After GSP is up** — one multicast COEFF write across all FBPAs, followed by a PRI fence and a lock poll. --- -## Boot Flow +## Supporting Changes -1. **Driver loads** → nvidia-open kernel modules initialize -2. **GSP power-on** → SEC2 Booter executes (normally-locked path) -3. **cmpunlocker intercepts** → PMM is opened, custom PLM sequences run - - PLMs set to unrestricted mode - - CFG1/LMR written (memory geometry) - - SS0/SS1 written (compute state) - - Late PMA adjustments applied -4. **GSP boot completes** → GPU is now fully unlocked -5. **Driver ready** → `nvidia-smi` shows 65536 MiB (8GB) or 40960 MiB (10GB) +Not part of the unlock proper, but required for the unlocked geometry to be stable: ---- +- **Memory manager quirks** (`0004`) — CE virtual mode is disabled for the scrubber and CeUtils, and the PTE kind is forced to `GENERIC_MEMORY` instead of the PLC-disable variant. Compression is unreliable on the widened geometry. +- **BAR0 PRAMIN clamp** (`0005`) — the BAR0 window only decodes the stock 8 GB, so PRAMIN is pinned where it would have landed before the unlock widened `fbAddrSpaceSizeMb`. +- **Persistent software state** (`0006`) — `NV_FLAG_PERSISTENT_SW_STATE` is set for CMP device IDs. The unlock happens once during GSP bootstrap, so the software state has to survive teardown rather than being rebuilt. +- **Late PMA extension** (`0003`) — GSP hands back a heap sized for the stock capacity. The memory above it is present but parked in a reserved FB region; once the heap and PMA are fully initialised, that region is carved out and registered with PMA. -## Persistence Across Reboot +--- -The unlock is applied by **patched kernel modules**, not a userspace daemon: +## Persistence -- Modified `nvidia-drm.ko` and `nvidia.ko` are installed to `/lib/modules/$(uname -r)/updates/cmpunlocker/` -- These modules load before the stock NVIDIA modules (due to the `updates/` directory priority) -- Every time the driver initializes (on boot or after a reload), the patched sequence runs -- The unlock persists indefinitely until `./remove.sh` is run +The unlock is applied by patched kernel modules, not a userspace daemon. `build.sh` installs `nvidia.ko`, `nvidia-modeset.ko`, `nvidia-uvm.ko`, `nvidia-drm.ko` and `nvidia-peermem.ko` into `/lib/modules/$(uname -r)/updates/cmpunlocker/`, which `depmod` prefers over the stock paths, then rebuilds the initramfs. -Card profile (8GB vs 10GB) is determined at runtime from PCI device ID. +Every driver initialisation re-runs the sequence, so the unlock survives reboots until `./remove.sh` is run. Nothing is stored on the card. --- -### GPU-to-GPU P2P - -GSP firmware reports `pcieP2PReadCaps` / `pcieP2PWriteCaps` = NOT_SUPPORTED for CMP device IDs. This blocks `cudaDeviceEnablePeerAccess()` even though the GA100 PCIe mailbox P2P hardware works. +## Verifying -`cmpUnlockForceP2PCaps()` overrides the GSP response to OK after the RPC returns in `_gpuInitPcieP2PCapability()`. The driver then uses `P2P_CONNECTIVITY_PCIE_PROPRIETARY` (mailbox protocol through BAR0/PRAMIN) which does not require large BAR1. - -Expected dmesg output: ``` +CMPUNLOCK: PLM[0] WPR_CFG(0x1fa7cc) attempt=0 status=0x0 reg=0xfffff0ff +CMPUNLOCK: PLMs: FEAT=0xffffffff FBPA=0xffffffff WPR=0xffffffff WPR_CFG=0xfffff0ff +CMPUNLOCK: POST-WRITE SS0=0x88888888 SS1=0x00000008 CFG1=0x02779000 LMR=0x0000020b (devId=0x20c2) +CMPUNLOCK: PCIe retrain done (polls=1): LinkCtrlStat=0x... speed=2 width=x16 CMPUNLOCK: PCIe P2P caps forced to OK ``` ---- +Non-zero Booter status codes during the early PLM rounds are common and harmless as long as the register reads back correctly and the boot completes — the table retries each gate anyway. -## Known Limitations +--- -- **Secure Boot must be disabled** — patched modules are unsigned -- **Requires nvidia-open 610.43.0x** — stock NVIDIA proprietary driver has different boot paths and cannot be patched the same way -- **Linux only** — GSP boot path is Linux-specific (Windows WDDM driver is fundamentally different) -- **Kernel headers required** — modules must be compiled for the running kernel version +## Limitations +- **Secure Boot must be disabled** — the patched modules are unsigned. +- **nvidia-open 610.43.0x only** — the proprietary driver has a different GSP boot path and cannot be patched this way. +- **Linux only** — the unlock lives in the Linux GSP bootstrap path. +- **Kernel headers required** — modules are compiled against the running kernel. +- ?**BAR1 stays at 64 MiB** — locked by VBIOS, so P2P goes through the mailbox protocol rather than direct BAR1 mapping.? diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index 513096d..b47cdd3 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -29,9 +29,9 @@ If memory is still stock after a cold reboot, open a Discord ticket (see below). ## Running the benchmark ```bash -./benchmark/nvidia_bench # default: GPU 0, auto-sized iterations -./benchmark/nvidia_bench 1 # test GPU 1 -./benchmark/nvidia_bench 0 50 # GPU 0, 50 iterations per test +./benchmark/nvidia_bench # default: GPU #0, auto-sized iterations +./benchmark/nvidia_bench 1 # test GPU #1 +./benchmark/nvidia_bench 0 50 # GPU #0, 50 iterations per test ./benchmark/nvidia_bench --csv # machine-readable output ``` -- 2.51.2 From 0c443898ee47205f3e744eae0431319e35b11b82 Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 19:10:23 +0200 Subject: [PATCH 8/9] update docs --- docs/CONTRIBUTING.md | 109 ++++++++++++++++++++++++++++++++++--------- docs/DEBUGGING.md | 5 +- 2 files changed, 88 insertions(+), 26 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 1285884..2baf6b7 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,37 +1,102 @@ # Contributing -Thanks for your interest in contributing to cmpunlocker! This guide covers submitting changes. +Thanks for your interest in cmpunlocker. Read [ARCHITECTURE.md](ARCHITECTURE.md) first — it explains how the unlock works and where each piece lives. --- -## Submitting Changes +## Where To Make Changes -1. **Fork the repo** on GitHub +Almost everything belongs in **`driver/src/cmpunlock.c`**. The patches in `driver/patches/` only contain the hook calls that reach it, and they should stay that way — logic in a patch is much harder to carry to the next nvidia-open release. -2. **Create a branch** for your changes: - ```bash - git checkout -b feature/my-improvement - ``` +| You want to | Edit | +|---|---| +| Change unlock behaviour | `driver/src/cmpunlock.c` | +| Add a new hook | `cmpunlock.h` (declaration) + `cmpunlock.c` (body) + a new patch with the call | +| Change build options | `driver/build.sh` | +| Change install/removal flow | `install.sh` / `remove.sh` | +| Support a new driver version | `driver/VERSION` (newest first), then re-verify every patch applies | -3. **Make changes** and test thoroughly on real hardware +Every entry point must start with `cmpUnlockIsTarget(pGpu)` and return early on non-CMP GPUs. The patched modules are expected to run unchanged on mixed systems. -4. **Commit with clear messages**: - ```bash - git commit -m "Add improvement to 8GB card support" - ``` +--- -5. **Push and open a PR**: - ```bash - git push origin my-feature - ``` +## Build & Test Loop + +```bash +sudo ./install.sh # re-extracts stock sources, applies patches, builds, installs +sudo shutdown -h now # cold reboot — see below +``` -6. **Describe your changes** in the PR body (following the PR template) +After power-on: + +```bash +sudo dmesg | grep CMPUNLOCK # unlock trace +nvidia-smi # geometry +./benchmark/nvidia_bench # memory bandwidth, SMs, PCIe speed, tensor cores +``` + +`driver/.build/` is regenerated on every run and is gitignored, so there is nothing to clean between iterations — just re-run `install.sh`. + +**A cold reboot means a full power off, not `reboot`.** Some of the unlocked state survives a warm reset, which makes results misleading: a change can look like it works because the previous boot already put the card in that state. When in doubt, `./remove.sh --yes`, power cycle, and start from stock. + +--- + +## Patches + +- Unified diff, `-p1`, applied in filename order by `build.sh`. +- Must apply **without fuzz**. Verify against an extracted tree before submitting: + ```bash + cd driver/.build/open-gpu-kernel-modules- + patch -p1 --dry-run --verbose < ../../patches/00XX-your.patch + ``` + Any `Hunk #N succeeded ... with fuzz` means the context is wrong — fix the context lines, do not rely on `patch` guessing. +- Keep them minimal: an `#include` and a call. If a hunk is growing, move the body into `cmpunlock.c`. +- Name them `NNNN-short-description.patch`, continuing the existing numbering. --- -## Code Style & Conventions +## Code Style + +`cmpunlock.c` follows the surrounding nvidia-open RM code: + +- RM types (`NvU32`, `NvU64`, `NvBool`, `NV_STATUS`), not kernel types. +- `GPU_REG_RD32` / `GPU_REG_WR32` for register access, `NV_PRINTF(LEVEL_ERROR, "CMPUNLOCK: ...")` for logging. +- Public functions prefixed `cmpUnlock`, file-local ones `_cmp`, declared `static`. +- 4-space indent, no tabs, brace on its own line. +- Named `#define`s for register addresses at the top of the file rather than bare constants inline. +- Comment *why*, not *what* — the register writes are not self-explanatory, so say what the sequence is doing and why it has to happen there. + +Shell scripts use `set -euo pipefail`, quoted variables and explicit error handling. + +--- + +## Hardware Changes + +Register writes on a card this locked can hang the GPU or the host, and a bad memory clock can corrupt data silently. If you are adding or changing register sequences: + +- Prefer read-modify-write over blind writes, and read back to confirm the write landed. +- Log enough that a failure is diagnosable from `dmesg` alone. +- Anything risky should be opt-in behind a build flag, the way `--mclk-ndiv` is. + +--- + +## Submitting + +1. Fork and branch: + ```bash + git checkout -b my-change + ``` +2. Make the change and test it on real hardware. +3. Commit with a clear message describing what changed and why. +4. Push and open a PR filling in [the template](../.github/pull_request_template.md) — summary, changes, and **testing with proof**. + +Report the hardware your change actually depends on: + +| PR touches | Report example | +|---|---------------------------------------------------------------------------| +| Docs only | Nothing — leave the hardware section empty | +| `install.sh` / `remove.sh` / `build.sh` | Distro, kernel, driver version | +| `cmpunlock.c` / patches | Card variant (`0x20C2` / `0x2082`), VBIOS, distro, kernel, driver version | +| Memory clock, PCIe, P2P | The above, plus GPU count and host/slot topology | -- **Patch files**: Use unified diff format (`git diff` or `patch -u`). Include context lines. -- **Bash scripts**: Strict mode (`set -euo pipefail`), quote variables, error checking. -- **Comments in patches**: Use standard patch comments (`---` and `+++` headers); C comments go in the patched code. -- **Testing**: Always test on physical hardware before submitting. Describe your test environment (distro, kernel version, card variant). +Anything that changes driver behaviour must be tested on real hardware, with proof (`dmesg`, `nvidia-smi`, benchmark output). diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md index b47cdd3..7938110 100644 --- a/docs/DEBUGGING.md +++ b/docs/DEBUGGING.md @@ -22,11 +22,8 @@ Check that all PLMs show `0xffffffff`: sudo dmesg | grep CMPUNLOCK ``` -If memory is still stock after a cold reboot, open a Discord ticket (see below). ---- - -## Running the benchmark +## Running the benchmark for unlock verification ```bash ./benchmark/nvidia_bench # default: GPU #0, auto-sized iterations -- 2.51.2 From ddb4fc2ef7a867055ea3bccbfea29d1e4d701fce Mon Sep 17 00:00:00 2001 From: aboba Date: Fri, 31 Jul 2026 20:37:50 +0200 Subject: [PATCH 9/9] update README.md --- README.md | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6460942..28d92de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # cmpunlocker -Unlock tool for the NVIDIA CMP 170HX (GA100). Restores full SM compute, unlocked HBM2e memory geometry and PCIe Gen2 that are restricted in firmware/OTP configuration. +Unlock tool for the NVIDIA CMP 170HX (GA100). Restores full SM compute, unlocked HBM2e memory geometry, PCIe Gen2 and GPU-to-GPU P2P — all clamped in firmware on the stock card. **[Join our Discord community](https://discord.gg/CdHSakKSFv)** for support and discussions. @@ -20,7 +20,7 @@ Below are memory and performance results after applying the unlock: - Linux (x86-64 or aarch64) - Root access - NVIDIA CMP 170HX (8GB or 10GB) -- **nvidia-open 610.43.0x already installed** (libs + firmware) +- **nvidia-open 610.43.03 or 610.43.02 already installed** (libs + firmware) - Kernel headers matching the running kernel (`linux-headers-$(uname -r)` / `kernel-devel`) - Secure Boot disabled (patched modules are unsigned) - Network access on first install (downloads matching stock `open-gpu-kernel-modules` sources) @@ -75,31 +75,31 @@ Or add `iommu=pt` to your kernel cmdline manually. IOMMU must also be enabled in After install and cold reboot: ```bash -# Memory and SMs — 8GB card should show 65536 MiB, 10GB card 40960 MiB +# Memory — 8GB card should show 65536 MiB, 10GB card 40960 MiB nvidia-smi --query-gpu=index,memory.total,pci.bus_id --format=csv # Unlock logs sudo dmesg | grep CMPUNLOCK -# P2P support (multi-GPU) — should show PIX/PHB/SYS/OK, not GNS -nvidia-smi topo -m +# P2P read matrix (multi-GPU) — should be OK, not GNS nvidia-smi topo -p2p r -# PCIe link speed, performance, memory amount, memory speed, SM count... -./benchmark/nvidia_bench [--cuda_gpu_id] - +# Link topology (multi-GPU) — PIX / PHB / SYS depending on how the GPUs are wired +nvidia-smi topo -m ``` ### Benchmark +SM count, memory size and bandwidth, PCIe link speed, tensor core throughput (TF32/BF16/INT8), SM clock, and hardware features (NVENC/NVDEC): + ```bash -./benchmark/nvidia_bench # test GPU 0 -./benchmark/nvidia_bench 0 # explicit GPU index -./benchmark/nvidia_bench --csv # machine-readable output +./benchmark/nvidia_bench # GPU 0, auto-sized iterations +./benchmark/nvidia_bench 1 # explicit GPU index +./benchmark/nvidia_bench 0 50 # explicit iteration count +./benchmark/nvidia_bench --csv # one header line + one data line +./benchmark/nvidia_bench --help # all options ``` -Measures memory bandwidth, tensor core throughput (TF32/BF16/INT8), PCIe H2D/D2H speed, SM clock, and reports hardware features (NVENC/NVDEC). - A pre-built x86-64 binary is included. On aarch64 (or to rebuild), install the CUDA toolkit and build from source: ```bash @@ -114,12 +114,21 @@ cd benchmark && nvcc -O3 -o nvidia_bench nvidia_bench.cu -lnvidia-ml -ldl \ | Full SM compute throughput (SS0/SS1) | Working | | Memory geometry (64GB on 8GB cards, 40GB on 10GB cards) | Working | | PCIe Gen 2 speeds | Working | -| GPU-to-GPU P2P (cudaDeviceEnablePeerAccess) | Working | -| HBM2 memory overclock/downclock | Working | +| GPU-to-GPU P2P (`cudaDeviceEnablePeerAccess`) | Working | +| HBM2e memory overclock/downclock | Working | | Persistence across reboot (patched modules) | Working | --- +## Documentation + +- [Installation](docs/INSTALLATION.md) — requirements and install steps +- [Architecture](docs/ARCHITECTURE.md) — how the unlock works +- [Debugging](docs/DEBUGGING.md) — when something does not come up +- [Contributing](docs/CONTRIBUTING.md) — making changes + +--- + ## Uninstall ```bash