ago

ago / check_gpc.py

Last active 1 month ago

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