#!/usr/bin/env python3 """Does the DF FabricIndirectConfigAccess port work from the host? READ ONLY. NV22 map: DF.FabricConfigAccessControl SMN 0x1D040 DF.FabricIndirectConfigAccessAddress SMN 0x1D050 DF.FabricIndirectConfigAccessDataLo SMN 0x1D080 DF.FabricIndirectConfigAccessDataHi SMN 0x1D084 This is an index/data port into the Data Fabric's CONFIG space, which is where address-map routing (DramBase/DramLimit style) lives. If it is host-readable we can enumerate how the fabric routes physical addresses -- including, possibly, how the PSP's TMR carve-out is expressed. Nothing here writes a DF config register. The only writes are to the ADDRESS half of the port, which is how a read is performed -- the same pattern the driver uses for SMN itself. Safety: the four registers are checked for decode FIRST. If the port does not decode, nothing else is attempted. """ import struct, time from tinygrad import Device adev = Device["AMD"].iface.dev_impl idx = adev.reg("regBIF_BX0_PCIE_INDEX2") dat = adev.reg("regBIF_BX0_PCIE_DATA2") hb = adev.reg("regMP0_SMN_C2PMSG_81") def alive(): a = hb.read(); time.sleep(0.2); return hb.read() != a def bswap(x): return struct.unpack("I", x & 0xFFFFFFFF))[0] def rd(a): idx.write(a & 0xFFFFFFFF) return dat.read() def wr(a, v): idx.write(a & 0xFFFFFFFF) dat.write(v & 0xFFFFFFFF) def cls(a): v = rd(a) return v, ("MIRROR" if v == bswap(a) else "all-ones" if v == 0xFFFFFFFF else "DECODED") CTL, ADDR, DLO, DHI = 0x1D040, 0x1D050, 0x1D080, 0x1D084 print("control C2PMSG_58 = %#x (expect 0x310036)" % rd(0x581E8)) print("psp alive: %s\n" % alive()) print("%-38s %-12s %s" % ("register", "value", "verdict")) ok = True for a, nm in ((CTL, "DF.FabricConfigAccessControl"), (ADDR, "DF.FabricIndirectConfigAccessAddress"), (DLO, "DF.FabricIndirectConfigAccessDataLo"), (DHI, "DF.FabricIndirectConfigAccessDataHi")): v, k = cls(a) ok &= (k == "DECODED") print(" %-36s %#010x %s" % (nm, v, k)) if not ok: print("\nport does not decode -- stopping, nothing further attempted") raise SystemExit(0) print("\nport decodes. Reading DF config space through it (address-half writes only).") # DF config: instance/function/offset packing varies; sweep a small offset range # on instance 0 and look for non-trivial, non-repeating data. seen = {} for off in range(0, 0x100, 4): wr(ADDR, off) lo = rd(DLO) seen[off] = lo print(" read %d offsets; distinct values: %d" % (len(seen), len(set(seen.values())))) for off in sorted(seen)[:16]: print(" cfg offset %#05x = %#010x" % (off, seen[off])) print("\npsp alive: %s" % alive())