code wiki / _hdl_build / nx_kfd.nx

nx_kfd.nx source

↩ module page · 45 lines · 2765 B

1// nx_kfd.nx -- the native-Linux AMD executor shim (/dev/kfd AM/KFD path), sibling to nx_nv (NVIDIA) + nx_dxg 2// (WSL2). Modeled on tinygrad's ops_amd.py AM driver: PM4 ring buffer + wptr + doorbell, bypassing the MES 3// scheduler firmware = the MOST-sovereign GPU path per deep-research. Composes PM4 packets (nx_pm4_asm) into a 4// compute-queue ring, updates wptr, rings the doorbell. Runs on a native-Linux / rented AMD cloud instance 5// (brick-safe, rule #26). 6// 7// LOCALLY-VERIFIABLE (gated): the PM4 compute-dispatch stream composition (via nx_pm4_asm, already gated). 8// CLOUD-PENDING (structured): the KFD queue creation (AMDKFD_IOC_CREATE_QUEUE on /dev/kfd) + the ring/doorbell 9// BAR map -- completed against the instance's ROCt/KFD ABI on first cloud run. Pure funcs, no main. license_tier: ORIGINAL 10import "nx_syscalls.nx" 11import "nx_pm4_asm.nx" 12 13// AMD KFD ioctls (AMDKFD_IOCTL_BASE='K'=0x4B): the ioctl = _IOWR(0x4B, nr, size). (struct sizes = TODO_CLOUD) 14const KFD_IOC_CREATE_QUEUE: i64 = 0x02 15const KFD_IOC_CREATE_EVENT: i64 = 0x05 16const KFD_IOC_ALLOC_MEMORY_OF_GPU: i64 = 0x16 17 18func kfd_open() -> i64 { return sys_openat_rd("/dev/kfd" as *u8) } 19func kfd_open_render() -> i64 { return sys_openat_rd("/dev/dri/renderD128" as *u8) } 20 21// write one 32-bit dword into the PM4 ring at byte offset `off`. 22func pm4_ring_put(ring: *u8, off: i64, dw: i64) -> i64 { let w: *u8 = (ring as i64 + off) as *u8; w[0]=(dw&0xff) as u8; w[1]=((dw>>8)&0xff) as u8; w[2]=((dw>>16)&0xff) as u8; w[3]=((dw>>24)&0xff) as u8; return 0 } 23 24// compose a minimal PM4 COMPUTE DISPATCH into `ring`: SET_SH_REG(kernel params) + DISPATCH_DIRECT(dims). 25// reg values are 0-framed here (real kernel address/rsrc are cloud-supplied); returns bytes written. 26func pm4_compose_dispatch(ring: *u8, reg_base: i64, n_regs: i64, dim_x: i64, dim_y: i64, dim_z: i64) -> i64 { 27 var o: i64 = 0 28 pm4_ring_put(ring, o, pm4_packet3(PM4_IT_SET_SH_REG, n_regs + 1)); o = o + 4 29 pm4_ring_put(ring, o, reg_base); o = o + 4 30 var i: i64 = 0 31 while i < n_regs { pm4_ring_put(ring, o, 0); o = o + 4; i = i + 1 } 32 pm4_ring_put(ring, o, pm4_packet3(PM4_IT_DISPATCH_DIRECT, 3)); o = o + 4 33 pm4_ring_put(ring, o, dim_x); o = o + 4 34 pm4_ring_put(ring, o, dim_y); o = o + 4 35 pm4_ring_put(ring, o, dim_z); o = o + 4 36 pm4_ring_put(ring, o, 1); o = o + 4 // dispatch_initiator (COMPUTE_SHADER_EN) 37 return o 38} 39 40// ring the doorbell: 32-bit write of the wptr (in dwords) to the queue's mapped doorbell address. 41func kfd_doorbell_ring(doorbell: i64, wptr_dwords: i64) -> i64 { 42 let b: *u8 = doorbell as *u8 43 b[0]=(wptr_dwords&0xff) as u8; b[1]=((wptr_dwords>>8)&0xff) as u8; b[2]=((wptr_dwords>>16)&0xff) as u8; b[3]=((wptr_dwords>>24)&0xff) as u8 44 return 0 45}