ago

ago / check_gpc.py

Last active 1 month ago

Like 0

Revision 352cd5d3d603ef8f4d85b6de3a3a05c8593db113

check_gpc.py Raw
1#!/usr/bin/env python3
2"""Read-only BAR0 probe for GA100 GPC floorsweep fuses (OPT_GPC_DISABLE / OPT_GPC_DEFECTIVE).
3
4Never writes to BAR0. Requires root to mmap /sys/bus/pci/devices/<bdf>/resource0.
5"""
6import mmap
7import os
8import struct
9import subprocess
10import sys
11
12REG_GPC_DISABLE = 0x00820350
13REG_GPC_DEFECTIVE = 0x008205c4
14PAGE = 0x1000
15
16
17def find_ga100_cards(pattern="GA100"):
18 """Return [(bdf, label)] for PCI devices whose lspci name matches pattern."""
19 try:
20 out = subprocess.check_output(["lspci", "-D"], text=True)
21 except FileNotFoundError:
22 sys.exit("lspci not found; install pciutils or pass BDFs another way")
23 except subprocess.CalledProcessError as e:
24 sys.exit(f"lspci failed: {e}")
25 cards = []
26 for line in out.splitlines():
27 if pattern in line:
28 bdf = line.split(None, 1)[0]
29 cards.append((bdf, bdf.split(":")[1]))
30 return cards
31
32
33def read_reg(bdf, addr):
34 path = f"/sys/bus/pci/devices/{bdf}/resource0"
35 if not os.path.exists(path):
36 raise OSError(f"no BAR0 (resource0 missing, device has no MMIO?)")
37 if os.path.getsize(path) <= addr:
38 raise OSError(f"BAR0 too small for offset 0x{addr:x}")
39 fd = os.open(path, os.O_RDONLY | os.O_SYNC)
40 try:
41 base = addr - (addr % PAGE)
42 off = addr - base
43 m = mmap.mmap(fd, PAGE, mmap.MAP_SHARED, mmap.PROT_READ, offset=base)
44 try:
45 return struct.unpack_from("<I", m, off)[0]
46 finally:
47 m.close()
48 finally:
49 os.close(fd)
50
51
52def bits_set(mask, width=8):
53 return [i for i in range(width) if mask & (1 << i)]
54
55
56def main():
57 if os.geteuid() != 0:
58 sys.exit("must run as root (mmaps BAR0 via /sys/.../resource0)")
59
60 cards = find_ga100_cards()
61 if not cards:
62 sys.exit("no GA100 cards found (lspci name match)")
63 print(f"Detected GA100 card(s): {', '.join(b for b, _ in cards)}\n")
64
65 print(f"{'Card':<6} {'Disabled clusters':<20} {'Marked defective':<18} {'Disabled but not defective'}")
66 for bdf, label in cards:
67 try:
68 disable = read_reg(bdf, REG_GPC_DISABLE)
69 defective = read_reg(bdf, REG_GPC_DEFECTIVE)
70 except OSError as e:
71 print(f"{label:<6} ERROR reading {bdf}: {e}")
72 continue
73
74 disabled_bits = set(bits_set(disable))
75 defective_bits = set(bits_set(defective))
76 not_defective_bits = disabled_bits - defective_bits
77
78 def fmt(bits):
79 return ", ".join(str(b) for b in sorted(bits)) if bits else "none"
80
81 print(f"{label:<6} {fmt(disabled_bits):<20} {fmt(defective_bits):<18} {fmt(not_defective_bits)}")
82 print(f" (raw: OPT_GPC_DISABLE=0x{disable:08x} OPT_GPC_DEFECTIVE=0x{defective:08x})")
83
84
85if __name__ == "__main__":
86 main()
87