Hardware: Add 20GB modding guide, cmp-pstate NVAPI tool, and document private NvAPI_GPU_SetForcePstate and PCIe retrain mechanisms
This commit is contained in:
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Force one NVIDIA GPU into a P-state through the private NVAPI entry point."""
|
||||
|
||||
import argparse
|
||||
import ctypes
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
NVAPI_OK = 0
|
||||
NVAPI_MAX_PHYSICAL_GPUS = 64
|
||||
NVAPI_ENUM_PHYSICAL_GPUS = 0xE5AC921F
|
||||
NVAPI_GPU_GET_BUS_ID = 0x1BE0B8E5
|
||||
NVAPI_GPU_SET_FORCE_PSTATE = 0x025BFB10
|
||||
NVAPI_INITIALIZE = 0x0150E828
|
||||
NVAPI_UNLOAD = 0xD22BDD7E
|
||||
|
||||
|
||||
def status_text(status):
|
||||
return "0x%08x" % (ctypes.c_uint32(status).value,)
|
||||
|
||||
|
||||
def bus_number(bus_id):
|
||||
match = re.search(r"(?:^|:)([0-9a-fA-F]{2}):[0-9a-fA-F]{2}\.[0-7]$",
|
||||
bus_id.strip())
|
||||
if not match:
|
||||
raise ValueError("invalid PCI bus ID: %s" % bus_id)
|
||||
return int(match.group(1), 16)
|
||||
|
||||
|
||||
def query_function(query, function_id, restype, *argtypes):
|
||||
address = query(ctypes.c_uint32(function_id))
|
||||
if not address:
|
||||
raise RuntimeError("NVAPI function 0x%08x is unavailable" % function_id)
|
||||
return ctypes.CFUNCTYPE(restype, *argtypes)(address)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--bus-id", required=True,
|
||||
help="Linux PCI bus ID, for example 00000000:01:00.0")
|
||||
parser.add_argument("--pstate", required=True, type=int,
|
||||
help="P-state number: 0..15, or 16 for automatic/high")
|
||||
args = parser.parse_args()
|
||||
if not 0 <= args.pstate <= 16:
|
||||
parser.error("--pstate must be between 0 and 16")
|
||||
|
||||
try:
|
||||
wanted_bus = bus_number(args.bus_id)
|
||||
api = ctypes.CDLL("libnvidia-api.so.1")
|
||||
query = api.nvapi_QueryInterface
|
||||
query.argtypes = [ctypes.c_uint32]
|
||||
query.restype = ctypes.c_void_p
|
||||
|
||||
initialize = query_function(query, NVAPI_INITIALIZE, ctypes.c_int32)
|
||||
unload = query_function(query, NVAPI_UNLOAD, ctypes.c_int32)
|
||||
enum_gpus = query_function(
|
||||
query, NVAPI_ENUM_PHYSICAL_GPUS, ctypes.c_int32,
|
||||
ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint32))
|
||||
get_bus_id = query_function(
|
||||
query, NVAPI_GPU_GET_BUS_ID, ctypes.c_int32,
|
||||
ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint32))
|
||||
set_force_pstate = query_function(
|
||||
query, NVAPI_GPU_SET_FORCE_PSTATE, ctypes.c_int32,
|
||||
ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32)
|
||||
except (OSError, RuntimeError, ValueError) as exc:
|
||||
print("cmp-pstate: %s" % exc, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
status = initialize()
|
||||
if status != NVAPI_OK:
|
||||
print("cmp-pstate: NvAPI_Initialize failed (%s)" % status_text(status),
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
handles = (ctypes.c_void_p * NVAPI_MAX_PHYSICAL_GPUS)()
|
||||
count = ctypes.c_uint32()
|
||||
status = enum_gpus(handles, ctypes.byref(count))
|
||||
if status != NVAPI_OK:
|
||||
print("cmp-pstate: GPU enumeration failed (%s)" %
|
||||
status_text(status), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
handle = None
|
||||
for index in range(min(count.value, NVAPI_MAX_PHYSICAL_GPUS)):
|
||||
bus = ctypes.c_uint32()
|
||||
status = get_bus_id(handles[index], ctypes.byref(bus))
|
||||
if status == NVAPI_OK and bus.value == wanted_bus:
|
||||
handle = handles[index]
|
||||
break
|
||||
if handle is None:
|
||||
print("cmp-pstate: NVAPI GPU for PCI bus %02x was not found" %
|
||||
wanted_bus, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
status = set_force_pstate(handle, args.pstate, 0)
|
||||
if status != NVAPI_OK:
|
||||
print("cmp-pstate: P%d request failed (%s)" %
|
||||
(args.pstate, status_text(status)), file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
finally:
|
||||
unload()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user