--- tinygrad/runtime/support/am/ip.py.orig 2026-10-05 14:28:31.791136814 +0200 +++ tinygrad/runtime/support/am/ip.py 2026-10-05 14:29:52.707496539 +0200 @@ -692,7 +692,19 @@ wait_cond(lambda: self.adev.reg(f"{self.reg_pref}_64").read() & 0x8000FFFF, value=0x80000000, msg="sOS ring not created") def _ring_submit(self, cmd:am.struct_psp_gfx_cmd_resp) -> am.struct_psp_gfx_cmd_resp: - msg = am.struct_psp_gfx_rb_frame(fence_value=(prev_wptr:=self.adev.reg(f"{self.reg_pref}_67").read()) + 1, + # The PSP KM ring is circular (ring_size = 0x10000, frame = 64 B => 1024 frames) but the wptr + # was advanced without ever wrapping, so after ~1024 submissions the frame was written past the + # end of the ring and the fence stopped advancing ("sOS ring not responding", wptr ~16353 of + # 16384 dwords). Wrap the wptr, and use an independent monotonic fence so the wrapped value + # cannot collide with a stale fence already in memory. Wrap one frame EARLY (>=, not >): + # the final slot is unusable because advancing into it makes wptr == ring_size == 0 (mod + # size) == rptr, which the PSP reads as an EMPTY ring, so that frame is never consumed. + # Measured: the stall always happened at wptr 16368 of 16384 dwords, i.e. the last slot. + _frame_dw = ctypes.sizeof(am.struct_psp_gfx_rb_frame) // 4 + prev_wptr = self.adev.reg(f"{self.reg_pref}_67").read() + if (prev_wptr + _frame_dw) * 4 >= self.ring_size: prev_wptr = 0 + self._fence_ctr = getattr(self, "_fence_ctr", 0) + 1 + msg = am.struct_psp_gfx_rb_frame(fence_value=self._fence_ctr, cmd_buf_addr_lo=lo32(self.adev.paddr2mc(self.cmd_paddr)), cmd_buf_addr_hi=hi32(self.adev.paddr2mc(self.cmd_paddr)), fence_addr_lo=lo32(self.adev.paddr2mc(self.fence_paddr)), fence_addr_hi=hi32(self.adev.paddr2mc(self.fence_paddr))) @@ -700,7 +712,7 @@ self.adev.vram.view(self.ring_paddr + prev_wptr * 4, ctypes.sizeof(msg))[:] = memoryview(msg).cast('B') # Move the wptr - self.adev.reg(f"{self.reg_pref}_67").write(prev_wptr + ctypes.sizeof(am.struct_psp_gfx_rb_frame) // 4) + self.adev.reg(f"{self.reg_pref}_67").write(prev_wptr + _frame_dw) wait_cond(lambda: self.adev.vram.view(self.fence_paddr, 4, 'I')[0], value=msg.fence_value, msg="sOS ring not responding")