aboutsummaryrefslogtreecommitdiffstats
path: root/hw/loadta_ring_exhaustion.py
blob: c5090410f8ce93781e68447494c8b5088fd8480c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python3
"""Was the 'wall' an address boundary, or exhaustion caused by the sweep itself?

The sweep's failures began at PA 0x3ef00000, which was ALSO probe #1006. The
failing value was (PA>>16)+0x101 -- but since PA = n*0x100000, that is exactly
16*n + 257. Address-derived and count-derived are indistinguishable in that data.

A fresh process probes 0x3ff00000 and 0x40000000 fine, which already argues
against the address hypothesis. This settles it: probe ONE fixed, known-good
address repeatedly and see whether it degrades at the same count.

LOAD_TA allocates a session on every successful load and this probe never
unloads, so session exhaustion is the obvious candidate.
"""
import sys, time
sys.path.insert(0, "/root/psp/work")
from tinygrad import Device
import tinygrad.runtime.autogen.am.am as am

def main():
    adev = Device["AMD"].iface.dev_impl
    cmd_pa = adev.mm.palloc(0x10000, align=0x1000, zero=True, boot=False)
    mcc = adev.paddr2mc(cmd_pa)
    FIXED = 0x20000000                      # one address, known good, never changes
    def probe(pa):
        mc = adev.paddr2mc(pa)
        c = am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_TA)
        c.cmd.cmd_load_ta.app_phy_addr_lo = mc & 0xFFFFFFFF
        c.cmd.cmd_load_ta.app_phy_addr_hi = mc >> 32
        c.cmd.cmd_load_ta.app_len = 0x1000
        c.cmd.cmd_load_ta.cmd_buf_phy_addr_lo = mcc & 0xFFFFFFFF
        c.cmd.cmd_load_ta.cmd_buf_phy_addr_hi = mcc >> 32
        c.cmd.cmd_load_ta.cmd_buf_len = 0x10000
        t = time.time()
        try: st = adev.psp._ring_submit(c).resp.status
        except Exception as e:
            try: st = int(str(e).strip().split()[-1])
            except Exception: st = -1
        return st, time.time() - t
    print("probing ONE fixed address %#x repeatedly" % FIXED)
    first_bad = None
    for n in range(1, 1400):
        st, dt = probe(FIXED)
        if st != 0x34 or dt > 0.5:
            if first_bad is None:
                first_bad = n
                print("   FIRST DEVIATION at probe #%d: status=%#x (%.2fs)" % (n, st, dt))
                print("   -> 16*n+257 = %#x   (PA>>16)+0x101 = %#x"
                      % (16 * n + 257, (FIXED >> 16) + 0x101))
            if n > (first_bad + 3): break
        if n % 250 == 0: print("   ... probe #%d status=%#x %.3fs" % (n, st, dt))
    if first_bad is None:
        print("   no deviation in 1399 probes at a fixed address")
    print()
    print("=> %s" % ("COUNT-dependent: the 'wall' was exhaustion, not an address boundary"
                     if first_bad else "not count-dependent at this address"))
    return 0

sys.exit(main())