code wiki / _hdl_build / nx_gpu_mem.nx
nx_gpu_mem.nx source
↩ module page · 67 lines · 4038 B
1// nx_gpu_mem.nx -- HEAPS AND RESIDENCY over the dxg door (gpu GP6): allocate, place, make resident, EVICT, with the
2// budget READ from the device, never assumed. One heap = one EXISTINGHEAP allocation of a page-aligned size,
3// placed at a GPU virtual address through the paging queue and made resident; eviction is the device's own
4// EVICT, and the proof that it happened is the device's own paging state (a make-resident after an evict
5// answers DXG_MKRES_PENDING instead of 0).
6//
7// SCOPE, stated once: these heaps are SYSTEM-memory backed (the UMD-less EXISTINGHEAP path R4d measured), so they
8// live in the NON-LOCAL segment; a VRAM (local-segment) heap needs the vendor UMD's private allocation data, the
9// same blocker class as the command ring (gpu.plan GP5 lesson). Exhausting the non-local budget would exhaust the
10// host's RAM, so this lib walks a BOUNDED window under the budget and never crosses it; the exhaust-to-evict test on
11// the local segment is named on the board as owed, not claimed.
12// license_tier: ORIGINAL No hw writes (Rule 26): per-process allocations, released with the process.
13import "nx_syscalls.nx"
14import "nx_dxg.nx"
15import "nx_gpu_sync.nx"
16
17const GM_MAX_HEAPS: i64 = 64
18const GM_ERR_BUDGET: i64 = 0 - 21 // the budget query refused
19const GM_ERR_ALLOC: i64 = 0 - 22 // an allocation refused or returned no handle
20const GM_ERR_MAP: i64 = 0 - 23 // the GPU VA map refused (259 = pending is fine)
21const GM_ERR_RES: i64 = 0 - 24 // make-resident refused (259 = pending is fine)
22const GM_ERR_EVICT: i64 = 0 - 25 // evict refused
23const GM_ERR_TOOMANY: i64 = 0 - 26 // more heaps than the table holds
24
25// a heap table: handles[i], vas[i], sysmem[i], bytes[i] for i < count
26func gm_table_new() -> *i64 { let t: *i64 = sys_mmap(GM_MAX_HEAPS * 8 * 4) as *i64; return t }
27func gm_handle(t: *i64, i: i64) -> i64 { return t[i] }
28func gm_va(t: *i64, i: i64) -> i64 { return t[GM_MAX_HEAPS + i] }
29func gm_sysmem(t: *i64, i: i64) -> *u8 { return t[GM_MAX_HEAPS * 2 + i] as *u8 }
30func gm_bytes(t: *i64, i: i64) -> i64 { return t[GM_MAX_HEAPS * 3 + i] }
31
32// budget for a segment group, read from the device: out[0]=budget out[1]=usage out[2]=reservation out[3]=available
33func gpu_mem_budget(fd: i64, adapter: i64, group: i64, out: *i64) -> i64 {
34 if dxg_query_vidmem(fd, adapter, group, out) != 0 { return GM_ERR_BUDGET }
35 if out[0] <= 0 { return GM_ERR_BUDGET }
36 return 0
37}
38
39// allocate heap i of `bytes`, place it (GPU VA through the paging queue) and make it resident; returns 0 or a stage code.
40// mapf[0] / resf[0] receive the paging fence values (259 = pending, completes on the paging queue's fence).
41func gpu_mem_heap(fd: i64, device: i64, pq: i64, t: *i64, i: i64, bytes: i64, mapf: *i64, resf: *i64) -> i64 {
42 if i >= GM_MAX_HEAPS { return GM_ERR_TOOMANY }
43 let mem: *u8 = sys_mmap(bytes)
44 let h: *i64 = sys_mmap(16) as *i64
45 if dxg_alloc_eh_sz(fd, device, mem, bytes, h) != 0 { return GM_ERR_ALLOC }
46 if h[0] == 0 { return GM_ERR_ALLOC }
47 let va: *i64 = sys_mmap(16) as *i64
48 let mr: i64 = dxg_map_va(fd, pq, h[0], va, mapf)
49 if mr != 0 { if mr != DXG_MKRES_PENDING { return GM_ERR_MAP } }
50 let rr: i64 = dxg_makeresident(fd, pq, h[0], resf)
51 if rr != 0 { if rr != DXG_MKRES_PENDING { return GM_ERR_RES } }
52 t[i] = h[0]; t[GM_MAX_HEAPS + i] = va[0]; t[GM_MAX_HEAPS * 2 + i] = mem as i64; t[GM_MAX_HEAPS * 3 + i] = bytes
53 sys_munmap(h as *u8, 16); sys_munmap(va as *u8, 16)
54 return 0
55}
56
57// evict heap i; outtrim[0] = the device's num_bytes_to_trim
58func gpu_mem_evict(fd: i64, device: i64, t: *i64, i: i64, outtrim: *i64) -> i64 {
59 if dxg_evict(fd, device, t[i], outtrim) != 0 { return GM_ERR_EVICT }
60 return 0
61}
62
63// re-make heap i resident; returns the device's own answer: 0 = it was still resident, DXG_MKRES_PENDING = it had
64// been evicted and is paging back in, negative = refused
65func gpu_mem_reresident(fd: i64, pq: i64, t: *i64, i: i64, resf: *i64) -> i64 {
66 return dxg_makeresident(fd, pq, t[i], resf)
67}